基础知识
- Blender:制作3D文字
- 科大讯飞星火:生成故事单元剧情
- Blockade Labs: 根据故事情节生成全景图片(要使用英文单词)
- TTS-Vue:生成语音作旁白
- 将文本,图片,音频,按钮(按钮文本,跳转场景的索引值),场景旋转的起始和结束,持续时间存放到对象数组中。按照步骤,载入图片,页面搭建,监听跳转函数等完成交互式2D故事游戏
- leiapix:将静态图片生成3D图片
- three.js官网: 官网
- 导入three.js的文件后
第一步: 创建场景、相机和渲染器
1 | // 引入three.js |
第二步: 创建几何体、材质、网格 并添加到场景中
1 | // 创建几何体 --- 决定形状 |
第三步: 使用世界坐标辅助器和轨道控制器
1 | // 设置相机的位置 --- 调整视角方便看到坐标轴 |
倒数第二步: 渲染函数
1 | // 渲染函数 |
最后一步: 监听窗口的变化
- 监听窗口的变化,仪表窗口缩小,物体没有跟着自适应回到视图的中心
1
2
3
4
5
6
7
8
9// 监听窗口变化
window.addEventListener("resize", () => {
// 重置渲染器宽高比
renderer.setSize(window.innerWidth, window.innerHeight)
// 重置相机宽高比
camera.aspect = window.innerWidth / window.innerHeight
// 更新相机投影矩阵
camera.updateProjectionMatrix()
})
认识向量(Vector3)、父元素和子元素的position的关系、缩放、旋转
1 | // 通过案例来分析,首先先创建一个父元素的网格和子元素的网格 |
position
- 子元素的坐标轴相对于父元素
- 父元素的position设置的是它的局部坐标,没有父元素,元素设置的position就是世界坐标
scale
- 对于缩放,不管cube原本的大小是什么,只要父元素缩放,子元素也会跟着缩放,
- 公式:父元素(x,y,z),子元素的缩放为(x1,y1,z1),最终子元素的缩放(xx1,yy1,z*z1)
- 所以,如果遇到与缩放有关的,只需要缩放父元素
rotation
- rotation: 欧拉角(x,y,z,xyz),旋转的顺序不同,效果不一样,默认的旋转顺序为xyz
- 同样都是相对于父元素
结果
- 此时父元素的坐标为(-3,0,0),二子元素相对于父元素的坐标为(0,0,0)位于原点
- 此时父元素的大小放大2倍,子元素的大小在父元素的放大后的大小再放大2倍
- 此时父元素绕着x轴旋转45°,子元素在相对于父元素旋转45°后,变为90°
学习监听事件
- 在渲染器后区监听
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26// 监听按钮,点击触发全屏
const btn = document.createElement("button")
btn.innerHTML = "点击全屏"
btn.style.position ="absolute"
btn.style.top ="10px"
btn.style.left="10px"
btn.style.zIndex="999"
btn.onclick = () => {
// 画布全屏 -- 看不到按钮
// renderer.domElement.requestFullscreen()
document.body.requestFullscreen()
}
// 将按钮添加到body上
document.body.appendChild(btn)
// 经停按钮点击退出全屏
const escbtn = document.createElement("button")
escbtn.innerHTML = "退出全屏"
escbtn.style.position ="absolute"
escbtn.style.top ="10px"
escbtn.style.left="100px"
escbtn.style.zIndex="999"
escbtn.onclick = () => {
// 退出全屏
document.exitFullscreen()
}
document.body.appendChild(escbtn)
属性参数的管理工具
- 方便快速开发
- lil.gui
- 能自动识别属性值是什么类型,并展示对应的样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28// 创建GUI
const gui = new GUI()
/ 控制事件
//添加按钮
// add(事件对象,函数名)
// name(别名)
gui.add(eventObj, "Fullscreen").name("全屏")
gui.add(eventObj, "ExitFullscreen")
// 控制立方体的位置
// gui.add(cube.position, "x", -5 ,5).name("立方体x轴位置")
/ 控制一组属性,展示拖到条
// 存放在组中
let folder = gui.addFolder("立方体位置")
// add(元素,元素的属性)
// min/max()设置最小值/最大值
// onChange: 只要改变就会触发
// onFinishChange: 当拖拽结束后再触发
folder.add(cube.position, "x").min(-10).max(10).step(1).name("立方体x轴位置").onChange((val) => {console.log("立方体x轴位置",val)})
folder.add(cube.position, "y").min(-10).max(10).step(1).name("立方体y轴位置").onFinishChange((val) => {console.log("立方体y轴的位置",val)})
folder.add(cube.position, "z").min(-10).max(10).step(1).name("立方体z轴位置")
/ 控制单个属性,展示勾选框
gui.add(parentMaterial, "wireframe").name("父元素线框模式")
/ 控制单个元素选择颜色,展示颜色选择器
// colorParams中的cubeColor相当于该元素的默认颜色,所以,如元素已经有颜色,则cubeColor最好与之相等
let colorParams = { cubeColor: "#00ff00"}
gui.addColor(colorParams, "cubeColor").name("立方体颜色").onChange((val) => {
cube.material.color.set(val)
})
几何体怎么来的
在js中所有的图形都是由三角形组成的
- 两种方式创建
第一种: 顶点需要一个一个列出来,不可共用,冗余
1 | // 创建几何体 |
第二种:顶点可以共用
1 | // 创建几何体 |
材质创建的两种方式
第一种: 创建之后单独的设置
1 | const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 }) |
第二种: 在构造函数中定义
1 | const material = new THREE.MeshBasicMaterial({ |
组的概念和创建一个立方体
组的概念(划分组)
1 | // BufferGeometry():用来创建由顶点组成的图形 |
给几何体的每一个面添加不同的材质
1 | BoxGeometry(x,y,z) :可以创建几何体 |
官方提供的几何体 – 文档搜geometry
网格基础材料 — 上编辑器上看
贴图/Map:
- 如果使用一张带纹理的png图片,边缘透明,贴在一个正/长方形上,边缘也会自动生成纹理(勾选上透明性即消失)
透明贴图/alpha Map:
- 使用一张由黑色,白色和0.5白色的图片贴图,则黑色为完全透明,白色完全不透明,0.5白色为半透明。即使用贴图后在使用透明贴图,则只看得见白色区域的图和0.5白色区域的半透明图和后面的物体
环境贴图/env Map:
- 先在上面的背景放上一张全景图/环境的图,环境和环境贴图页放上相同的全景图,可以调节反射率
高光贴图:
- 在环境中,金属的反射亮度,找一张亮一点的图
光照贴图:
- 贴的图,代表光照射进来的颜色,比如,光通过玻璃照进来,而玻璃贴了窗纸,窗纸就是这个图,最后呈现的光展示在物体上也要跟环境贴图搭上
环境光遮蔽贴图:
- 就是给边缘缝隙添加阴影的
代码实现各种贴图
雾
1 | // 创建场景fog(线性雾) |
载入模型
第一步 引入相关资源
1 | // 导入hdr加载器 |
创建实例化
1 | // 实例化加载器gltf |
设置模型路径和环境贴图
1 | // 设置Draco路径 |
光线投射
threeJS-光线投射补间动画
threeJS-补间动画TWEEN物理网格材质
首先需要安装npm i gsap 动画库
看车模型案例