1、简介
WebGL 是在浏览器中实现三维效果的一套规范,而 Three.js 可以看成是浏览器对 WebGL 规范实现的一套封装, 能够让 Web 开发者使用 JavaScript 语言直接和显卡(GPU)进行通信。其中得 GLSL 是GPU 部分对应的编程语言,可以用 GLSL 编写着色器程序,并配合 JavaScript 共同实现 3D 效果。一个简单的 Three.js 程序包含以下几个部分:
<html>
<head>
<title>My first Three.js app</title>
<style>
body { margin: 0; }
canvas { width: 100%; height: 100% }
</style>
</head>
<body>
<script src="//wow.techbrood.com/libs/three.r73.js"></script>
<script>
// 1、建立场景
var scene = new THREE.Scene();
// 2、建立相机
var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 );
camera.position.z = 5;
// 3、建立渲染器
var renderer = new THREE.WebGLRenderer();
renderer.setSize( window.innerWidth, window.innerHeight );
document.body.appendChild( renderer.domElement );
// 4、建立物体
var geometry = new THREE.BoxGeometry( 1, 1, 1 );
var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
var cube = new THREE.Mesh( geometry, material );
scene.add( cube );
// 5、开始绘制
var render = function () {
requestAnimationFrame( render );
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera);
};
render();
</script>
</body>
</html>
2、概念介绍
- 场景
在 Threejs 中场景就只有一种,用THREE.Scene来表示,要构件一个场景也很简单,只要new一个对象就可以了,代码如下:
var scene = new THREE.Scene();
场景是所有物体的容器,如果要显示一个苹果,就需要将苹果对象加入场景中。
- 相机
相机决定了场景中哪个角度的景色会显示出来,在 Threejs 中有多种相机,这里介绍两种,它们是:
透视相机(THREE.PerspectiveCamera)和正投影相机(THREE.OrthographicCamera),透视相机跟人眼差不多,有近大远小的效果,而正投影相机则没有这个效果,所有东西显示都是一样大
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
- 渲染器
渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。ThreeJS 框架提供了好几种渲染器对象,分别使用不同的底层技术实现,比如:
WebGLRenderer使用 WebGL 技术;CanvasRenderer使用 Canvas 2D 技术;CSS2DRenderer和CSS3DRenderer则是使用 CSS 技术;
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
- 物体 Mesh
Mesh 好比一个包装工,它将『可视化的材质』粘合在一个『数学世界里的几何体』上,形成一个『可添加到场景的对象』。
当然,创建的材质和几何体可以多次使用(若需要)。而且,包装工不止一种,还有 Points(点集)、Line(线/虚线) 等,比如添加一个几何体到场景中:
var geometry = new THREE.CubeGeometry(1,1,1);
var material = new THREE.MeshBasicMaterial({color: 0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);
CubeGeometry 表示一个几何体
几何体 Geometry
目前 Three.js 一共提供了 22 个 Geometry,详情参见https://aotu.io/notes/2017/08/28/getting-started-with-threejs/index.html点 & 线
创建一个点:
var point1 = new THREE.Vecotr3(4,8,9);
// or
var point1 = new THREE.Vector3();
point1.set(4,8,9)
创建一条线:线由点组成(准确来说由点,材质和颜色组成),所以先创建点,再组合点(通过Geometry组织点),Threejs 中没有提供单独画点的函数,它必须被放到一个THREE.Geometry形状中
// 方式 1
var geometry = new THREE.Geometry();
var material = new THREE.LineBasicMaterial( { vertexColors: true } );
var color1 = new THREE.Color( 0x444444 ), color2 = new THREE.Color( 0xFF0000 );
// 线的材质可以由2点的颜色决定
var p1 = new THREE.Vector3( -100, 0, 100 );
var p2 = new THREE.Vector3( 100, 0, -100 );
// vertices 保存点,colors 保存对应点的颜色
geometry.vertices.push(p1);
geometry.vertices.push(p2);
geometry.colors.push( color1, color2 );
var line = new THREE.Line( geometry, material, THREE.LinePieces );
// 方式 2
var geometry = new THREE.Geometry();
geometry.vertices.push( new THREE.Vector3( - 500, 0, 0 ) );
geometry.vertices.push( new THREE.Vector3( 500, 0, 0 ) );
for ( var i = 0; i <= 20; i ++ ) {
var line = new THREE.Line( geometry, new THREE.LineBasicMaterial( { color: 0x000000, opacity: 0.2 } ) );
line.position.z = ( i * 50 ) - 500;
scene.add( line );
}
操作线的某一维坐标本质是做平移
- 坐标系
Threejs使用的是右手坐标系,x轴正方向向右,y轴正方向向上,z轴由屏幕从里向外
- 运动原理
要么是摄像机移动(camera.position),要么是物体移动(object.position)
- 光源
1、环境光
环境光是经过多次反射而来的光,无法确定其最初的方向。环境光是一种无处不在的光。环境光源放出的光线被认为来自任何方向。因此,当你仅为场景指定环境光时,所有的物体无论法向量如何,都将表现为同样的明暗程度。
var light = new THREE.AmbientLight( 0xff0000 );
scene.add( light );
2、点光源
由这种光源放出的光线来自同一点,且方向辐射自四面八方
PointLight( color, intensity, distance )
3、聚光灯
这种光源的光线从一个锥体中射出,在被照射的物体上产生聚光的效果。使用这种光源需要指定光的射出方向以及锥体的顶角α
THREE.SpotLight( hex, intensity, distance, angle, exponent )
- 材质
材质的本质就是光
- 纹理
纹理的本质就是图片或者说贴图,纹理主要用于丰富材质,
1、用图片创建一个纹理:
// 创建一个几何平面
var geometry = new THREE.PlaneGeometry( 500, 300, 1, 1 );
// 设置纹理坐标
geometry.vertices[0].uv = new THREE.Vector2(0,0);
geometry.vertices[1].uv = new THREE.Vector2(2,0);
geometry.vertices[2].uv = new THREE.Vector2(2,2);
geometry.vertices[3].uv = new THREE.Vector2(0,2);
// 加载纹理
var texture = THREE.ImageUtils.loadTexture("textures/a.jpg",null,function(t)
{
});
// 将纹理运用到材质
var material = new THREE.MeshBasicMaterial({map:texture});
// 结合几何体和材质
var mesh = new THREE.Mesh( geometry,material );
scene.add( mesh );
2、用 canvas 创建纹理
var geometry = new THREE.CubeGeometry(150, 150, 150);
texture = new THREE.Texture( canvas);
var material = new THREE.MeshBasicMaterial({map:texture});
texture.needsUpdate = true;
mesh = new THREE.Mesh( geometry,material );
scene.add( mesh );
需要注意的是在定义了纹理之后,我们将texture.needsUpdate设置为了true,如果不设置为true,那么纹理就不会更新,很可能你看到的是一个黑色的正方体,原因是纹理没有被载入之前,就开始渲染了,而渲染使用了默认的材质颜色
- 模型
模型是由面组成,面分为三角形和四边形面。三角形和四边形面组成了网格模型。在Three.js中用THREE.Mesh来表示网格模型。THREE.Mesh可以和THREE.Line相提并论,区别是THREE.Line表示的是线条。THREE.Mesh表示面的集合。
THREE.Mesh = function ( geometry, material )
第一个参数geometry:是一个THREE.Geometry类型的对象,他是一个包含顶点和顶点之间连接关系的对象。
第二个参数Material:就是定义的材质。有了材质就能够让模型更好看,材质会影响光照、纹理对Mesh的作用效果。
// VTK loader 使用示例
var material = new THREE.MeshLambertMaterial( { color:0xffffff, side: THREE.DoubleSide } );
var loader = new THREE.VTKLoader();
loader.addEventListener( 'load', function ( event ) {
var geometry = event.content;
var mesh = new THREE.Mesh( geometry, material );
mesh.position.setY( - 0.09 );
scene.add( mesh );
});
loader.load( "models/vtk/bunny.vtk" );
- 相机控制
通过鼠标控制相机 TrackballControls
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1e10 );
camera.position.z = 0.2;
controls = new THREE.TrackballControls( camera );
controls.rotateSpeed = 5.0;
controls.zoomSpeed = 5;
controls.panSpeed = 2;
controls.noZoom = false;
controls.noPan = false;
controls.staticMoving = true;
controls.dynamicDampingFactor = 0.3;
- 阴影
阴影是增强三维场景效果的重要因素,但 Three.js 出于性能考虑,默认关闭阴影
// 启用阴影
renderer.shadowMap.enabled = true
// 并不是所有类型的光源能产生投影,不能产生投影的光源有:环境光(AmbientLight)、半球光(HemisphereLight)
spotLight.castShadow = true
// 平面和立方体都能接受阴影
plane.receiveShadow = true
cube.receiveShadow = true
// 球体的阴影可以投射到平面和球体上
sphere.castShadow = true
// 更改渲染器的投影类型,默认值是 THREE.PCFShadowMap
renderer.shadowMap.type = THREE.PCFSoftShadowMap
// 更改光源的阴影质量,默认值是 512
spotLight.shadow.mapSize.width = 1024
spotLight.shadow.mapSize.height = 1024
- 雾化
// Fog( hex, near, far ),线性雾化。
// near 表示哪里开始应用雾化效果(摄像机为 0)
// far 表示哪里的雾化浓度为 1。若某物体在该距离后,则其表现为雾的颜色。当雾的颜色和渲染器的背景色相同时,则表现为消失(实为颜色相同)。
scene.fog = new THREE.Fog( 0xffffff, 0.015, 100 )
// FogExp2( hex, density ),指数雾化
// density 是雾化强度
scene.fog = new THREE.FogExp2( 0xffffff, 0.01 )
// 雾化效果默认是全局影响的,若某个材质不受雾化效果影响,则可为材质的 fog 属性设置为 false(默认值 true)
var material = new THREE.Material({
fog: false
})
- 渲染器剔除模式
在 Three.js 中,材质默认只应用在正面(THREE.FrontSide),即当你旋转物体(或摄像机)查看物体的背面时,它会因为未被应用材质而变得透明(即效果与 CSS3 backface-visibility: hidden 一样)。因此,当你想让物体正反两面均应用材质,则需要在创建材质时声明 side 属性为 THREE.DoubleSide:
var material = new THREE.MeshBasicMaterial({
side: THREE.DoubleSide // 其他值:THREE.FrontSide(默认值)、THREE.BackSide
})
这个模式应用在3D看房时比较好用
- 声音 Audio
音频也是 3D 的,它会受到摄像机的距离影响:
1、声源离摄像机的距离决定着声音的大小。
2、声源在摄像机左右侧的位置分别决定着左右扬声器声音的大小。