Three.js学习记录:创建三维场景

3D基本原理

为了实现3D图像的动态展示有三个要点:

三维场景包括三维模型、光源、相机三个部分构成。

从最简单的情形来说,三维模型由网格(mesh)和材质(material)组成。网格则一般由若干个图元(一般是空间中的三角形)拼接而成。网格表面还要考虑本身的纹理和对光源的反射情况。所以3D模型的数据主要是顶点信息和网格表面材质信息。
光源就是在空间中人为添加光照信息,例如方向,强度,光色等。没有光源,渲染出来的3D场景将一片漆黑。

相机相当于场景的一个观察点。相机在建立时就要确定,视角,远平面,近平面,纵横比四个参数。根据这些参数可以确定一个可视区域。3D模型必须在可视区域(view frustum)内。否则将不会被屏幕捕捉。
图片描述

将场景以2D的形式显示

要想将场景以2D的形式显示出来,实际就是将空间中的点映射为平面的像素值。这个过程需要考虑两个关系:

模型和相机之间的关系:这个变换关系由两个矩阵控制,其中一个矩阵表示了相机所在位置和方向,另一个矩阵控制了从3D到2D的投影参数。模型和相机的关系决定空间中的某一点是否会被渲染。

光源和材质的关系: 光源和材质的关系决定这一点的像素值会是多少。着色器将会结合该点的材质(包括对光的反射率)和光照强度,判断该点的颜色。

当3D数据发生改变时,可以近乎无延迟的对2D图像更新渲染

上述复杂的映射过程,实际是交给着色器来完成的,着色器往往是一种基于gpu的程序(所谓硬件加速)。保证了渲染的低延迟。

https://codepen.io/AlexZ33/pe...

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Example01.01-Basic skeleton </title>
  <style>
     body{
       margin:0;
       overflow: hidden;
     }
  </style>

</head>
<body>
  <div id="WebGL-output">

  </div>
  <script src="https://cdn.bootcss.com/three.js/r83/three.min.js"></script>
  <script>
  function init() {
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(45,window.innerWidth/window.innerHeight,0.1,1000);
    var renderer = new THREE.WebGLRenderer();
    renderer.setClearColor(0xEEEEEE);
    renderer.setSize(window.innerWidth,window.innerHeight);
   //创建轴(axes)对象,并调用scene.add方法将轴添加到场景中
    var axes = new THREE.AxisHelper(20);
    scene.add(axes);
   //定义平面
    var planeGeometry = new THREE.PlaneGeometry(60,20,1,1);
  //创建材质来设置平面外观
    var planeMaterial = new THREE.MeshBasicMaterial({color: 0xcccccc});
  //将对象planeGeometry 和 planeMaterial 合并到名为plane的网格对象中
    var plane = new THREE.Mesh(planeGeometry,planeMaterial);
 
    plane.rotation.x = -0.5*Math.PI;
    plane.position.x = 15;
    plane.position.y = 0;
    plane.position.z = 0;
    scene.add(plane);
    var cubeGeometry = new THREE.BoxGeometry(4,4,4);
    var cubeMaterial = new THREE.MeshBasicMaterial({color:0xff0000,wireframe:true});
    var cube = new THREE.Mesh(cubeGeometry,cubeMaterial);
    cube.position.x = -4;
    cube.position.y = 3;
    cube.position.z = 0;
    
    scene.add(cube);
    var sphereGeometry = new THREE.SphereGeometry(4,20,20);
    var sphereMaterial = new THREE.MeshBasicMaterial({color:0x7777ff,wireframe:true});
    var sphere = new THREE.Mesh(sphereGeometry,sphereMaterial);
    sphere.position.x = 20;
    sphere.position.y = 4;
    sphere.position.z = 2;
    scene.add(sphere);
    camera.position.x = -30;
    camera.position.y = 40;
    camera.position.z = 30;
    camera.lookAt(scene.position);
    document.getElementById("WebGL-output")
            .appendChild(renderer.domElement);
            renderer.render(scene,camera);  
  };
  window.onload = init;
  </script>
</body>
</html>请输入代码

图片描述

接下来我们会用光照、阴影、材质和动画来美化。
首先添加光源:

//添加点光源
var spotLight = new THREE.SpotLight(0xffffff);
spotLight.position.set(-40,60,-10);
scene.add(spotLight);

因为使用的是THREE.MeshBasicMaterial所以不会对光源有反应,基本材质只会使用指定的颜色来渲染物体。
因此,替换THREE.MeshBasicMaterialTHREE.MeshLamberMaterial

图片描述

现在我们来添加阴影效果:
因为渲染阴影需要消耗大量计算资源,所以默认下是不会渲染阴影的。
因此,我们需要:

renderer.setClearColor(new THREE.Color(0xeeeeee,1.0));
render.setSize(window.innerWidth,window.innerHeight);
renderer.shadowMapEnabled = true;//告诉渲染器需要阴影效果

以上没有明确指定哪个物体投射阴影,哪个物体接受阴影。
示例中,我们将相应的属性设置为true来指定球体和立方体在地面上投射阴影:

plane.receiveShadow = true;
cube.castShadow = true;
sphere.castShadow = true;
spotLight.castShadow = true;

图片描述

可参考实例

https://codepen.io/Yakudoo/pe...

参考

《Three.js 开发指南》
3D机房前端学习笔记

阅读 1.5k

推荐阅读
镜心的小树屋
用户专栏

方寸湛然GitHub组织地址:[链接]

47 人关注
123 篇文章
专栏主页