Three.js 学习笔记(一)

2019-04-13

本篇主要记录一下自己的threejs学习笔记

Javascript 3D library,提供了 Canvas 2D,SVG,CSS3D 和 WebGL 渲染器。

什么是 WebGL?

WebGL,使浏览器能够展示 3D 模型和场景。

浏览器实现了OpenGL ES规范,通过 OpenGL ES 可以直接通过 API 直接调用显卡。

WebGL 实际上就是通过 Javascript 操作 OpenGL 接口从而来调用显卡绘制场景。

WebGL 是如何对 GPU 进行编程的

  • WebGL 的 API,由 Javascript 提供。
  • GLSL(着色器语言),定点着色器片元着色器

WebGL 是通过 Javascript 的 API 去创建一个显存中的Buffer,从而实现将数据传递给定点着色器和片元着色器的。

创建一个 WebGL 程序的过程

  • 初始化 WebGL 绘图上下文
  • 初始化着色器程序
  • 建立模型和数据缓存
  • 完成绘制和动画

three.js 是什么

thress.js 是对 WebGL 的封装。ThreeJS是由 Ricardo Cabello 在 2010 年 4 月开源于 GitHub 的 3D 框架,基于这个框架我们可以直接使用 JavaScript 语言在网页中构建 3D 场景;

几个核心的关键因素

  • 相机
  • 渲染器
  • 物体
  • 光源

渲染器的作用是成像,ThreeJS 提供了好几种渲染器对象。

WebGLRenderer使用WebGL (最强大,主流浏览器支持较好)
CanvasRenderer使用Canvas 2D (具有较好的兼容性,但也有居多限制)
CSS2DRenderer和CSS3DRenderer则是使用CSS技术(具有较好的兼容性,但也有居多限制)

相机的作用决定了观察的视角和位置,ThreeJS 中提供了多种相机

PerspectiveCamera远景投影,也称之为透视投影。这个是我们人眼观察世界的模式.近大远小
OrthographicCamera投影线垂直于投影面的投影属于正交投影 ,也称为平行投影。
CubeCamera 立方体相机,创建6个远景相机并渲染到1个WebGL渲染器目标上

创建物体,ThreeJS 中实现了很多种几何体。例如立方几何体形状几何体等等。

光源,ThreeJS 中封装了多种光源,例如聚光灯平行光

场景,在 ThreeJS 中创建好物体、光源、相机关键因素后还应将其放进场景当中去。

上手 threejs

接下来我们通过一个 threejs 小的实例 demo,来学习一下 threejs 的几个概念。我们要实现的效果就是绘制一个旋转的三角形,结合上面的概念,我们来写一下我们的第一个 threejs 例子。

实现效果

首先结合 threejs 的几个概念,我们可以思考一下我们要实现这样的效果,需要几个东西。肯定需要渲染器相机物体场景。首先我们先新建 html 文件。

<!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>three-demo</title>
  </head>
  <body>
    <canvas id="three_demo"></canvas>
    <script src="https://cdn.bootcss.com/three.js/r83/three.js"></script>
    <script type="text/javascript" src="./demo_three.js"></script>
  </body>
</html>

这段代码我们仅仅是在页面上创建了一个 canvas 标签。下面我们在 js 文件里面写入。

// 在demo_three.js中写入
window.onload = function() {
  createRotateTriangle()
}

function createRotateTriangle() {
  initRender() // 创建渲染器
  initCamera() // 创建相机
  initObject() // 创建物体
  initSence() // 创建场景
  render() //渲染
}

这段代码也没什么可说的,我觉着要搞清楚 threejs 就是先要把它的几个概念搞清楚之后,然后结合自己的实际,运用一些数学知识达到我们想要的效果。 首先我们先创建一写全局变量。

var renderer //渲染器
var camera //相机
var plane //物体
var width = 400
var height = 400

首先我们需要先创建渲染器,渲染器的作用上面总结过了就是用来绘制出我们想要的场景。接下来我们就写一下initRender函数。

function initRender() {
  var canvas = document.getElementById('three_demo')
  // 定义渲染器  采用WrbGL渲染技术
  renderer = new THREE.WebGLRenderer({
    canvas: canvas,
    antialias: true // 抗锯齿开启
  })
  // 设置背景颜色 黑色,透明度
  renderer.setClearColor(new THREE.Color(0x000000, 1.0))
  // 设置渲染器宽度和高度
  renderer.setSize(400, 400)
}

此处采用的WebGLRenderer的 渲染器,api 贴在这里文档可以读一下。 好了,有了渲染器接下来我们来创建一下相机,相机的作用就是决定了我们观察的视角和位置,接下来我们来看一下initCamera函数。

function initCamera() {
  // 正交投影
  camera = new THREE.OrthographicCamera(
    -width / 2,
    width / 2,
    height / 2,
    -height / 2,
    -1000,
    1000
  )
  camera.position.set(0, 0, 0) //设置相机位置
  camera.lookAt(new THREE.Vector3(0, 0, 1)) // 设置相机视点
}

这段代码我们来看一下,前面提到过threejs中提供了很多相机,此处我们用的就是OrthographicCamera正交相机,这一相机使用正交投影来来进行投影,在这种投影模式下,无论物体距离相机距离远或者近,在最终渲染的图片中物体的大小都保持不变(适用于渲染2D场景或者UI元素)OrthographicCamera的参数分别是OrthographicCamera(left,right,top,bottom,near,far)具体api文档查看这里文档

position.set方法可以设置相机的位置,lookAt用来设置相机的视点,即人眼的焦点。Vector3是一个对象它具有三个属性,这三个属性表示三维空间中的点,也可以表示向量。

当相机创建完成好之后,接下来我们来创建一下物体。物体在threejs中也是一个非常重要的概念,首先我们先来看一下代码。

function initObject() {
  var triangleShape = new THREE.Shape()
  triangleShape.moveTo(0, 100) // 移动到开始位置坐标
  triangleShape.lineTo(-100, -100) // 绘制一条线目标位置坐标
  triangleShape.lineTo(100, -100)
  triangleShape.lineTo(0, 100)
  // ShapeGeometry参数是创建一个
  var geometry = new THREE.ShapeGeometry(triangleShape) // 创建几何体
  // 定义材质(描述对象的外观)
  // 一个以简单着色(平面或线框)方式来绘制几何形状的材料。
  var material = new THREE.MeshBasicMaterial({
    color: 0xff0000, // 材质的颜色
    side: THREE.DoubleSide // 定义了那一边的面将会被渲染,默认值是FromtSide(只渲染正面)DoubleSide表示两面都渲染。
  })
  // 定义网格(物体的类)参数是集合体,材质
  plane = new THREE.Mesh(geometry, material)
  plane.position.set(0, 0, 1)
}

前面已经提到过threejs中实现了多种物体,可以在文档中的Geometries找到相关的例子。我们所需要的就是根据我们自己想要的效果找到所对应的,那么我们来看一下实现绘制一个三角形,三角形是一个平面是一个2d的东西,因此我们在threejs中找一下有没有合适的。我们可以很快的找到Shape这个对象,因此接下来我们来看一下文档,描述也很简单,用来定义2d形状平面,结合官网的demo我们再来看一下这段代码应该会相对好理解一下。我们实例化一个shape对象,接下来moveTolineTo跟canvas绘制的api一样。

当我们定义好形状之后,接下来我们需要去创建一个几何体,在threejs中我们通过ShapeGeometry创建一个多边形几何。参数是一个shape或者一组shape

当我们几何体创建好之后,接下来我们需要给它定义一下材质,也就是我们的物体的外观,在threejs中我们通过MeshBasicMaterial来定义我们物体的外观,此处我们设置了一下材质的颜色与渲染正面和反面两个面都渲染。

最终几何体,和材质构成了我们的物体,所以,接下来通过Mesh来表示物体。接下来调用set设置其位置。

物体也有了,接下来我们需要创建一下场景。

function initSence() {
  scene = new THREE.Scene()
  scene.add(plane)
}

这个就没有什么好解释的了,需要注意的是当我们创建好场景之后,我们需要将我们创建好的物体添加到场景当中去。接下来我们就要调用渲染的方法了,不过在调用之前我们需要创建一个动画。

function animate() {
  var now = Date.now()
  var duration = now - lastTimestamp
  lastTimestamp = now 
  currentAngle = currentAngle + (duration / 1000) * Math.PI
}

接下来执行一下render方法。

function render() {
  animate()
  // 设置渲染角度
  plane.rotation.set(0, 0, currentAngle)
  renderer.render(scene, camera)
  requestAnimationFrame(render)
}

这里就没什么好解释的啦,接下来就可以在页面中看到我们要实现的效果了,需要注意的是这个例子只是非常简单的例子,只是为了给自己能够理清楚threejs的构建流程以及几个重要的概念。其中没有涉及到光源等等概念。在下一个例子中再来搞一下。