THREE.js

1,481 阅读5分钟

关于WebGL

WebGL 是基于 OpenGL ES 2.0 的 Web 标准,可以通过 HTML5 Canvas 元素作为 DOM 接 口访问。

什么是 THREE.js

Three.js是JavaScript编写的WebGL第三方库。 Three.js 封装了WebGL底层的图形接口,开发人员无需掌握图形学知识即可以用简单的js代码实现三维场景的渲染。 渲染3d模型的时候,其实 是 很多个三角形拼接出来的。如下:

左边是 一个 立方体,右侧的是 一个 球体(球体的话,切分出的 三角形 越多 网格模型更加 贴近 球体);

核心代码如下

//立方体 (x轴宽度,y轴高度,z轴深度,沿宽面分段数,沿高度面分段数,沿深度面分段数)
object = new THREE.Mesh(
  new THREE.BoxGeometry(100, 100, 100, 1, 1, 1),
  material
);
object.position.set(-200, 0, -200);
scene.add(object);

//立方体 (x轴宽度,y轴高度,z轴深度,沿宽面分段数,沿高度面分段数,沿深度面分段数)
object = new THREE.Mesh(
  new THREE.BoxGeometry(100, 100, 100, 2, 2, 2),
  material
);
object.position.set(-200, 0, 200);
scene.add(object);

//球形网格 (半径长度,水平块的密度,垂直块的密度)
var object = new THREE.Mesh(new THREE.SphereGeometry(75, 5, 5), material);
object.position.set(200, 0, -200);
scene.add(object);

//球形网格 (半径长度,水平块的密度,垂直块的密度)
var object = new THREE.Mesh(new THREE.SphereGeometry(75, 50, 50), material);
object.position.set(200, 0, 200);
scene.add(object);



一个three.js 项目中 三个重要对象,场景scenecamerarenderer

一个典型的 Three.js 程序至少要包括渲染器(Renderer)、场景(Scene)、照相机 (Camera),以及你在场景中创建的物体。

  • scene: 在 Three.js 中添加的物体都是添加到场景中的,因此它相当于一个大容器。
  • renderer: 渲染器,挂载了一个canvas 标签,用来最终渲染的
  • camera:摄像机,相当于在三维场景中人的眼睛。

设置好各个对象的配置信息后,最终渲染的方法就是: renderer.render(scene, camera);

看这三个对象前,需要先了解一下 three.js的坐标系

WebGL 和 Three.js 使用的坐标系是右手坐标系,看起来就是这样的:

创建一个three.js 项目的基本步骤如下

1.创建场景 scene

var scene;
function initScene(){
    scene = new THREE.Scene();
}

2.创建相机 camera

两种相机,正交相机透视投影相机

一般说来,对于制图、建模软件通常使用正交投影,这样不会因为投影而改变物体比例; 而对于其他大多数应用,通常使用透视投影,因为这更接近人眼的观察效果。

下面图a是透视投影(近大远小,更真实),图b是正交投影

正交相机

构造函数: THREE.OrthographicCamera(left, right, top, bottom, near, far)

  • 这六个参数分别代表正交投影照相机拍摄到的空间的六个面的位置,这两个面围成一个长 方体,我们称其为视景体(Frustum)。只有在视景体内部(下图中的灰色部分)的物体才 可能显示在屏幕上,而视景体外的物体会在显示之前被裁减掉。
  • 为了保持照相机的横竖比例,需要保证 (right - left) 与 (top - bottom) 的比例与 Canvas 宽度与高度的比例一致。

创建方式如下:

var camera = new THREE.OrthographicCamera(-2, 2, 1.5, -1.5, 1, 10);
camera.position.set(0, 0, 5);
scene.add(camera);

透视投影相机

构造函数:THREE.PerspectiveCamera(fov, aspect, near, far)

  • fov 是视景体竖直方向上的张角(是角度制而非弧度制),如侧视图所示。
  • aspect 等于 width / height ,是照相机水平方向和竖直方向长度的比值,通常设为 Canvas 的横纵比例。
  • near 和 far 分别是照相机到视景体最近、最远的距离,均为正值,且 far 应大于 near 。

透视图中,灰色的部分是视景体,是可能被渲染的物体所在的区域。

创建方式如下

var camera;
function initCamera(){
    camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
}

3.创建渲染器 renderer

var renderer
function initScene(){
    renderer = new THREE.WebGLRenderer();
    renderer.setSize( window.innerWidth, window.innerHeight );
    document.body.appendChild( renderer.domElement );
}

4.创建网格模型

var geometry = new THREE.BoxGeometry(1,1,1);
var matrial = new THREE.MeshBasicMaterial({color:0x00ff00});
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

5.一个简单的demo

知道了以上关键的即可以动手渲染一个简单的 3d场景

var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;

// 创建一个渲染器
var renderer = new THREE.WebGLRenderer({
  antialias: true
});
renderer.setSize(windowWidth, windowHeight);

document.body.appendChild(renderer.domElement);

// 创建一个场景,所有的 3d模型都需要添加到 场景中才可以渲染
var scene = new THREE.Scene();

// 创建一个 camera
var camera = new THREE.PerspectiveCamera(
  45,
  windowWidth / windowHeight,
  1,
  4000
);
camera.position.set(0, 0, 3);

// 创建一个光找模型
var light = new THREE.AmbientLight("#ffffff");
light.position.set(0, 0, 1);
scene.add(light);

var map = new THREE.TextureLoader().load("./img/lala.jpg");
// 创建材质,在模型上需要用到
var material = new THREE.MeshPhongMaterial({
  map: map
});

// 一个立方体
var geometry = new THREE.CubeGeometry(1, 1, 1);

// 创建一个 由 3d模型 和 材质组成 的 网格模型
var cube = new THREE.Mesh(geometry, material);
scene.add(cube);

(function animate() {
  // 渲染
  renderer.render(scene, camera);
  cube.rotation.x += 0.02;
  cube.rotation.y += 0.02;
  requestAnimationFrame(animate);
})();

常用的几个 配置对象:

材质

基本的材质MeshBasicMaterial

使用基本材质的物体,渲染后的颜色始终为设置的颜色,也就是说不受光照影响,例如 设置太阳就很有用,当没有设置颜色的,颜色将是随机的

构造函数是:THREE.MeshBasicMaterial(opt);

//例子(创建一个 颜色为黄色,不透明度为0.75的材质)
var  geometry = new THREE.SphereGeometry(3,30,30);
var map =  new THREE.TextureLoader().load('./img/lala.jpg');
var material = new THREE.MeshBasicMaterial({
   color:0xffff00,
   opacity:0.75
})

var cube = new THREE.Mesh(geometry, material)

MeshLambert材质 和 MeshPhong材质

THREE.MeshLambertMaterial(opt) 与 THREE.MeshPhongMaterial(opt) 和 基本材质 THREE.MeshBasicMaterial(opt) 的是用方法一致。 他们的几个常用属性(逗号后面的为默认值)

  • visible:是否可见 ,true
  • side: 渲染面片 正面还是反面,默认为 THREE.FrontSide
  • wireframe: 是否渲染为 线 而不是 面,默认为 false,
  • color: 十六进制颜色(0xffffff)
  • map: 使用纹理贴图,如(new THREE.TextureLoader().load('./img/lala.jpg');

区别就是 在光照下,Lambert 模型 是漫反射,更加适合用生活中的大部分情况,而Phong模型则适合用在 金属 和镜面 相对反射率 比较高的物体上

  • Phong材质

  • Lambert材质

Light(光源)

// 环境光,各个角度观察无差别
var light = new THREE.AmbientLight("#0000ff");
light.position.set(0, 0, 1);
scene.add(light);

// 点光源,顾名思义
spotLight = new THREE.PointLight("#ffffff");
spotLight.position.set(0, 0, 0);
scene.add(spotLight);

// 平行光,顾名思义
directionalLight = new THREE.DirectionalLight("#ffffff");
directionalLight.position.set(-40, 60, -10);
//告诉平行光需要开启阴影投射
directionalLight.castShadow = true;
scene.add(directionalLight);

加载外部模型,比如 stl格式

<!--需要先引入STL加载器,其他的类似-->
	<script src="./lib/STLLoader.js"></script>
function initModel() {

  //辅助工具
  var loader = new THREE.STLLoader();
  loader.load("./model/aixiaofei.stl", function(geometry) {
    //创建纹理
    new THREE.TextureLoader().load("./img/lala.jpg", function(map) {
    var material = new THREE.MeshPhongMaterial({
        color:0xffffff,
        map: map
      });

      var mesh = new THREE.Mesh(geometry, material);
      mesh.rotation.x = -0.5 * Math.PI; //将模型摆正
      mesh.scale.set(0.1, 0.1, 0.1); //缩放
      geometry.center(); //居中显示
      scene.add(mesh);
    });
  });
}

stlModel

例子

  1. 太阳系

  1. VR