学习文档地址:
threejs官网:https://threejs.org/
Threejs官网中文文档:https://threejs.org/docs/index.html#manual/zh/
threejs中文网:http://www.webgl3d.cn/
threejs基础教程:http://www.webgl3d.cn/pages/aac9ab/
webgl基础教程:http://www.webgl3d.cn/pages/9bc0db/
threejs数学几何计算:http://www.webgl3d.cn/pages/001888/
threejs shader:http://www.webgl3d.cn/pages/d30795/
blender基础:http://www.webgl3d.cn/pages/00cfc0/
学习文档下载:
https://gitee.com/xin_hu199/threejs-code-public
git clone https://gitee.com/xin_hu199/threejs-code-public.git
结构图:
threejs中有三个对象:
- 场景
- 相机
- 渲染器
一、场景 Scene
1.创建场景
const scene = new THREE.Scene();
2.创建网络模型
2.1 几何体
立方体、球……
1.立方体-BoxGeometry(x, y, z)
const geometry = new THREE.BoxGeometry(5, 5, 5)
x:左右 const geometry = new THREE.BoxGeometry(10, 5, 5)
y:上下 const geometry = new THREE.BoxGeometry(5, 10, 5)
z:前后 const geometry = new THREE.BoxGeometry(5, 5, 10)
x: BoxGeometry(10, 5, 5) y: BoxGeometry(5, 10, 5) z: BoxGeometry(5, 5, 10)
2 球-SphereGeometry(5, 32, 16)
2.2 材质
创建几何体之后需要给它一个材质,让它有颜色。
Threejs自带了几种材质,每种材质都有相应的属性,如MeshBasicMaterial
1.MeshBasicMaterial
color:十六进制(hex colors)颜色格式
wireframe:是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
const materialBasic = new THREE.MeshBasicMaterial({
color: '#4d72a9',
wireframe: true
})
2.3 网格 Mesh
网格包含一个几何体以及作用在此几何体上的材质,我们可以直接将网格对象放入到我们的场景中,并让它在场景中自由移动。
const geometry = new THREE.BoxGeometry( 1, 1, 1 ); // 几何体
const materialBasic = new THREE.MeshBasicMaterial( { color: '#4d72a9' } ); // 材质
const cube = new THREE.Mesh( geometry, materialBasic ); // 网格
scene.add( cube );
注: 默认在调用 scene.add()时,物体会被添加到(0,0,0)坐标,使得摄像机和立方体在一起。为了防止这种情况的发生,我们需移动摄像机位置,如:camera.position.z = 5。
二、相机 Camera
1.相机类型
three.js 里有几种不同的相机:
- 透视相机:PerspectiveCamera (透视投影)
模拟人眼视觉效果的相机,进大远小
- 正交相机:OrthographicCamera(正射投影)
用于渲染2D场景的相机,无论物体距离相机有多远,相机看到的物体大小都会一致
这里使用 PerspectiveCamera(透视摄像机)
const camera = new THREE.PerspectiveCamera(
70, // 视野角度:在显示器上能看到的场景范围,单位是角度
threeRef.value.clientWidth / threeRef.value.clientHeight, // 长宽比:宽 除以 高
0.1, // 近截面
1000 // 远截面,某些部分比摄像机的远截面或近截面近的时候,该部分不会被渲染到场景中
)
构造器: new THREE.PerspectiveCamera( fov: Number, aspect: Number, near: Number, far: Number)
属性:
- 视野角度 (FOV): 无论在什么时候,你所能在显示器上看到的场景的范围,它的单位是角度(与弧度区分开)。默认值是50
- 长宽比 (aspect ratio): 物体的宽除以它的高的值。通常是使用画布的宽/画布的高。默认值是1(正方形画布)
- 近截面 (near)/远截面 (far): 当物体某些部分比摄像机的远截面远或者比近截面近的时候,该这些部分将不会被渲染到场景中。
远截面:默认2000,该值必须大于近截面
近截面:默认0.1,该值在0—far之间,0对于透视摄像机来说不是有效值
- 其他属性查看文档: filmGauge(胶片尺寸) 、filmOffset(偏移量)、zoom(缩放倍数)……
2.相机位置
语法: camera.position.set(x,y,z);
// 设置相机位置
camera.position.set(10, 10, 10)
注: 如果不设置相机位置,相机会默认在(0,0,0),需要调整相机位置防止摄像机和立方体彼此在一起,如:camera.position.z =5
3.相机视线方向
设置相机看向物体的方向(默认指向三维坐标系的原点)
语法: camera.lookAt(x,y,z);
//相机-视线方向:设置相机看向物体的方向(默认指向三维坐标系的原点)
camera.lookAt(0, 0, 0)
三、使用渲染器渲染场景
three.js 里提供了几种不同的渲染器:
- WebGLRenderer
这里使用 WebGLRenderer 渲染器
// 1 创建WebGLRenderer渲染器
const renderer = new THREE.WebGLRenderer()
// 2 通过setSize()方法设置渲染的长宽
renderer.setSize(
threeRef.value.clientWidth,
threeRef.value.clientHeight,
false
)
// 3 将渲染器renderer的dom元素(renderer.domElement)添加到页面中
threeRef.value.appendChild(renderer.domElement)
// 4 渲染
renderer.render(scene, camera)
1.创建渲染器
语法: const renderer = new THREE.WebGLRenderer()
2.设置渲染器的尺寸
使用 setSize 传入渲染器的宽高,
renderer.setSize(
threeRef.value.clientWidth,
threeRef.value.clientHeight,
false
)
3.渲染场景
添加“渲染循环”(render loop)或者“动画循环”(animate loop)
function animate() {
requestAnimationFrame( animate );
// 使立方体动起来
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
}
animate();
四、总结
1.步骤
1.创建场景: const scene = new THREE.Scene();
2.创建相机:const camera = new THREE.PerspectiveCamera();
注1:相机默认位置会和几何体重叠,需要调整相机位置
3.创建立方体: const geometry = new THREE.BoxGeometry(2, 2, 2);
4.添加材质: const materialBasic = new THREE.MeshBasicMaterial({ color: ‘#4d72a9’, wireframe: true });
5.创建网格,将立方体与材质放入: const cube = new THREE.Mesh(geometry, materialBasic);
注2:创建网格地面,添加到场景中
6.将内容添加到场景中:scene.add(cube);
7.创建渲染器: const renderer = new THREE.WebGLRenderer();
8.将渲染器添加到页面中:document.body.appendChild(renderer.domElement);
9.渲染场景,将场景及摄像机传入: renderer.render(scene, camera);
注3:第一个参数是场景,第二个参数是摄像机
10.添加动画循环,让立方体动起来
2.示例
示例一:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>My first three.js app</title>
<style>
body { margin: 0; }
</style>
</head>
<body>
<script type="module">
import * as THREE from 'https://unpkg.com/three/build/three.module.js';
// 1.创建场景
const scene = new THREE.Scene();
// 2.创建相机
const camera = new THREE.PerspectiveCamera();
camera.position.z = 10;
camera.position.y = 2;
// 3.创建立方体
const geometry = new THREE.BoxGeometry();
// 4.添加材质
const material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
// 5.创建网格,将立方体和材质放入
const cube = new THREE.Mesh(geometry, material);
cube.position.set(0, 3, 0 )
// 6.将内容添加到场景中
scene.add(cube);
// 7.创建渲染器
const renderer = new THREE.WebGLRenderer();
// 8.将渲染器添加到页面中
document.body.appendChild(renderer.domElement);
// 调整渲染器窗口大小
renderer.setSize(window.innerWidth, window.innerHeight);
// 添加网格地面
const gridHelper = new THREE.GridHelper(10, 10);
// 将网格地面添加到场景中
scene.add(gridHelper);
// 9.渲染场景,将场景和摄像机传入
// renderer.render(scene, camera)
// 10.让立方体动起来
function animate() {
requestAnimationFrame(animate); // 动画循环
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
// TODO: 画布自适应暂时无效果
window.addEventListener('resize', () => {
// 更新摄像头比例
camera.aspect = window.innerWidth / window.innerHeight
// 更新摄像机的投影矩阵
camera.updateProjectionMatrix()
// 渲染器大小
renderer.setSize(
window.innerWidth,
window.innerHeight,
false
)
// 设置渲染器的像素比
renderer.setPixelRatio(window.devicePixelRatio)
})
// 全屏
window.addEventListener('dblclick', () => {
const fullScreenElement = document.fullscreenElement
if (!fullScreenElement) {
//让画布对象全屏
renderer.domElement.requestFullscreen()
} else {
//退出全屏,使用document对象
document.exitFullscreen()
}
})
</script>
</body>
</html>
示例二:
<template>
<div class="w-100% h-100%">
<div ref="threeRef" class="w-100% h-100%"></div>
</div>
</template>
<script setup>
// 引入three.js
import * as THREE from 'three'
import { onMounted, ref, reactive } from 'vue'
let threeRef = ref(null)
// 一、场景:创建场景(scene)
const scene = new THREE.Scene()
let camera = reactive()
const renderer = new THREE.WebGLRenderer()
onMounted(() => {
initThree()
})
function initThree() {
// 1.1 创建网络模型-几何体: 立方体-BoxGeometry(x, y, z)
// const geometry = new THREE.SphereGeometry(5, 32, 16)
const geometry = new THREE.BoxGeometry(2, 2, 2)
// 1.2 创建网络模型-材质: Basic
const materialBasic = new THREE.MeshBasicMaterial({
color: '#4d72a9',
wireframe: true, //是否将几何体渲染为线框,默认值为false(即渲染为平面多边形)
})
// 1.3 创建一个网格模型对象:Mesh
const cube = new THREE.Mesh(geometry, materialBasic) //网络模型对象Mesh
// 1.4 把网格模型添加到三维场景
scene.add(cube)
// 1.4.3 修改几何体位置
cube.position.set(0, 0, 0)
camera = new THREE.PerspectiveCamera(
70, // 视野角度:在显示器上能看到的场景范围,单位是角度
threeRef.value.clientHeight / threeRef.value.clientWidth, // 摄像机视锥体长宽比(aspect)
0.1, // 近截面
1000 // 远截面,某些部分比摄像机的远截面或近截面近的时候,该部分不会被渲染到场景中
)
// 2.1 相机-位置:设置相机位置
camera.position.set(10, 10, 10)
// 2.2 相机-视线方向:设置相机看向物体的方向(默认指向三维坐标系的原点)
camera.lookAt(0, 0, 0)
// 防止摄像机和立方体彼此在一起
// camera.position.z =5;
// 三、渲染器
// 3.1 创建WebGLRenderer渲染器
// 3.2 通过setSize()方法设置渲染的长宽
renderer.setSize(
threeRef.value.clientWidth,
threeRef.value.clientHeight,
false
)
// 3.3 将渲染器renderer的dom元素(renderer.domElement)添加到页面中
threeRef.value.appendChild(renderer.domElement)
// 创建光源
const spotLight1 = new THREE.SpotLight(0xffffff, 1) //(光照颜色, 光照强度)
// 设置光源位置
spotLight1.position.set(10, 10, 10)
const spotLight2 = new THREE.SpotLight(0xffffff, 1) //(光照颜色, 光照强度)
// 设置光源位置
spotLight2.position.set(-10, -10, -10)
// 将光源添加到场景中
scene.add(spotLight1, spotLight2)
// 为了方便观察3D图像,添加三维坐标系对象
// const axes = new THREE.AxesHelper(8) // 坐标系轴长设置为8
// 把三维坐标系 添加到场景中
// scene.add(axes)
// 五、渲染场景
function animate() {
//循环调用: 切换到其他页面时会暂停
requestAnimationFrame(animate)
// 让立方体动起来
cube.rotation.x += 0.01
cube.rotation.y += 0.01
//渲染
renderer.render(scene, camera)
}
animate()
}
</script>
<style lang="scss" scoped>
.my-three {
width: 100%;
height: 100%;
}
</style>