ThreeJs 入门(01)-编写第一个three.js程序

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

近年来web得到了快速的发展。随着HTML5的普及,网页的表现能力越来越强大。网页上已经可以做出很多复杂的动画,精美的效果。通过Threejs可以让我们轻松地在网页上实现3D效果。

yuque_diagram.jpg

示例代码采用three.js-r73版本:cdnjs.cloudflare.com/ajax/libs/t…

1. 四大组件概念介绍

在Three.js中,要渲染物体到网页中,我们需要4个组件:场景(scene)、相机(camera)、渲染器(renderer)和几何体(geometry)。 记住关键语句:有了这四样东西,我们才能够使用相机将场景中的物体渲染到网页上去

1. 场景

  • 场景就是舞台,你可以把任何要显示的东西,放在场景中的任何位置。
THREE.Scene = function ()
复制代码
  • 场景创建
var scene = new THREE.Scene();
复制代码
  • 提问:那我们能不能在浏览器中放多个场景?
    • 答案是可以的。我们可以在页面中放多个场景(new 多个场景实例)

2. 相机

  • 相机就是现实生活中的相机,我们最终能够在浏览器中看到的景象,就是相机拍摄出来的。
  • 相机决定了场景中那个角度的景色会显示出来。相机就像人的眼睛一样,人站在不同位置,抬头或者低头都能够看到不同的景色。
  • 场景只有一种,但是相机却又很多种。和现实中一样,不同的相机确定了呈相的各个方面。比如有的相机适合人像,有的相机适合风景,专业的摄影师根据实际用途不一样,选择不同的相机。对程序员来说,只要设置不同的相机参数,就能够让相机产生不一样的效果。
  • 相机分类有多种,这里介绍两种:透视相机和正投影相机

image.png

1. 透视相机

  • 透视相机:透视投影符合人们心理习惯,即离视点近的物体大,离视点远的物体小,远到极点即为消失,成为灭点。(近大远小)

2. 正投影相机

  • 就是远处的和近处的是一样大。(保持不变)

注:透视相机和正投影相机的概念,有点像 thingjs 中的 keepSize 参数的作用,设置/获取 图标是否保持像素大小不变。默认为 false,即图标在 3D 场景中呈现“近大远小”的表现形式。

3. 相机参数

image.png

THREE.PerspectiveCamera = function (fov, aspect, near, far)
复制代码
  • 视角fov:上下两个平面的夹角 θ,这个最难理解,我的理解是,眼睛睁开的角度,即,视角的大小,如果设置为0,相当你闭上眼睛了,所以什么也看不到,如果为180,那么可以认为你的视界很广阔,但是在180度的时候,往往物体很小,因为他在你的整个可视区域中的比例变小了。
  • 近平面near:表示你近处的裁面的距离。补充一下,也可以认为是眼睛距离近处的距离,假设为10米远,请不要设置为负值,Three.js就傻了,不知道怎么算了,
  • 远平面far:表示你远处的裁面,
  • 纵横比aspect:实际窗口的纵横比,即宽度除以高度。这个值越大,说明你宽度越大,那么你可能看的是宽银幕电影了,如果这个值小于1,那么可能你看到的是如下的图中的LED屏幕了。

image.png

  • 代码示例
var camera = new THREE.PerspectiveCamera(45, width/height, 1, 1000 );
scene.add( camera );
复制代码

3. 渲染器

  • 渲染器决定了渲染的结果应该画在页面的什么元素上面,并且以怎样的方式来绘制。
  • 就像是画家怎么将眼前的场景画到屏幕上。
  • 计算的过程叫渲染
  • 这里我们定义了一个 WebRenderer 渲染器,代码如下所示:
THREE.WebGL.Renderer()
复制代码

4. 几何体

  • 几何体,即使要显示在场景中的对象
  • 几何体是网格模型,如果加了纹理,就像穿了衣服。如果加了光照,会显示光亮不同的颜色。

image.png

2. 编写第一个 three.js 程序

1. 创建场景

在Threejs中场景就只有一种,用THREE.Scene来表示,要构件一个场景也很简单,只要new一个对象就可以了,代码如下:

// 1. 定义场景
var scene = new THREE.Scene();
console.log(scene);
复制代码
  • 场景是所有物体的容器,如果要显示一个苹果,就需要将苹果对象加入场景中。
  • scene中有 add 方法,一会我们会用到

2. 创建透视摄像机

  • THREE.PerspectiveCamera透视摄像机
  • 我们创建一个,夹角为75度,相机拍摄面的长宽比为窗口宽度/窗口高度,近裁剪面为1,远裁剪面为1000
  • 1和1000的单位可以是米,也可以是厘米,这个是自己想象(目前是这样理解的)
// 2. 定义相机 夹角:75度,显示大小:窗口宽度/窗口高度,显示距离:最近1米,最远1000米
var camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 1000 );
复制代码

3. 创建渲染器以及渲染器大小

// 3. 定义渲染器
var renderer = new THREE.WebGLRenderer();
renderer.setClearColor("#ffffff"); // 每次设置渲染器,清空渲染器颜色,变为白色
// 4. 设置渲染器大小
renderer.setSize(window.innerWidth, window.innerHeight);
console.log(renderer);
// 5. 将渲染器添加到 body 上
document.body.appendChild(renderer.domElement);
复制代码
  • setClearColor设置颜色及其透明度
  • renderer.setSize设置画布的大小
  • renderer.domElement返回的是一个 canvas,渲染器的构造函数会自动创建(如果没有传入canvas参数),所有的渲染都是画在domElement上的
  • 这里的appendChild表示将这个domElement挂接在body下面,这样渲染的结果就能够在页面中显示了。

4. 定义几何体并添加到场景中

上面的画布准备好了,然后我们要往画布中添加物体(3D几何体)

// 6. 定义几何体
// 宽度,高度,深度,后面不设置默认为 1
// width, height, depth, widthSegments, heightSegments, depthSegments
var geometry = new THREE.BoxGeometry(2, 2, 2);
// 7. 定义材质
var material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
// 8. 定义网格, 几何体和材质组成网格
var cube = new THREE.Mesh(geometry, material);
// 9. 将网格模型添加到场景中
scene.add(cube);
// 10. 改变相机位置
// 此时我们的相机在坐标原点,物体也在坐标原点,所以我们什么也看不到
camera.position.z = 10; // 向屏幕外移动 5 米
复制代码
  • THREE.BoxGeometryBoxGeometry是四边形的原始几何类,它通常使用构造函数所提供的“width”、“height”、“depth”参数来创建立方体或者不规则四边形。这是一个包含立方体所有顶点和填充面的对象
    • width — X轴上面的宽度,默认值为1。
    • height — Y轴上面的高度,默认值为1。
    • depth — Z轴上面的深度,默认值为1。
    • widthSegments — (可选)宽度的分段数,默认值是1。
    • heightSegments — (可选)宽度的分段数,默认值是1。
    • depthSegments — (可选)宽度的分段数,默认值是1。
  • THREE.MeshBasicMaterial一个以简单着色(平面或线框)方式来绘制几何体的材质。这种材质不受光照的影响。
    • color — 可以作为十六进制字符串传递,默认情况下为 0xffffff(白色),内部调用Color.set(color)。
  • THREE.Mesh表示基于以三角形为polygon mesh(多边形网格)的物体的类。 同时也作为其他类的基类,例如SkinnedMesh。
    • geometry —— (可选)Geometry或者BufferGeometry的实例,默认值是一个新的BufferGeometry。
    • material —— (可选)一个Material,或是一个包含有Material的数组,默认是一个新的MeshBasicMaterial。
    • 也就是说,几何体和材质组成网格
  • 最后调用 scene.add() 时,对象将被添加到原点处,即坐标点**(0,0,0)**,这将导致相机和立方体发生空间重叠。为了避免这样,我们把相机(camera)的位置移出来一些

5. 定义渲染器方法进行渲染

如果你在新建作品中拷贝了前述的代码,并点击[运行],你还是看不到任何东西,因为我们还没有实际去渲染它。为此,我们需要一个 渲染循环(render loop)

// 11. 定义渲染方法
function render() {
  // 当浏览器空闲,就不断调用传入的函数
  requestAnimationFrame(render);
  // 通过场景和相机,把最终显示的东西渲染出来,渲染到 renderer.domElement 上
  renderer.render(scene, camera);
}
render();
复制代码

这将创建一个循环,以每秒60次的频率来绘制场景。requestAnimationFrame这个函数,它用来替代 setInterval, 这个新接口具备多个优点,比如浏览器Tab切换后停止渲染以节约资源、和屏幕刷新同步避免无效刷新、在不支持该接口的浏览器中能安全回退为setInterval。

让物体动起来

  • 现在在页面上应该可以看到一个红色的立方体,我们添加一点动画,让它转动起来。
  • 把如下代码加在 render 函数中 renderer.render 这行代码之前:
function render() {
  // 当浏览器空闲,就不断调用传入的函数
  requestAnimationFrame(render);
  cube.rotation.x += 0.1; // 围绕 x 轴旋转
  cube.rotation.y += 0.1; // 围绕 y 轴旋转
  // 通过场景和相机,把最终显示的东西渲染出来,渲染到 renderer.domElement 上
  renderer.render(scene, camera);
}
复制代码
  • 这样我们就使用Three.js完成了一个旋转的立方体。基本上,如果要改变立方体的运动,我们都是在render循环中处理。

3. 总结场景、相机、渲染器、几何体之间的关系

  • Three.js 中的场景是一个物体的容器,开发者可以将需要的几何体放入场景中,例如苹果,葡萄。同时,几何体自身也管理着其在场景中的位置。
  • 相机的作用就是面对场景,在场景中取一个合适的景,把它拍下来。
  • 渲染器的作用就是将相机拍摄下来的图片,放到浏览器中去显示。
  • 他们四者的关系如下图所示:

image.png

Guess you like

Origin juejin.im/post/7055826414133575688