Three.js中文网 Three.js中文网
首页
免费视频
系统课 (opens new window)
  • Three.js基础课程
  • Vue3+Threejs 3D可视化
  • Threejs进阶课程
  • 展厅3D预览漫游
  • Threejs Shader
  • Blender建模基础
  • Three.js基础课程(旧版本) (opens new window)
  • 文章
WebGPU教程
  • WebGL教程
  • WebGL教程(旧版本) (opens new window)
3D案例
  • 本站部署(打开快) (opens new window)
  • 原英文官网文档 (opens new window)
首页
免费视频
系统课 (opens new window)
  • Three.js基础课程
  • Vue3+Threejs 3D可视化
  • Threejs进阶课程
  • 展厅3D预览漫游
  • Threejs Shader
  • Blender建模基础
  • Three.js基础课程(旧版本) (opens new window)
  • 文章
WebGPU教程
  • WebGL教程
  • WebGL教程(旧版本) (opens new window)
3D案例
  • 本站部署(打开快) (opens new window)
  • 原英文官网文档 (opens new window)
Web3D系统课程视频
  • 1.threejs Shader基础语法

    • 1. 学前说明
    • 2. 着色器GLSL ES语言(复习)
    • 3. ShaderMaterial着色器材质
      • 4. ShaderMaterial半透明、双面显示
      • 5. uniform变量传值
      • 6. WebGL渲染管线
      • 7. 片元屏幕坐标fragCoord.xy
      • 8. 顶点颜色varying插值计算
      • 9. 顶点位置插值(实现渐变色)
      • 10. 颜色贴图map(顶点UV坐标)
      • 11. shader模仿点材质效果
      • 12. attribute自定义顶点变量
    • 2.onBeforeCompile修改材质

    • Threejs Shader教程
    • 1.threejs Shader基础语法
    郭隆邦
    2023-10-23
    目录

    3. ShaderMaterial着色器材质

    # ShaderMaterial着色器材质

    原来给大家介绍过threejs的各种材质,比如MeshBasicMaterial、MeshLambertMaterial...,对于这些材质,你可以通过color、map等属性直接设置物体的外观。

    const material = new THREE.MeshBasicMaterial({
        color: 0x00ffff,//颜色
        map:texture,//颜色贴图
    });
    

    这节课介绍一个特殊的threejs材质,就是Shader材质类ShaderMaterial,单词Shader就是着色器的意思,ShaderMaterial是通过着色器GLSL ES语言 (opens new window)自定义材质效果,比如颜色。

    提醒:如果你图形学或数学的相关基础都不太好,建议本节课的视频和文档内容反复多看几遍。

    # .vertexShader和fragmentShader属性

    • .vertexShader:顶点着色器
    • .fragmentShader:片元着色器

    本节课主要重点学习ShaderMaterial的顶点着色器属性.vertexShader、片元着色器属性.fragmentShader。

    const material = new THREE.ShaderMaterial({
        vertexShader: '着色器代码',// 顶点着色器
        fragmentShader: '着色器代码',// 片元着色器
    });
    

    # 使用Shader材质ShaderMaterial

    打开本节课源码演示文件,你可以看到一个矩形网格模型Mesh,Mesh的材质是基础网格材质MeshBasicMaterial。

    const geometry = new THREE.PlaneGeometry(100, 50);
    const material = new THREE.MeshBasicMaterial({
        color: 0xff0000,
    });
    const mesh = new THREE.Mesh(geometry, material);
    

    使用Shader材质ShaderMaterial代替MeshBasicMaterial,外观效果,可以通过顶点着色器.vertexShader、片元着色器.fragmentShader实现。

    具体替换结果,你可以查看课件案例源码文件,打开测试效果,和演示文件对比下。

    const geometry = new THREE.PlaneGeometry(100, 50);
    const material = new THREE.ShaderMaterial({
        vertexShader: '...',// 顶点着色器
        fragmentShader: '...',// 片元着色器
    });
    const mesh = new THREE.Mesh(geometry, material);
    

    # 设置顶点着色器vertexShader

    ShaderMaterial顶点着色器属性vertexShader的值是字符串,字符串的内容是着色器GLSL ES语言写的代码。关于着色器GLSL ES语言的语法可以参考前面课程1.2. 着色器GLSL ES语言 (opens new window)的介绍。

    const material = new THREE.ShaderMaterial({
        vertexShader: '',// 顶点着色器
    });
    

    为了方便预览顶点着色器代码,咱们用模板字符串``的形式去写,模板字符串``的按键位于键盘Tab键的上面。

    const vertexShader = `
        // 写顶点着色器的代码 
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    # 设置顶点着色器主函数

    先按照着色器GLSL ES语言的语法,给顶点着色器代码设置一个主函数main,函数main无返回值,前面加上关键字void即可。

    const vertexShader = `
    void main(){
        // 写顶点着色器的代码  
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    # 内置变量gl_Position

    gl_Position是着色器GLSL ES语言的内置变量,所谓内置变量,就是不用声明,就可以在代码中使用。

    着色器内置变量gl_Position数据类型是四维向量vec4,可以用函数vec4()创建,vec4()有四个参数,每个参数都是浮点数float

    gl_Position的值,前面三个参数表示xyz坐标,第四个参数一般固定设置为1.0。

    const vertexShader = `
    void main(){
        gl_Position = vec4( x, y ,z ,1.0 );
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    不过一般不会通过gl_Position直接写顶点坐标,而是从几何体BufferGeometry获取顶点坐标数据,下面给大家讲解具体实现方式。

    const vertexShader = `
    void main(){
        gl_Position = vec4(从几何体获取顶点xyz坐标,1.0 );
    }
    `
    

    # 着色器GLSL ES语言语法:attribute关键字

    attribute是着色器GLSL ES语言的一个关键字,按照GLSL ES的语法规定,attribute关键字一般用来声明与顶点数据有关变量。

    attribute vec3 pos;表示用attribute声明了一个变量pos,attribute的作用就是指明pos是顶点相关变量,pos的数类型是三维向量vec3,三维向量vec3意味着pos表示的顶点数据有x、y、z三个分量。比如你可以用pos表示顶点的位置数据xyz(当然也能表示其它类型顶点数据,遇到再讲解)。

    const vertexShader = `
    attribute vec3 pos;//注意在主函数外面
    void main(){
        gl_Position = vec4(...,1.0 );
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    假设attribute声明的变量pos表示顶点位置数据,你就可以赋值给gl_Position。

    执行vec4(pos,1.0 ),给三维向量vec3增加一个分量,就可以变成四维向量vec4(这是GLSL ES基本语法)。

    const vertexShader = `
    attribute vec3 pos;
    void main(){
        gl_Position = vec4(pos,1.0 );
    }
    `
    

    # 知识回顾:几何体geometry的顶点位置数据

    知识回顾:基础课程中讲解过几何体BufferGeometry的顶点知识 (opens new window)

    访问geometry.attributes.position你可以看到几何体所有的顶点位置数据,这些位置数据包含在一个数组中,三个为一组表示一个顶点的x、y、z坐标。这里再强调一遍,threejs默认情况下,几何体的顶点位置数据中的每个顶点都包含x、y、z三个分量。

    const geometry = new THREE.PlaneGeometry(100, 50);
    console.log('顶点位置数据',geometry.attributes.position);
    

    # ShaderMaterial的内置变量position

    调用shader材质ShaderMaterial的时候,threejs会在内部给你写的顶点着色器代码中,插入一行代码attribute vec3 position;,相当于帮你声明了一个变量position,position表示顶点的位置数据

    const vertexShader = `
    attribute vec3 position;//默认提供,不用自己写
    void main(){
        gl_Position = vec4(...,1.0 );
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    # 内置变量position含义

    查看案例代码,可以看到几何体geometry与ShaderMaterial材质构成了一个mesh。也就是说材质ShaderMaterial关联了几何体geometry。

    const geometry = new THREE.PlaneGeometry(100, 50);
    console.log('顶点位置数据',geometry.attributes.position);
    const material = new THREE.ShaderMaterial();
    const mesh = new THREE.Mesh(geometry, material);
    

    当你ShaderMaterial的时候,threejs会在内部把内置变量position与几何体的顶点位置数据geometry.attributes.position关联起来。这意味着,你在顶点着色器代码中访问变量position,就相当于获取了几何体顶点位置数据geometry.attributes.position

    
    const vertexShader = `
    // attribute vec3 position;//默认提供,不用自己写
    void main(){
        gl_Position = vec4(...,1.0 );
    }
    `
    

    总而言之,你可以通过执行代码gl_Position = vec4(position,1.0);,把几何体的顶点位置数据geometry.attributes.position赋值给内置变量gl_Position

    const vertexShader = `
    // attribute vec3 position;//默认提供,不用自己写
    void main(){
        gl_Position = vec4(position,1.0 );
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    # 知识回顾:顶点矩阵变换

    如果你对矩阵变换的知识点完全不了解,可以去看看前面threejs进阶部分关于矩阵 (opens new window)的讲解。

    const vertexShader = `
    void main(){
        // 通过矩阵对顶点坐标进行几何变换(旋转、缩放、平移)
        gl_Position = 矩阵 * vec4(position,1.0 );
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    # 着色器GLSL ES语言语法:uniform关键字

    uniform是着色器GLSL ES语言语言的一个关键字,用来声明非顶点的变量(顶点变量用atribute声明),比如模型的矩阵、光源位置等等。

    执行uniform mat4 mT;意味着,你通过关键字uniform声明一个变量mT,变量mT的数据类型是mat4(4x4的矩阵)。

    const vertexShader = `
    uniform mat4 mT;
    void main(){
        gl_Position = mT * vec4(position,1.0 );
    }
    `
    

    假设mT是一个平移矩阵,mT * vec4(position,1.0 )就可以平移几何体的顶点位置position。

    # 知识点回顾:世界矩阵.matrixWorld

    当网格模型mesh自身或父对象平移、旋转、缩放时候,会改变自身的世界矩阵属性mesh.matrixWorld,换句话说,就是threejs内部会用世界矩阵.matrixWorld记录mesh的位置、尺寸和姿态角度变化。

    const mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(100,0,0);//平移改变位置
    mesh.scale.set(3,3,3,);//缩放改变尺寸
    mesh.rotateY(Math.PI / 2);//旋转改变姿态角度
    

    关于模型世界矩阵mesh.matrixWorld更多内容可以参考前面课程5.5 模型本地矩阵、世界矩阵 (opens new window)

    # 内置变量模型矩阵modelMatrix

    调用shader材质ShaderMaterial的时候,threejs会在内部给你写的顶点着色器代码中,插入一行代码uniform mat4 modelMatrix;,这意味着帮你声明了一个变量modelMatrix,modelMatrix在这里表示4x4的模型矩阵mat4。

    const vertexShader = `
    uniform mat4 modelMatrix;//默认提供,不用自己写
    void main(){
        gl_Position = vec4(...,1.0 );
    }
    `
    

    使用ShaderMaterial的时候,threejs会自动获取模型世界矩阵mesh.matrixWorld的值,赋值给变量modelMatrix。这意味着,模型矩阵modelMatrix包含了模型自身的位置、缩放、姿态角度信息。

    你当平移、旋转、缩放mesh时候,会改变mesh的世界矩阵属性.matrixWorld,自然同步改变顶点着色器的模型矩阵modelMatrix变量。

    const mesh = new THREE.Mesh(geometry, material);
    mesh.position.set(100,0,0);
    mesh.rotateY(Math.PI / 2);
    

    在顶点着色器代码中,你可以直接使用modelMatrix对几何体顶点位置坐标进行旋转、缩放、平移。

    const vertexShader = `
    // uniform mat4 modelMatrix;//默认提供,不用自己写
    void main(){
        // 模型矩阵 * 顶点坐标
        gl_Position = modelMatrix * vec4(position,1.0 );
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
    });
    

    # 知识回顾:视图矩阵和投影矩阵

    通过基础课程的学习大家都知道,当你改变相机的参数的时候,场景中模型Mesh渲染位置、尺寸、角度可能会发生变化。其实原因很简单,threejs内部会把相机的参数生成矩阵,对模型的顶点进行矩阵变换。

    const width = window.innerWidth;
    const height = window.innerHeight;
    const camera = new THREE.PerspectiveCamera(30, width / height, 1, 3000);
    camera.position.set(292, 223, 185);
    camera.lookAt(0, 0, 0);
    

    前面进阶课程5.6. 视图矩阵、投影矩阵 (opens new window),给大家介绍过,threejs会读取相机的参数生成两个矩阵,也就是视图矩阵camera.matrixWorldInverse和投影矩阵camera.projectionMatrix。

    # 内置变量:视图矩阵viewMatrix和投影矩阵projectionMatrix

    刚才给大家介绍过ShaderMaterial的一个内置变量是模型矩阵modelMatrix。

    const vertexShader = `
    uniform mat4 modelMatrix;//默认提供,不用自己写
    void main(){
        gl_Position = modelMatrix * vec4(position,1.0 );
    }
    `
    

    使用ShaderMaterial的时候,除了内置变量模型矩阵modelMatrix,threejs内部还提供了两个内置的矩阵变量,这两个内置变量分别是相机的视图矩阵viewMatrix、投影矩阵projectionMatrix。viewMatrix的值来自相机视图矩阵属性camera.matrixWorldInverse,projectionMatrix的值来自相机的投影矩阵属性camera.projectionMatrix。

    视图矩阵viewMatrix和投影矩阵projectionMatrix因为是内置变量,同样不用声明你就可以直接使用。

    const vertexShader = `
    uniform mat4 modelMatrix;//默认提供,不用自己写
    uniform mat4 viewMatrix;//默认提供,不用自己写
    uniform mat4 projectionMatrix;//默认提供,不用自己写
    void main(){
        // 投影矩阵 * 视图矩阵 * 模型矩阵 * 顶点坐标
        // 注意矩阵乘法前后顺序不要写错
        gl_Position = projectionMatrix * viewMatrix * modelMatrix * vec4(position,1.0 );
    }
    `
    

    通过viewMatrix和projectionMatrix来表示相机对场景模型的旋转、缩放、平移变换。

    # 设置片元着色器代码fragmentShader

    fragmentShader表示ShaderMaterial的片元着色器属性。

    // 片元着色器代码
    const fragmentShader = `
    void main() {
        ...
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
        fragmentShader: fragmentShader,// 片元着色器
    });
    

    gl_FragColor和gl_Position一样是着色器GLSL ES语言的内置变量,不用声明,就可以在代码中使用。

    你可以通过gl_FragColor设置ShaderMaterial相关模型的颜色值。

    着色器内置变量gl_FragColor数据类型是四维向量vec4,可以用函数vec4()创建,vec4()有四个参数,每个参数都是浮点数float

    gl_FragColor的值,前面三个参数表示像素的RGB值,第四个参数表示透明度,不透明就是1.0。

    // 片元着色器代码
    const fragmentShader = `
    void main() {
        // RGB 0.0,1.0,1.0对应16进制颜色是0x00ffff
        gl_FragColor = vec4(0.0,1.0,1.0,1.0);
    }
    `
    const material = new THREE.ShaderMaterial({
        vertexShader: vertexShader,// 顶点着色器
        fragmentShader: fragmentShader,// 片元着色器
    });
    

    # 体验测试

    你可以平移网格模型mesh.position.x = 100;,然后比较下顶点着色器使用modelMatrix和不使用modelMatrix的差异。

    你可以发现modelMatrix包含了你的平移变换mesh.position.x = 100;。

    // 投影矩阵 * 视图矩阵 * 模型矩阵 * 模型顶点坐标
    gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4( position, 1.0 );
    
    mesh.position.x = 100;
    

    改变模型的颜色值

    // 青色
    gl_FragColor = vec4(0.0,1.0,1.0,1.0);
    // 红色
    gl_FragColor = vec4(1.0,0.0,0.0,1.0);
    

    # 内置变量:模型视图矩阵

    ShaderMaterial还提供了一个内置变量模型视图矩阵modelViewMatrix,就是视图矩阵viewMatrix和模型矩阵modelMatrix的乘积。

    const vertexShader = `
    //模型视图矩阵
    uniform mat4 modelViewMatrix;//默认提供,不用自己写
    void main(){
        // 投影矩阵 * 模型视图矩阵 * 模型顶点坐标
        gl_Position = projectionMatrix*modelViewMatrix*vec4( position, 1.0 );
    }
    `
    

    你可以把上面代码viewMatrix*modelMatrix简化为modelViewMatrix。

    // 投影矩阵 * 视图矩阵 * 模型矩阵 * 模型顶点坐标
    gl_Position = projectionMatrix*viewMatrix*modelMatrix*vec4( position, 1.0 );
    
    // 投影矩阵 * 模型视图矩阵 * 模型顶点坐标
    gl_Position = projectionMatrix*modelViewMatrix*vec4( position, 1.0 );
    
    2. 着色器GLSL ES语言(复习)
    4. ShaderMaterial半透明、双面显示

    ← 2. 着色器GLSL ES语言(复习) 4. ShaderMaterial半透明、双面显示→

    Theme by Vdoing | Copyright © 2016-2025 豫ICP备16004767号-2
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式