着色器材质可以自定义几何体面的颜色。进一步学习后就会知道, three.js 就是对 GLSL 语言进行了多方面的封装,下面我们就使用着色器语言来绘制一个正方体。

绘制一个有着色器材质的几何体

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8" />
    <title>学习</title>
  </head>
    <canvas id="c2d" class="c2d" width="1000" height="500"></canvas>
    <script type="module">
      import * as THREE from './file/three.js-dev/build/three.module.js'
      import { OrbitControls } from './file/three.js-dev/examples/jsm/controls/OrbitControls.js'
      const canvas = document.querySelector('#c2d')
      // 渲染器
      const renderer = new THREE.WebGLRenderer({ canvas })
      const fov = 40 // 视野范围
      const aspect = 2 // 相机默认值 画布的宽高比
      const near = 0.1 // 近平面
      const far = 10000 // 远平面
      // 透视投影相机
      const camera = new THREE.PerspectiveCamera(fov, aspect, near, far)
      camera.position.set(0, 0, 3)
      camera.lookAt(0, 0, 0)
      // 控制相机
      const controls = new OrbitControls(camera, canvas)
      controls.update()
      // 场景
      const scene = new THREE.Scene()
      // 顶点着色器
      const vertexShader = `
      varying vec2 vUv;
      varying vec3 vPosition;
      void main(){
          gl_Position = projectionMatrix*modelViewMatrix*vec4(position,1.0);
          vUv=uv;
          vPosition=position;
      // 片元着色器
      const fragmentShader = `
      uniform float uTime;
      varying vec2 vUv;
      vec3 background(vec2 uv){
          float dist=length(uv-vec2(.5));
          vec3 bg=mix(vec3(.3),vec3(.0),dist);
          return bg;
      void main(){
          vec3 bg=background(vUv);
          vec3 color=bg;
          gl_FragColor=vec4(color,1.);
      const geometry = new THREE.BoxGeometry(1, 1, 1)
      const shaderMaterial = new THREE.ShaderMaterial({
        vertexShader: vertexShader,
        fragmentShader: fragmentShader,
        side: THREE.DoubleSide,
        uniforms: {
          uTime: {
            value: 0
      const mesh = new THREE.Mesh(geometry, shaderMaterial)
      scene.add(mesh)
      // 渲染
      function render() {
        renderer.render(scene, camera)
        requestAnimationFrame(render)
      requestAnimationFrame(render)
    </script>
  </body>
</html>
  1. 顶点着色器中。projectionMatrix是投影变换矩阵,modelViewMatrix是相机坐标系的变换矩阵,position顶点坐标,都是three.js定义好的。
  2. 片元着色器中。通过background函数计算出当前顶点的颜色,交由片元自动计算各个顶点之间的渐变。
  • 这是一个比较复杂的过程。本节只了解如何使用别人写好的公式绘制图形。
  • 下面的操作都是在片元着色器中。
  • 方块的距离函数。
  float sdBox(vec3 p,vec3 b){
      vec3 q=abs(p)-b;
      return length(max(q,0.))+min(max(q.x,max(q.y,q.z)),0.);
  1. 有了方块,就需要一个光线步进函数来展示它。
float rayMarch(vec3 ro,vec3 rd,float end,int maxIter){
  float d0 = 0.;
  for(int i=0;i<maxIter;i++){
      vec3 pos=ro+d0*rd;
      float ds=sdBox(pos,vec3(.3));
      d0+=ds;
      if(ds >= end || ds < 0.01){
          break;
  return d0;
  • 控制片元的颜色,来展示方块。
void main(){
    // 光线位置 位置
    vec3 eye = vec3(0.,0.,2.5);
    // 方向
    vec3 ray = normalize(vec3(vUv,-eye.z));
    // 最大距离
    float end = 5.;
    // 最大步数
    int maxIter=256;
    float depth = rayMarch(eye,ray,end,maxIter);
    if(depth < end){
        vec3 pos = eye + depth * ray;
        color = pos;
  1. 让方块动起来。
  • 开始我们定义了uTime全局变量,通过修改它来实现旋转方块。
  • 矩阵函数。
  mat4 rotationMatrix(vec3 axis,float angle){
      axis=normalize(axis);
      float s=sin(angle);
      float c=cos(angle);
      float oc=1.-c;
      return mat4(oc*axis.x*axis.x+c,oc*axis.x*axis.y-axis.z*s,oc*axis.z*axis.x+axis.y*s,0.,
          oc*axis.x*axis.y+axis.z*s,oc*axis.y*axis.y+c,oc*axis.y*axis.z-axis.x*s,0.,
          oc*axis.z*axis.x-axis.y*s,oc*axis.y*axis.z+axis.x*s,oc*axis.z*axis.z+c,0.,
      0.,0.,0.,1.);
  • 旋转函数。
  vec3 rotate(vec3 v,vec3 axis,float angle){
      mat4 m=rotationMatrix(axis,angle);
      return(m*vec4(v,1.)).xyz;
  • 修改rayMarch函数,在加载方块之前先旋转方块。这里要注意rotate()函数需要在rayMarch()函数之前加载。
float rayMarch(vec3 ro,vec3 rd,float end,int maxIter){
    vec3 pos=ro+d0*rd;
    vec3 p1=rotate(pos,vec3(1.),uTime);
    float ds=sdBox(p1,vec3(.3));
  1. 修改方块的位置。
  • 修改法线为居中法线。
  vec2 centerUv(vec2 uv){
      uv=2.*uv-1.;
      float aspect=1;
      uv.x*=aspect;
      return uv;
  • 修改光线步进的方向。
// 方向 vec2 cUv=centerUv(vUv); vec3 ray=normalize(vec3(cUv,-eye.z)); // vec3 ray = normalize(vec3(vUv,-eye.z));
  • 本节是对GLSL语言的简单应用,通过各种公式使用着色器来绘制立方体。three.js的源码也是在控制着色器,所以想要深入理解three.js就必须要学会如何使用GLSL语言
简介着色器材质可以自定义几何体面的颜色。进一步学习后就会知道,three.js就是对GLSL语言进行了多方面的封装,下面我们就使用着色器语言来绘制一个正方体。开始绘制绘制一个有着色器材质的几何体&lt;!DOCTYPE html&gt;&lt;html lang="en"&gt; &lt;head&gt; &lt;meta charset="UTF-8" /&gt; &lt;title&gt;学习&lt;/title&gt; &lt;/head&gt; &lt;body 使用HTML5和WebGL对Web的3D动画和可视化进行编程 这本书是关于什么的? WebGL使在浏览器中创建3D图形成为可能,而不必使用Flash和Java之类的插件。 但是,对WebGL进行编程既困难又复杂。 使用Three.js,无需学习WebGL,就可以使用JavaScript以直观的方式创建精美的3D图形。 通过这本书,您将学习如何利用WebGL和现代浏览器的全部潜能,直接在浏览器中创建和制作精美的3D场景并为其设置动画。 它从Three.js使用的基本概念和构建块开始。 从那以后,它将使用大量示例和代码示例来扩展这些主题。 您将学习使用材质和纹理从外部创建的模型创建或加载逼真的3D对象。 您将发现如何使用内置在相机控件中的Three.js轻松控制相机,这将使您能够在创建的3D场景中飞行或行走。 然后,您将
Three.js 是一款运行在浏览器中的 3D 引擎,你可以用它创建各种三维场景,包括了摄影机、光影、材质等各种对象。你可以在它的主页上看到许多精彩的演示。不过,这款引擎目前还处在比较不成熟的开发阶段,其不够丰富的 API 以及匮乏的文档增加了初学者的学习难度(尤其是文档的匮乏)three.js的代码托管在github上面。 http://github.com/mrdoob/three.js/ 我们来看实例吧 <!DOCTYPE html> <meta charset="utf-8" /> <title></title> </head>
  1. 首先要创建一个基本图元的距离函数