搞浏览器3D绘图的应该都或多多少接触过threejs,其之于webGL,如jquery之于js。有了webGL,开发者仅通过遵循其提供的api和js就能在html网页中进行3d绘图。而直接使用原生的webGL API 进行3d绘图十分繁琐,所以一个优秀的webGL框架——threeJs应运而生,其包装了很多复杂的细节,使3d绘图变得轻松了起来。
在Three.js中,要渲染物体到网页中,我们必须构建场景(scene)、相机(camera)和渲染器(renderer)。有了这三样东西,才能将物体渲染到网页中去。
ThreeJS绘图的核心:
- 设置渲染器renderer
- 设置场景 scene
- 设置相机 camera
- 设置光源 light
- 设置物体 object
1) 渲染器
渲染器的作用就是将相机所拍摄到的场景内容渲染到2d的画布上,从而在浏览器中展示。Threejs中的渲染器主要是WebGLRender。创建一个渲染器的方式就是new一个WebGLRender实例。
代码示例如下:
var renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
2) 场景
场景就是物体所处的环境,其作用就是一个容器。用来放置物体,灯光和相机。换句话说,开发时创建的物体,灯光和相机都需要将其添加进场景中,只有这样才能进行正确渲染。Ps:经过测试,相机其实可以不用添加进场景。创建一个场景的方式就是new一个scene实例。
代码示例如下:
var scene = new THREE.Scene(); // 场景
3) 相机
相机就如同人的眼睛,人站在不同角度看同一个静态事物,会看到不同的景象。因此,相机设置在不同的位置,浏览器中呈现的物体形态和位置也会有所不同。Ps:Threejs中默认相机处于三维空间原点,而创建的物体也默认中心在原点,因此在开发时,注意改变相机位置。
Threejs中的相机有以下几种类型:
- CubeCamera 立方体相机,会创建6个摄像头。
- OrthographicCamera 使用正摄投影原理的相机,及被渲染物体的尺寸与相机距离无关。详细了解参考官网示例。
- PerspectiveCamera 使用透射投影原理的相机,该相机在3d渲染中使用最为普遍。特点是:离相机远呈现更小,近则更大。符合人体对事物的实际观察规律。
- StereoCamera 立体声相机,暂不了解
代码示例如下:
var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000);
其构造器如下:
4) 光源
OpenGL(WebGL)的三维空间中,存在“点光源”和“聚光灯”两种类型。 而且,作为点光源的一种特例还存在平行光源(无线远光源)。另外,作为光源的参数还可以进行 [环境光] 等设置。
Threejs中的光源有以下几种类型:
- Ambient Light 环境光,特点:同等地照亮场景中的所有物体,没有方向。
- Direction Light 平行光,特点:定向,距离远,普遍模拟太阳光。使用正摄投影原理的相机,及被渲染物体的尺寸与相机距离无关。详细了解参考官网示例。
- HemisphereLight 半球光,特点:位于场景正上方。
- PointLight 电光源,特点:模拟灯泡。
- RectAreaLight 矩形区域光源,特点:在整个面上均匀地发射出一个矩形平面。可以用来模拟像明亮的窗户或带状照明的东西。
- SpotLight 聚光灯,特点:能投射锥形阴影区域的点光源。
和OpenGL一样,在一个场景中可以设置多个光源。 基本上,都是环境光和其他几种光源进行组合。 如果不设置环境光,那么光线照射不到的面会变得过于黑暗。
5) 物体
待渲染于画布上的3D图形,其创建后必须包含在场景中才能被正确渲染,最常用的一种方法是使用网格(Mesh)进行绘制。网格是由一个或多个多边形组成的物体,各个顶点的坐标(x, y, z)定义了多变在3D空间中的位置。网格中的多边形通常是三角形(包含三个顶点)和四边形(包含四个顶点)。3D网格通常也被称为模型(model)。
Threejs中内置了许多不同形状的几何体,常见的有:BoxGeometry(立方体),SphereGeometry(球体),CylinderGeometry(圆柱体),PlaneGeometry(平面)等,其余可查询官网API。
一个完整3D图形应该由两部分组成:网格,网格表面的材质(material),其中材质主要体现物体的外观,通常依赖于一个或多个光源来呈现出外观效果。Threejs中有多种类型的材质,常用的如下:
- MeshBasicMaterial:一个以简单着色(平面或线框)方式来绘制几何形状的材料。最主要是其不受光照影响,Ps:经测试,使用此材质的几何体即便不设置光源也
- MeshLambertMaterial:无光泽的表面材质,无镜面高光。Ps:物体颜色的最终呈现会受光照的影响。
- MeshPhongMaterial:用于表面有光泽的材料,可以模拟具有镜面高光的光泽表面。
- MeshNormalMaterial:可以是物体表面呈现彩虹色的材质。Ps:经测试,使用此材质的几何体即便不设置光源也可见。
以创建简单的立方体为例,代码如下:
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);//添加到场景中(重要)
6)渲染
以上,我们进行了渲染器,场景,相机,光源,物体的创建,最后一步就是渲染。实现这个功能的函数是:
renderer.render(scene, camera);
渲染函数的原型:render( scene, camera, renderTarget, forceClear )
- scene:前面定义的场景
- camera:前面定义的相机
- renderTarget:渲染的目标,默认是渲染到前面定义的render变量中
- forceClear:为true时,每次绘制之前都将画布的内容给清除,即使自动清除标志autoClear为false,也会清除。
7)循环渲染
就是不停的对画面进行渲染,即使画面中什么也没有改变,也需要重新渲染。当制作物体的动画效果时就需要循环渲染,只有这样才能将物体位置或形态的变化及时渲染在画布上。下面就是一个渲染循环:
function render() {
cube.rotation.x += 0.1;
cube.rotation.y += 0.1;
renderer.render(scene, camera); //加入之前创建的场景和相机。
requestAnimationFrame(render);
}
以上面创建的立方体为例,使立方体一直绕着x、y轴旋转,每次改变其旋转角度后会重新调用render函数进行渲染,最终呈现的状态就是一个不断在旋转的立方体。其中一个重要的函数是requestAnimationFrame,该函数功能如同setIntervl(),不过其性能更好。
简单完整示例
Title
<script src="three.js"></script>
<script type="text/javascript">
var scene,camera,render,geometry,material,mesh,light;
var container = document.getElementById("container");
render = new THREE.WebGLRenderer();
render.setSize(container.offsetWidth,container.offsetHeight);
container.appendChild(render.domElement);
render.setClearColor(0xFFFFFF, 0.5)
scene = new THREE.Scene();
camera = new THREE.PerspectiveCamera(45,container.offsetWidth/container.offsetHeight,1,5000);
camera.position.set(0,0,10);
// scene.add(camera);
light = new THREE.DirectionalLight(0xff0000, 1.0);//设置平行光源
light.position.set( 200, 200, 200 );//设置光源向量
scene.add(light);// 追加光源到场景(重要!)
geometry = new THREE.BoxGeometry(1,1,1);
material = new THREE.MeshBasicMaterial({color: 0x00ff00});
mesh = new THREE.Mesh(geometry,material);
scene.add(mesh);
renderer();
function renderer() {
mesh.rotation.x += 0.1;
mesh.rotation.y += 0.1;
render.render(scene,camera);
window.requestAnimationFrame(renderer);
}
</script>
参考链接:
1. WebGL中文网
2. threejs官方文档