Three.js是一款webGL框架,由于其易用性被广泛应用。Three.js在WebGL的api接口基础上,又进行的一层封装,所以不用担心他得性能,和主机游戏一样都是支持硬件加速的。它是由居住在西班牙巴塞罗那的程序员Ricardo Cabbello Miguel(https://ricardocabello.com/) 开发的,Three.js以简单、直观的方式封装了3D图形编程中常用的对象。Three.js在开发中使用了很多图形引擎的高级技巧,极大地提高了性能。Three.js还是完全开源的。
里面有很多图形学的概念,比如坐标变换,光照计算,同样可以创建自己的Shader,调用底层的图形接口,框架具有相当高的灵活性。
Webgl和Three.js的关系
Webgl和Three.js的关系,相当于JavaScript和Jquery的关系
创建一个场景
为了真正能够让你的场景借助three.js来进行显示,我们需要以下几个对象:场景、相机和渲染器,这样我们就能透过摄像机渲染出场景。
//创建场景
const scene = new THREE.Scene();
//创建一个立方体
const geometry = new THREE.BoxGeometry( 1, 1, 1 ); //几何形状
const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } ); //材质
const cube = new THREE.Mesh( geometry, material );
scene.add( cube );
scene以树结构存放所有可见的和不可见的三维物体,包括光源等等
//创建一个摄像机
const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.z = 5;
摄像机决定了我们从什么位置,什么角度观察三维物体
const renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
渲染器负责将我们的看到的场景树渲染成二维图像
const animate = ()=> {
requestAnimationFrame( animate );
//因为JavaScript是单线程的,所以用requestAnimationFrame来请求浏览器定时回调这里的这个animate()
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render( scene, camera );
//在循环中调用renderer的render()函数来渲染每一帧图像
}
animate();
三角网Mesh
立方体是用Mesh(三角网)表示的
因为三角形的三个点可以空间中唯一地确定一个平面,所以也是最常见的用于表示三维物体的一种方式
Geometry
Geometry代表几何形状,由下面的一个个三角形和构成他们的所有顶点组成
three.js里内置了很多几何形状
http://www.webgl3d.cn/threejs/docs/#api/zh/geometries/CircleGeometry
//创建场景
const scene = new THREE.Scene();
var geometry = new THREE.CircleBufferGeometry( 5, 32 );
var material = new THREE.MeshBasicMaterial( { color: 0xffff00 } );
var circle = new THREE.Mesh( geometry, material );
scene.add( circle );
//创建一个摄像机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 50;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const animate = () => {
requestAnimationFrame(animate);
circle.rotation.x += 0.01;
circle.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
Material
Material代表三维物体几何材质,不同的材质在光照下会呈现不一样的效果,通过材质可以给物体表面设定不同的颜色,光泽度,或者给物体加上贴图
基础网格材质(MeshBasicMaterial) 不参与光照计算,不会产生阴影,使用这种材质三维物体看上不去很不真实。
要想有光照效果可以使用下面的两种材质:
- Phong网格材质(MeshPhongMaterial)
- Lambert网格材质(MeshLambertMaterial)
可以用shininess属性来调节物体表面光泽度
也可以使用map添加贴图
const material = new THREE.MeshBasicMaterial({
map:new THREE.TextureLoader().load('1.png'),
}); //材质
MeshStandardMaterial
和MeshPhysicalMaterial
类是PBR物理材质,可以更好的模拟光照计算,相比较高光网格材质MeshPhongMaterial
渲染效果更逼真。
emissive默认黑色,设置为白色 发光颜色
emissiveMap 自发光贴图
roughnessMap 粗糙度贴图 设定表面不同位置的粗糙程度
normalMap 法线贴图 给每个像素点设置不同的法向量 法线会影响光照的计算 可以用它模拟物体表面凹凸不平的效果
displacementMap 高度贴图 它会上下偏移物体表面的顶点坐标,从而做到真正的物体表面的起伏
aoMap 环境光遮罩贴图 他会让被遮蔽的区域看起来更暗,进一步提升场景的真实感
//创建场景
const scene = new THREE.Scene();
var geometry = new THREE.SphereBufferGeometry( 5, 32, 32 );
var texLoader = new THREE.TextureLoader()
const material = new THREE.MeshPhongMaterial({
emissive:0xffffff,
// // 发光贴图
emissiveMap: texLoader.load("wenli.png"),
// 法线贴图
normalMap: texLoader.load("faxian.png"),
// 粗糙度贴图
roughnessMap: texLoader.load("cucao.png"),
// //高度贴图
displacementMap:texLoader.load("weiyi.png"),
//光罩贴图,会让深坑得地方更暗,更有真实感
aoMap:texLoader.load("aoMap.png"),
}); //材质
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
//创建一个摄像机
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.z = 17;
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const animate = () => {
requestAnimationFrame(animate);
//因为JavaScript是单线程的,所以用requestAnimationFrame来请求浏览器定时回调这里的这个animate()
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
//在循环中调用renderer的render()函数来渲染每一帧图像
}
animate();
几何转换
创建Mesh之后,我们可以通过position修改几何物体在空间的位置
const material = new THREE.MeshPhongMaterial({
emissive:0xffffff,
// // 发光贴图
emissiveMap: texLoader.load("wenli.png"),
// 法线贴图
normalMap: texLoader.load("faxian.png"),
// 粗糙度贴图
roughnessMap: texLoader.load("cucao.png"),
// //高度贴图
displacementMap:texLoader.load("weiyi.png"),
//光罩贴图,会让深坑得地方更暗,更有真实感
aoMap:texLoader.load("aoMap.png"),
}); //材质
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.position.set(4,0,0)
scale用来转换物体的大小 rotation旋转物体
const material = new THREE.MeshPhongMaterial({
emissive:0xffffff,
// // 发光贴图
emissiveMap: texLoader.load("wenli.png"),
// 法线贴图
normalMap: texLoader.load("faxian.png"),
// 粗糙度贴图
roughnessMap: texLoader.load("cucao.png"),
// //高度贴图
displacementMap:texLoader.load("weiyi.png"),
//光罩贴图,会让深坑得地方更暗,更有真实感
aoMap:texLoader.load("aoMap.png"),
}); //材质
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.scale.multiplyScalar(2)
摄像机
摄像机决定了我们应当从什么角度观察这个三维场景
three.js中提供了两种不同类型的摄像机
- PerspectiveCamera 透视投影
- OrthographicCamera 正交投影
http://www.webgl3d.cn/threejs/examples/#webgl_camera
PerspectiveCamera
PerspectiveCamera和我们人眼成像原理类似,看到的物体呈远小近大的透视效果。
创建相机的时候先创建视锥
在渲染的时候,计算机会将视锥中的所有三维物体投影到二维屏幕上
const camera = new THREE.PerspectiveCamera(
75, //fov 代表垂直方向上视角的大小
window.innerWidth / window.innerHeight, //aspect ratio 代表投影平面的纵宽比
0.1, //near 代表相机能看到的最近的平面
1000 //far 代表相机能看到的最远的平面,超出这个平面的场景会被自动裁剪掉
);
OrthographicCamera
OrthographicCamera正交投影相机,会将空间中的所有物体平行投影到投影面上,所以不会呈现近大远小的效果
一般应用在像CAD这种需要精确测量物体尺寸的应用场景中
比如用正交投影可以轻易的渲染出物体的三视图等等
正交相机的视锥(Frustum)是一个长方体,所以定义正交相机要先定义前后左右上下这6个面的位置
const camera = new THREE.OrthographicCamera(
-2,//left
2,//right
1.5,//top
-1.5,//bottom
1,//near
10 //far
);
一样使用position属性修改相机的位置
//三种修改position的方法
camera.position.set(0,1,5)
camera.position.y += 2
camera.translateZ(2)
camera.updateMatrix()
//更新相机的变换矩阵
参考资料
1.奇乐编程
2.http://www.yanhuangxueyuan.com/threejs/docs/index.html#manual/zh/introduction/Creating-a-scene