THREE.js 入门

heavytiger 发布于1月前 阅读849次
0 条评论

基础篇

在 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);

// 向后移动 z
sphere.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);

查看原文:THREE.js 入门

共收到0条回复

需要 登录 后回复方可回复, 如果你还没有账号你可以 注册 一个帐号。