原理

threejs9threejs.png

架构

three.js.xmind

概念

一 场景

三维场景,画好的、需要去渲染的东西,类似于现实生活中用相机要去拍的东西(场景)。包括模型和光照,画了模型不添加光照的话,模型都是黑色的。

  1. var scene = new THREE.Scene();

(一)模型

包括点模型、线模型、网格模型。都是由几何体Geometry和材质Material构成的,区别在于对几何体顶点数据的渲染方式不同。

1 点模型

画几何体的顶点,使用点材质PointsMaterial

  1. // 创建一个立方体几何对象Geometry
  2. var geometry = new THREE.BoxGeometry(100, 100, 100);
  3. // 点材质对象
  4. var material = new THREE.PointsMaterial({
  5. color: 0xff0000,
  6. size: 5.0, //点对象像素尺寸
  7. });
  8. // 点模型对象
  9. var points = new THREE.Points(geometry, material);
  10. scene.add(points);

2 线模型

  • 画几何体的线条:直接使用预置的几何体,然后画它的线条。

    1. // 创建一个立方体几何对象Geometry
    2. var geometry = new THREE.BoxGeometry(100, 100, 100);
    3. // 线材质对象 实线或虚线
    4. var material=new THREE.LineBasicMaterial({
    5. color:0xff0000, // 线条颜色
    6. });
    7. // 线模型对象 构造函数:Line、LineLoop、LineSegments
    8. var line=new THREE.Line(geometry,material);
    9. scene.add(line);
  • 画直线:

    1. 通过Vector3定义几个顶点,然后通过geometry.vertices.push(p1, p2)将顶点坐标添加到geometry对象,然后生成一个线条对象。

      1. // 声明一个几何体对象Geometry
      2. var geometry = new THREE.Geometry();
      3. // 声明两个顶点
      4. var p1 = new THREE.Vector3(50, 0, 0);
      5. var p2 = new THREE.Vector3(0, 70, 0);
      6. // 顶点坐标添加到geometry对象
      7. geometry.vertices.push(p1, p2);
      8. // 线材质
      9. var material = new THREE.LineBasicMaterial({
      10. color: 0xffff00,
      11. });
      12. // 线条模型对象
      13. var line = new THREE.Line(geometry, material);
      14. // 线条对象添加到场景中
      15. scene.add(line);
    2. 通过Vector3定义几个顶点,然后用LineCurve或LineCurve3生成一个直线,然后通过LineCurve.getPoints(10)获取这个直线的顶点,通过geometry.setFromPoints(pointArr);将顶点添加到geometry对象,然后生成一条直线。

      1. // 声明一个几何体对象Geometry
      2. var geometry = new THREE.Geometry();
      3. // 声明两个顶点
      4. var p1 = new THREE.Vector3(50, 0, 0);
      5. var p2 = new THREE.Vector3(0, 70, 0);
      6. // 三维直线LineCurve3
      7. var LineCurve3 = new THREE.LineCurve3(p1, p2);
      8. // 二维直线LineCurve
      9. var LineCurve2 = new THREE.LineCurve(new THREE.Vector2(50, 0), new THREE.Vector2(0, 70));
      10. // 获取直线的点数组
      11. var pointArr = LineCurve2.getPoints(10);
      12. // 点数组赋给几何体对象
      13. geometry.setFromPoints(pointArr);
      14. // 线材质
      15. var material = new THREE.LineBasicMaterial({
      16. color: 0xffff00,
      17. });
      18. // 线条模型对象
      19. var line = new THREE.Line(geometry, material);
      20. // 线条对象添加到场景中
      21. scene.add(line);
  • 画圆弧:通过ArcCurve方法绘制一个圆弧,然后获取圆弧的顶点坐标,赋值给几何体对象

    1. // 声明一个几何体对象Geometry
    2. var geometry = new THREE.Geometry();
    3. // 参数:0, 0圆弧坐标原点x,y 100:圆弧半径 0, 2 * Math.PI:圆弧起始角度
    4. var arc = new THREE.ArcCurve(0, 0, 100, 0, 2 * Math.PI);
    5. // getPoints是基类Curve的方法,返回一个vector2对象作为元素组成的数组
    6. // 分段数50,返回51个顶点
    7. var points = arc.getPoints(50);
    8. // setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
    9. geometry.setFromPoints(points);
    10. // 线材质
    11. var material = new THREE.LineBasicMaterial({
    12. color: 0xffff00,
    13. });
    14. // 线条模型对象
    15. var line = new THREE.Line(geometry, material);
    16. // 线条对象添加到场景中
    17. scene.add(line);
  • 画样条曲线:设置几个顶点,用CatmullRomCurve3画出曲线,获取到更多顶点,然后构建一个几何体

    1. // 声明一个几何体对象Geometry
    2. var geometry = new THREE.Geometry();
    3. // 三维样条曲线 Catmull-Rom算法
    4. var curve = new THREE.CatmullRomCurve3([
    5. new THREE.Vector3(-50, 20, 90),
    6. new THREE.Vector3(-10, 40, 40),
    7. new THREE.Vector3(0, 0, 0),
    8. new THREE.Vector3(60, -60, 0),
    9. new THREE.Vector3(70, 0, 80)
    10. ]);
    11. //getPoints是基类Curve的方法,返回一个vector3对象作为元素组成的数组
    12. // 分段数100,返回101个顶点
    13. var points = curve.getPoints(100);
    14. // setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
    15. geometry.setFromPoints(points);
    16. // 线材质
    17. var material = new THREE.LineBasicMaterial({
    18. color: 0xffff00,
    19. });
    20. // 线条模型对象
    21. var line = new THREE.Line(geometry, material);
    22. // 线条对象添加到场景中
    23. scene.add(line);
  • 画贝塞尔曲线

    1. // 声明一个几何体对象Geometry
    2. var geometry = new THREE.Geometry();
    3. // 三次贝赛尔曲线的参数p1、p4是起始点,p2、p3是控制点,控制点不在贝塞尔曲线上
    4. var p1 = new THREE.Vector3(-80, 0, 0);
    5. var p2 = new THREE.Vector3(-40, 100, 0);
    6. var p3 = new THREE.Vector3(40, 100, 0);
    7. var p4 = new THREE.Vector3(80, 0, 0);
    8. // 三维三次贝赛尔曲线
    9. var curve = new THREE.CubicBezierCurve3(p1, p2, p3, p4);
    10. //getPoints是基类Curve的方法,返回一个vector3对象作为元素组成的数组
    11. // 分段数100,返回101个顶点
    12. var points = curve.getPoints(100);
    13. // setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
    14. geometry.setFromPoints(points);
    15. // 线材质
    16. var material = new THREE.LineBasicMaterial({
    17. color: 0xffff00,
    18. });
    19. // 线条模型对象
    20. var line = new THREE.Line(geometry, material);
    21. // 线条对象添加到场景中
    22. scene.add(line);
  • 多个线条组合

    1. // 声明一个几何体对象Geometry
    2. var geometry = new THREE.Geometry();
    3. // 绘制一个U型轮廓
    4. var R = 80;
    5. // 画一段圆弧
    6. var arc = new THREE.ArcCurve(0, 0, R, 0, Math.PI, true);
    7. // 半圆弧的一个端点作为直线的一个端点
    8. var line1 = new THREE.LineCurve(new THREE.Vector2(R, 200, 0), new THREE.Vector2(R, 0, 0));
    9. var line2 = new THREE.LineCurve(new THREE.Vector2(-R, 0, 0), new THREE.Vector2(-R, 200, 0));
    10. // 创建组合曲线对象CurvePath
    11. var CurvePath = new THREE.CurvePath();
    12. // 把多个线条插入到CurvePath中
    13. CurvePath.curves.push(line1, arc, line2);
    14. // 分段数200
    15. var points = CurvePath.getPoints(200);
    16. // setFromPoints方法从points中提取数据改变几何体的顶点属性vertices
    17. geometry.setFromPoints(points);
    18. // 材质对象
    19. var material = new THREE.LineBasicMaterial({
    20. color: 0x000000
    21. });
    22. // 线条模型对象
    23. var line = new THREE.Line(geometry, material);
    24. // 线条对象添加到场景中
    25. scene.add(line);

    3 网格模型

    (1)几何体

  • 长方体、球体、圆柱、正八面体、正十二面体、正二十面体

    1. // 创建一个立方体
    2. var geometry = new THREE.BoxGeometry(100, 100, 100);
    3. // 材质对象
    4. var material = new THREE.MeshLambertMaterial({
    5. color: 0x0000ff,
    6. opacity: 0.7,
    7. transparent: true,
    8. });
    9. // 网格模型对象Mesh
    10. var mesh = new THREE.Mesh(geometry, material);
    11. // 网络模型添加到场景中
    12. scene.add(mesh);
  • 曲线路径管道:由一条曲线生成一个管道

    1. // 创建多段线条的顶点数据
    2. var p1 = new THREE.Vector3(-85.35, -35.36)
    3. var p2 = new THREE.Vector3(-50, 0, 0);
    4. var p3 = new THREE.Vector3(0, 50, 0);
    5. var p4 = new THREE.Vector3(50, 0, 0);
    6. var p5 = new THREE.Vector3(85.35, -35.36);
    7. // 创建线条一:直线
    8. let line1 = new THREE.LineCurve3(p1,p2);
    9. // 创建线条2:三维样条曲线
    10. var curve = new THREE.CatmullRomCurve3([p2, p3, p4]);
    11. // 创建线条3:直线
    12. let line2 = new THREE.LineCurve3(p4,p5);
    13. // 创建CurvePath对象
    14. var CurvePath = new THREE.CurvePath();
    15. // 插入三段线条
    16. CurvePath.curves.push(line1, curve, line2);
    17. //通过多段曲线路径创建生成管道
    18. var geometry = new THREE.TubeGeometry(CurvePath, 100, 5, 25, false);
    19. // 材质对象
    20. var materialg = new THREE.LineBasicMaterial({
    21. color: 0xffff00
    22. });
    23. // 创建网格模型对象
    24. var mesh = new THREE.Mesh(geometryg, material);
    25. // 设置网络模型位置
    26. mesh.position.set(100, 100, 100);
    27. // 网络模型添加到场景中
    28. scene.add(mesh);
  • 旋转成形:由几个顶点旋转360度生成一个几何体

    1. // 定义几个顶点
    2. var points = [
    3. new THREE.Vector2(50,60),
    4. new THREE.Vector2(25,0),
    5. new THREE.Vector2(50,-60)
    6. ];
    7. // 旋转生成一个几何体
    8. var geometry = new THREE.LatheGeometry(points,30);
    9. // 材质
    10. var material=new THREE.MeshPhongMaterial({
    11. color: 0x0000ff, // 三角面颜色
    12. side: THREE.DoubleSide, // 两面可见
    13. });
    14. // 线条模式渲染:true-看到细分的三角形 false-看到设置的颜色
    15. material.wireframe = true;
    16. // 创建网格模型对象
    17. var mesh = new THREE.Mesh(geometryg, material);
    18. // 设置网络模型位置
    19. mesh.position.set(100, 100, 100);
    20. // 网络模型添加到场景中
    21. scene.add(mesh);
  • 轮廓填充:填充一个由多条曲线组成的2D图形

    1. // 圆弧与直线连接
    2. // Shape对象
    3. var shape = new THREE.Shape();
    4. var R = 50;
    5. // 绘制一个半径为R、圆心坐标(0, 0)的半圆弧
    6. shape.absarc(0, 0, R, 0, Math.PI);
    7. // 从圆弧的一个端点(-R, 0)到(-R, -200)绘制一条直线
    8. shape.lineTo(-R, -200);
    9. // 绘制一个半径为R、圆心坐标(0, -200)的半圆弧
    10. shape.absarc(0, -200, R, Math.PI, 2 * Math.PI);
    11. // 从圆弧的一个端点(R, -200)到(-R, -200)绘制一条直线
    12. shape.lineTo(R, 0);
    13. var geometry = new THREE.ShapeGeometry(shape, 30);
    14. // 材质
    15. var material=new THREE.MeshPhongMaterial({
    16. color: 0x0000ff,
    17. side: THREE.DoubleSide, // 两面可见
    18. });
    19. // 创建网格模型对象
    20. var mesh = new THREE.Mesh(geometryg, material);
    21. // 网络模型添加到场景中
    22. scene.add(mesh);
  • 拉伸扫描成型:将一个2D图形按照一条3D曲线进行拉伸扫描,生成一个几何体

    1. var shape = new THREE.Shape();
    2. // 四条直线绘制一个矩形轮廓
    3. shape.moveTo(0,0);
    4. shape.lineTo(0,10);
    5. shape.lineTo(10,10);
    6. shape.lineTo(10,0);
    7. shape.lineTo(0,0);
    8. // 创建轮廓的扫描轨迹(3D样条曲线)
    9. var curve = new THREE.SplineCurve3([
    10. new THREE.Vector3( -10, -50, -50 ),
    11. new THREE.Vector3( 10, 0, 0 ),
    12. new THREE.Vector3( 8, 50, 50 ),
    13. new THREE.Vector3( -5, 0, 100)
    14. ]);
    15. // 将矩形轮廓按照扫描轨迹进行拉伸
    16. var geometry = new THREE.ExtrudeGeometry(
    17. shape,
    18. {
    19. bevelEnabled: false, // 无倒角
    20. extrudePath: curve, // 选择扫描轨迹
    21. steps: 50, // 扫描方向细分数
    22. }
    23. );
    24. // 材质
    25. var material=new THREE.MeshPhongMaterial({
    26. color: 0x0000ff,
    27. side: THREE.DoubleSide, // 两面可见
    28. });
    29. // 创建网格模型对象
    30. var mesh = new THREE.Mesh(geometryg, material);
    31. // 网络模型添加到场景中
    32. scene.add(mesh);

    (2)材质

  • 基础网格材质

  • 与光照产生漫反射的材质
  • 高光材质
  • PBR物理材质,模拟金属、玻璃

    (二)光照

    对自然界光照的模拟,就像摄影师拍照时设置各种辅助灯光一样。不同的光源、不同的光照强度实现的渲染效果不同。
    threejs32light.png

  • 环境光

  • 点光源
  • 平行光
  • 聚光源
    1. // 点光源
    2. var point = new THREE.PointLight(0xffffff);
    3. // 点光源位置
    4. point.position.set(400, 200, 300);
    5. // 点光源添加到场景中
    6. scene.add(point);
    7. // 环境光
    8. var ambient = new THREE.AmbientLight(0x444444);
    9. // 环境光添加到场景中
    10. scene.add(ambient);

    二 相机

    一个虚拟的相机,需要设置位置、角度、投影方式。
    1. // 窗口宽度
    2. var width = window.innerWidth;
    3. // 窗口高度
    4. var height = window.innerHeight;
    5. // 窗口宽高比
    6. var k = width / height;
    7. // 三维场景显示范围控制系数,系数越大,显示的范围越大
    8. var s = 200;
    9. // 创建相机对象
    10. var camera = new THREE.OrthographicCamera(-s * k, s * k, s, -s, 1, 1000);
    11. // 设置相机位置
    12. camera.position.set(200, 300, 200);
    13. // 设置相机方向(指向的场景对象)
    14. camera.lookAt(scene.position);

    三 渲染器

    摁下相机,执行拍照动作。需要设置渲染区域的大小、背景色,执行渲染操作。
    1. // 创建渲染器对象
    2. var renderer = new THREE.WebGLRenderer();
    3. // 设置渲染区域尺寸
    4. renderer.setSize(width, height);
    5. // 设置背景颜色
    6. renderer.setClearColor(0xb9d3ff, 1);
    7. // body元素中插入canvas对象
    8. document.body.appendChild(renderer.domElement);
    9. // 执行渲染操作
    10. function render() {
    11. // 指定场景、相机作为参数
    12. renderer.render(scene,camera);
    13. requestAnimationFrame(render);
    14. }
    15. render();
    16. // 创建控件对象 监听鼠标操作
    17. // 需引入OrbitControls.js文件
    18. var controls = new THREE.OrbitControls(camera,renderer.domElement);

    示例

threejs9threejs2.png