前言
前几天参加了原宇宙项目的学习,奈何是blender新手,工作时间不能学习,只能忙里偷闲,先先做一个记录,项目用到的和没用到的文件都在src目录下的resources
文件夹里面。想着做不同的,那么就用框架不一样吧,利用vite搭建的react项目,下载threeJs安装包书写。
准备工作
1 ,工具
使用的是blender
- 因为blender对于mac和windows都是可以使用的,3dMax只适用于windows系统(不过因为我之前学过3dMax的,所以,虽然我是mac,但是也安装了一个windows的虚拟机,3dMax跑起来还是可以使用的。)
2,网址
- blender下载地址:https://www.blender.org/thanks/
- 下载贴图或者材质的:https://www.textures.com/library
- 一些基本模型:https://sketchfab.com/ (在sketchfab上可以拿模型,实现模型的小部分自由)(qq邮箱,google邮箱可以,163邮箱注册好像不行)
用于模型绑定骨骼: https://www.mixamo.com/ (无动画的角色,演示的时候用的glb不支持,没提示。用fbx格式的可以)
3,blender中的一些快捷键
在blender中使用的的右手坐标系
功能 | 快捷键 | ||||||
---|---|---|---|---|---|---|---|
全选: | A | 取消全选: | AA | 复制物体: | Shift+D | ||
移动: | G | 缩放: | S | 移动视角: | 鼠标滚轮键 | ||
旋转: | R | 搜索: | F3 | 删除: | X | ||
填充面: | F | 合并顶点: | M | 编辑模式: | Tab | ||
前视图: | 1 | 右视图: | 3 | 顶视图: | 7 | ||
切换视图: | Alt+鼠标中键 | 透视显示模式: | Alt+Z | 分离: | P | ||
属性栏: | N | 左侧工具栏: | T | 环选: | Alt+A | ||
反选: | Ctrl+I | 隐藏物体: | H | 取消隐藏: | Alt+H | ||
查看全部: | Shift+C | 父子链接: | Ctrl+P | 相机视图: | 0 | ||
着色模式: | Z | 弹出上次的渲染窗口: | F11 | 创建集合: | M | ||
设置游标: | Shift+S | 最大化当前窗口: | Ctrl+空格 | 物体交互模式设置: | Ctrl+Tab | ||
进入/退出三视图: | Ctrl+Alt+Q | 挤出: | F9 | 游标回到原点: | Shift+C | ||
开启/关闭吸附功能: | Shift+Tab | 选择相连元素: | L | 普通复制: | Shift+D | ||
去除父子关系: | Alt+P | 创建父子关系: | Ctrl+P | 移动物体: | M | ||
连接节点: | F | 断开节点: | Ctrl+鼠标左键 | 添加转换点: | Shift+鼠标左键 | ||
暂停/播放: | Alt+A | 上一帧/下一帧: | 左右箭头 | 删除关键帧: | Alt+I | ||
切换点线面: | Ctrl+Tab | 撕开后填充: | Alt+V | 倒角工具: | Ctrl+B | ||
切割工具: | K | 挤出工具: | E | 细分物体: | 按住S+鼠标中键 | ||
渲染: | F12 | 保存用户设置: | Ctrl+U |
有些快捷键我没有试过,可以自己动手尝试做一下
4,代码实现时可能遇到的几个坑
- 动画为什么不动,
需要在动画中设置帧的播放顺序
- 为什么按照操作,整个画面是黑的,
因为相机在内部,需要将相机的位置进行设置
为什么底部的材质是黑的,
可以用一个环境光,将周围的亮度调亮
5,代码
1,使用vite搭建项目
这里选择的是react版本
npm create vite@latest
2,下载three.js安装包
下载后查看文档对应下载的版本进行查看,因为不同的版本相应的文件可能存在的文件夹不一样,这里我用的是0.145.0
npm install [email protected]
3,具体代码
1,引入相关文件
import { useState, useEffect, useRef } from 'react' import * as THREE from 'three'; // 引入three.js其他扩展库,对应版本查看文档,最新扩展库在addons文件夹下,eg:'three/addons/controls/OrbitControls.js'; // OrbitControls控件支持鼠标左中右键操作和键盘方向键操作 import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader"; import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader';
2,设置盒子宽高
function App() { const [width, setWidth] = useState(window.innerWidth) const [height, setHeight] = useState(window.innerHeight) return ( ) } export default App
3,若窗口改变,则对窗口进行重置
const resizeUpdate = (e) => { // 通过事件对象获取浏览器窗口的高度 let h = e.target.innerHeight; let w = e.target.innerWidth; // 对应用大小进行重置 renderer.setSize(w, h); setHeight(h); setWidth(w) }; // 重置窗口大小 useEffect(() => { // 页面刚加载完成后获取浏览器窗口的大小 let h = window.innerHeight; setHeight(h) let w = window.innerWidth; setWidth(w) // 页面变化时获取浏览器窗口的大小 window.addEventListener('resize', resizeUpdate); return () => { // 组件销毁时移除监听事件 window.removeEventListener('resize', resizeUpdate); } }, [])
4,对相应的变量进行命名
let scene, camera, renderer, controls // 场景,相机,渲染器,控制器 let donuts; //后面甜甜圈旋转时的变量 let mixer; // 甜甜圈播放动画是的变量
5, 初始化/销毁 应用
useEffect(() => { // 创建场景 scene = new THREE.Scene(); // // 创建相机 camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.01, 10); renderer = new THREE.WebGLRenderer({ antialias: true }); renderer.setSize(width, height); //设置渲染器尺寸 document.getElementById('container').appendChild(renderer.domElement); camera.position.set(0.3, 0.3, 0.5); // 设置相机位置 controls = new OrbitControls(camera, renderer.domElement); const directionLight = new THREE.DirectionalLight(0xffffff, 0.4); //添加平行光 scene.add(directionLight); gltfLoader() // 场景添加glb文件 rgbeLoader() // 添加背景天空 animate() // 动画循环 // 组件销毁时移除app应用 return () => { document.getElementById('container').removeChild(renderer.domElement); } }, [])
6,三个分离出来的方法
// 场景添加glb文件 const gltfLoader = () => { new GLTFLoader().load('../src/resources/models/donuts.glb', (gltf) => { scene.add(gltf.scene); donuts = gltf.scene; mixer = new THREE.AnimationMixer(gltf.scene); const clips = gltf.animations; // 播放所有动画 clips.forEach((clip) => { const action = mixer.clipAction(clip); action.loop = THREE.LoopOnce; // 停在最后一帧 action.clampWhenFinished = true; action.play(); }); }) } // 添加背景天空 const rgbeLoader = () => { new RGBELoader() .load('../src/resources/sky2.hdr', function (texture) { scene.background = texture; texture.mapping = THREE.EquirectangularReflectionMapping; scene.environment = texture; renderer.outputEncoding = THREE.sRGBEncoding; renderer.render(scene, camera); }); } // 动画循环 const animate = () => { requestAnimationFrame(animate); renderer.render(scene, camera); controls.update(); if (donuts) { donuts.rotation.y += 0.01; } if (mixer) { mixer.update(0.02); } }
6,代码地址
代码在当前github地址,点击可进入查看
7,总结
不管做什么还是要坚持,坚持才会迎来胜利。
如果你有兴趣的话,也可以加入猿创营 (v:dashuailaoyuan),一起交流学习