THREE.js 入门

2017-01-12 09:53:23来源:作者:VillainHR人点击

基础篇

在 Web 中,实现 3D 的场景有很多方法,css 是最简单的,另外还有 canvas,webGL,webVR 等。但是,如果想让浏览器实现一个复杂的 3D 场景,如果你不好好利用 GPU 的话,那么你的网页的 jank 真的会让人 GG。而能使用 GPU 的技术也有很多,比如 transfrom 3d 的相关属性。不过考虑到灵活性,webGL 应该是第一选择,不过,webGL 没有一定的基础,确实很难掌握。而,three.js 就是抽象 webGL,让前端能根据简单的图形原理来作出有一定基础的 3D 场景。

在 Three.js 中,遵循的是一般 3D 世界的原理,它具有如下的内容:

场景 渲染器 相机 物体 光线

那如何创建一个简单的 three.js 呢? 直接放 demo:

// 设置场景大小(实际就是canvas 的大小)const WIDTH = 400;const HEIGHT = 300;// 设置相机的相关属性const VIEW_ANGLE = 45;const ASPECT = WIDTH / HEIGHT; // 屏幕比例const NEAR = 0.1;const FAR = 10000;const container = document.querySelector('#container');// 创建渲染器const renderer = new THREE.WebGLRenderer();const camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR );// 创建场景const scene = new THREE.Scene();// 将相机添加到场景中scene.add(camera);// 设置渲染器renderer.setSize(WIDTH, HEIGHT);// 将渲染器放在指定容器中container.appendChild(renderer.domElement); 创建网格

看到 网格感觉又是什么新奇的概念,实际上就是我们通常所说的几何体,比如:球体,平面,管道和圆柱体等。当然,这些只是一些原始模型,你还可以自定一些其他模型,比如使用一些其他的软件进行 3D 建模等。

// 设置球体的相关属性const RADIUS = 50;const SEGMENTS = 16;const RINGS = 16;// 创建一个球体的网格,然后使用一个材质覆盖const sphere = new THREE.Mesh( new THREE.SphereGeometry( RADIUS, SEGMENTS, RINGS), sphereMaterial);// 向后移动 zsphere.position.z = -300;// 将该球体添加到场景中scene.add(sphere); 材质

材质实际上就是网格上面覆盖的内容,THREE.js 提供了一些简单实用的材质去应用到你的网格中:

Basic: 默认,不发光材质 Lambert: 郎伯亮度 Phong: 冯材质

实际上,材质在 WebGL 中,理解为着色器(Shaders),也就是定义怎么将样式覆盖到网格上,这就会牵扯到 GLSL,一种直接和 GPU 交流的语言。不过,THREE.js 已经将这层给抽象出来,它提供了一些常用的材质,如果你想自定义一些,可以直接使用 MeshShaderMaterial来写相关的着色器。 这里我们使用 Lambert 材质:

const sphereMaterial = new THREE.MeshLambertMaterial( { color: 0xCC0000 }); 光照

如果执行到上面的代码,你会得到全黑的 canvas。因为如果你没有提供合适的光照,THREE.js 默认使用全景光,即,没有光照,就是全黑。所以,这里,我们需要添加光照:

// 添加点光源const pointLight = new THREE.PointLight(0xFFFFFF);// 设置点光源位置pointLight.position.x = 10;pointLight.position.y = 50;pointLight.position.z = 130;// 添加到场景中scene.add(pointLight); 渲染器

当然,你添加了上面的代码也不一定你能够渲染出来,因为,你根本没执行渲染操作。这里会涉及到相机的概念,我们可以将渲染理解为快照,你虽然将物体放在空间里面,但你并没有按下快门(渲染),那么该物体是不会被投影到你的屏幕上的,所以,你需要执行一次快照,让物体成功的渲染:

renderer.render(scene, camera);

当然,如果你还设计到动画,则可以利用 RAF 来进行重复执行快照:

function update () { // Draw! renderer.render(scene, camera); // Schedule the next frame. requestAnimationFrame(update);}// Schedule the first frame.requestAnimationFrame(update); 几何体

上面,我们通过 new Mesh 创建了一个几何体实例,而且是每个几何体实例都是继承了 Object3D。它上面挂在几个通用的属性:

position: 包含 x,y,z rotation: 同上 scale: 同上 geometry: vertices: 一个数组,表示该几何体上的点 faces: 一个数组,表示该几何体上的面 materials: 该几何体的材质

另外,当我们在不断进行渲染时,有可能会遇到渲染不成功的情况,那么这个时候,有可能是 THREE.js 把你的 Object3D 给缓存了。那应该怎么强制关闭缓存呢? 直接使用:

// 顶点发生改变sphere.geometry.verticesNeedUpdate = true;// 正常更新sphere.geometry.normalsNeedUpdate = true;

总的代码如下:

// Set the scene size. const WIDTH = window.innerWidth; const HEIGHT = window.innerHeight; // Set some camera attributes. const VIEW_ANGLE = 45; const ASPECT = WIDTH / HEIGHT; const NEAR = 0.1; const FAR = 10000; // Get the DOM element to attach to const container = document.querySelector('#container'); // Create a WebGL renderer, camera // and a scene const renderer = new THREE.WebGLRenderer(); const camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR ); const scene = new THREE.Scene(); // Add the camera to the scene. scene.add(camera); // Start the renderer. renderer.setSize(WIDTH, HEIGHT); // Attach the renderer-supplied // DOM element. container.appendChild(renderer.domElement); // create a point light const pointLight = new THREE.PointLight(0xFFFFFF); // set its position pointLight.position.x = 10; pointLight.position.y = 50; pointLight.position.z = 130; // add to the scene scene.add(pointLight); // create the sphere's material const sphereMaterial = new THREE.MeshLambertMaterial( { color: 0xCC0000 }); // Set up the sphere vars const RADIUS = 50; const SEGMENTS = 16; const RINGS = 16; // Create a new mesh with // sphere geometry - we will cover // the sphereMaterial next! const sphere = new THREE.Mesh( new THREE.SphereGeometry( RADIUS, SEGMENTS, RINGS), sphereMaterial); // Move the Sphere back in Z so we // can see it. sphere.position.z = -300; // Finally, add the sphere to the scene. scene.add(sphere); function update () { // Draw! renderer.render(scene, camera); // Schedule the next frame. requestAnimationFrame(update); } // Schedule the first frame. requestAnimationFrame(update);

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台