4. three.js 的渲染结构

理解three.js 的渲染结构

1 three.js 的渲染

  • Three.js 封装了场景、灯光、阴影、材质、纹理和三维算法,让你不必再直接用WebGL 开发项目。
  • three.js 在渲染三维场景时,需要创建很多对象,并将它们关联在一起。

下图便是一个基本的three.js 渲染结构。

image.png

解释一下上面的示意图:

1.1 Renderer 渲染器

Renderer 是three.js 的主要对象。当你将一个场景Scene 和一个摄像机Camera 传递到渲染器的渲染方法中,渲染器便会将摄像机视椎体中的三维场景渲染成一个二维图像显示在canvas 画布中。

1.2 Scene 场景对象

场景对象是树状结构的,其中包含了三维对象Object3D 和灯光对象Light。

  • Object3D 是可以被直接渲染出来的,Object3D是网格对象Mesh和集合对象Group的基类
  • 场景对象可以定义场景的背景色和雾效。

在场景对象的树状结构中,每个对象的变换信息都是相对的。

比如汽车和汽车里的人,人的位置是相对于汽车而言的,当汽车移动了,人的本地坐标位坐标位虽然不变,但其世界坐标位已经变了。

1.3 Camera 相机对象

按理说,相机对象是在场景里的,但是相机对象不在它所看的场景里,这就像我们自己看不见自己的眼睛一样。

因此,相机对象可以独立于场景之外。

相机对象是可以作为其它三维对象的子对象的,这样相机就会随其父对象同步变换。

1.4 Mesh 网格对象

网格对象由几何体`Geometry`和材质`Material`两部分组成,Geometry 负责塑形,Material 负责着色。

Geometry 和Materia 是可以被多个Mesh 对象复用的

比如要绘制两个一模一样的立方体,那只需要实例化两个Mesh 即可,Geometry 和Materia可以使用一套。

1.5 Geometry 几何体对象

几何体对象负责塑形,存储了与顶点相关的数据,比如顶点点位、顶点索引、uv坐标等。

Three.js 中内置了许多基本几何体,我们也可以自定义几何体,或者从外部的模型文件里加载几何体

1.6 Material 材质对象

材质对象负责着色,绘制几何体的表面属性,比如漫反射、镜面反射、光泽度、凹凸等。

材质对象的许多属性都可以用纹理贴图表示,比如漫反射贴图、凹凸贴图等。

1.7 Texture 纹理对象

纹理对象就是一张图像。纹理图像的图像源可以是Image 图片、canvas 画布、Video 视频等。

1.8 Light 光源对象

Light 对象不像Object3D 那样依托于顶点,它更多的是像Object3D 里的材质Material 那样,作用于物体的样式。

Light 对象可以理解为在为几何体添加了材质后,再利用光效配合材质对几何体的样式进行二次加工。

2 示例-绘制多个立方体

练习一下three.js的渲染结构。

2.1. 在vue2 项目中安装three依赖

npm install three @types/three --save --registry=https://registry.npm.taobao.org

image.png

2.2 绘制一个立方体

绘制一个立方体,其渲染结构如下:

image.png

1.gif

<template>
  <div id="threeBox"></div>
</template>

<script>
import * as THREE from 'three'
export default {
  data() {
    return {
      
    }
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );

      const renderer = new THREE.WebGLRenderer();
      renderer.setSize( window.innerWidth, window.innerHeight );
      document.querySelector("#threeBox").appendChild( renderer.domElement );

      const geometry = new THREE.BoxGeometry();
      const material = new THREE.MeshNormalMaterial();
      const cube = new THREE.Mesh(geometry, material);
      scene.add(cube);

      camera.position.z = 5;
      animate()
      function animate() {
          requestAnimationFrame( animate );

          cube.rotation.x += 0.01;
          cube.rotation.y += 0.01;

          renderer.render( scene, camera );
      }


    }
  }
}
</script>

当前这个立方体的材质是MeshNormalMaterial,并不受光照影响。

2.3 修改材质,添加光源

给立方体换个MeshPhongMaterial 材质,再添加光源。

const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshPhongMaterial({ color: 0x44aa88 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

const color = 0xffffff;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);

当前的渲染结构如下:

image.png

效果如下:

1.gif

2.4 绘制多个立方体

在场景中再添加两个一模一样的立方体,几何体和材质可被多个Mesh 对象共享。

<template>
  <div id="threeBox"></div>
</template>

<script>
import * as THREE from 'three'
export default {
  data() {
    return {
      
    }
  },
  mounted() {
    this.init();
  },
  methods: {
    init() {
      // 场景和相机
      const scene = new THREE.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.querySelector("#threeBox").appendChild( renderer.domElement );
      // 光源
      const color = 0xffffff;
      const intensity = 1;
      const light = new THREE.DirectionalLight(color, intensity);
      light.position.set(-1, 2, 4);
      scene.add(light);
      // 几何体和材质
      const geometry = new THREE.BoxGeometry();
      const material = new THREE.MeshPhongMaterial({ color: 0x44aa88 });
      // 几何体和材质可被多个Mesh 对象共享。
      const cubes = [-2, 0, 2].map((num) => makeInstance(num));
      scene.add(...cubes);
      //批量生成 Mesh 网格对象
      function makeInstance(x) {
        const cube = new THREE.Mesh(geometry, material);
        cube.position.x = x;
        return cube;
      }
      // 动画渲染
      animate()
      function animate() {
        requestAnimationFrame(animate);

        cubes.forEach((cube) => {
          cube.rotation.x += 0.01;
          cube.rotation.y += 0.01;
        });

        renderer.render(scene, camera);
      }

    }
  }
}
</script>

当前的渲染结构如下:

image.png

效果如下:

1.gif

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容