自定义着色器程序

  自定义three.js着色器程序需要用到着色器语言GLSL ES和相关的WebGL API,因此在学习本节课之前最好具有一定WebGL基础。

  着色器程序至少包含顶点着色器程序和片元着色器程序,对于原生WebGL应用而言,使用着色器语言GLSL编写好顶点、片元着色器程序后, 需要借助WebGL相关API进行编译处理后发送到GPU渲染管线的顶点、片元着色器单元执行,three.js引擎提供了一个接口着色器材质对象ShaderMaterial, 通过ShaderMaterial对象的属性vertexShader和fragmentShader用来接收着色器程序,着色器程序如何编译、如何传递给GPU的处理单元,这些过程已经被three.js引擎封装, three.js通过ShaderMaterial对象接收到着色器程序后会自动化为处理,说到这里大家可以看出three.js引擎的好处与作用,对WebGL API和着色器语言进行封装,一方面是降低Web3D的学习成本, 另一方面是对原生的WebGL程序进行封装,工程师更多的精力放在应用开发上。

  下面的代码完整的展示了如何利用ShaderMaterial对象加载着色器程序,如何把顶点相关的数据传输到顶点着色器程序中。

<body>
    <!--顶点着色器程序-->
    <script type="x-shader/x-vertex" id="vertexshader">
            void main() {

                gl_PointSize = 20.0;
                gl_Position = vec4( position, 1.0 );

            }
    </script>

    <!--片元着色器程序-->
    <script type="x-shader/x-fragment" id="fragmentshader">
            void main() {

                gl_FragColor = vec4(1.0,0.0,0.0,1.0);

            }
    </script>

    <script>

    ...
    ...

    /**
     * 创建模型对象
     */
    //类型数组创建顶点数据
    var vertices = new Float32Array([
        0.5,  0.5,  0.5,//顶点0
        -0.5,  0.5,  0.5,//顶点1
        -0.5, -0.5,  0.5,//顶点2
        0.5, -0.5,  0.5,//顶点3
    ]);
    //类型数组格式顶点数据转为BufferAttribute对象
    var verticesPosition = new THREE.BufferAttribute( vertices, 3 );
    var geometry = new THREE.BufferGeometry();//缓冲几何对象
    //顶点数据关联着色器程序
    geometry.addAttribute('position',verticesPosition);
    var material=new THREE.ShaderMaterial({

        //加载顶点着色器程序
        vertexShader:   document.getElementById( 'vertexshader' ).textContent,

        //加载片元着色器程序
        fragmentShader: document.getElementById( 'fragmentshader' ).textContent,

    });//着色器材质对象
    var points=new THREE.Points(geometry,material);//模型对象
    scene.add(points);//模型添加到场景中
    
    ...
    ...

    </script>

</body>

加载着色器程序

  ShaderMaterial对象的基类是材质对象MAterial,ShaderMaterial对象除了具有材质对象的属性和方法以外,与其它材质对象不同的是ShaderMaterial对象还具有处理着色器程序的相关属性或方法, 或者换句话说其它的各种材质对象对着色器程序进行了封装,three.js引擎会把材质对象的颜色属性、纹理贴图属性转化为着色器程序中的代码。

  vertexShader、fragmentShader是着色器材质对象ShaderMaterial属性,属性值是字符串格式着色器程序,着色器程序可以编写在任何html标签中,通过getElementById获取标签表示的元素对象, textContent属性返回的是标签里面的着色器程序,数据类型是字符串。下面代码是以构造函数THREE.ShaderMaterial参数的形式把顶点和片元着色器程序分别赋值给vertexShader属性、fragmentShader属性。

    var material=new THREE.ShaderMaterial({

        //加载顶点着色器程序
        vertexShader:   document.getElementById( 'vertexshader' ).textContent,

        //加载片元着色器程序
        fragmentShader: document.getElementById( 'fragmentshader' ).textContent,

    });//着色器材质对象

传入着色器顶点相关数据

  所谓的三维模型效果本质上都是通过顶点数据渲染出来,通过原生WebGL编写三维应用,需要在着色器通过attribute等关键字声明一个变量, 然后通过Javascript可以控制的WebGL API把顶点数据传递给着色器,关联到该变量。three.js对这些代码进行了封装,对于工程师来说更加友好易用。

BufferGeometry

  缓冲几何体对象BufferGeometry和几何体对象Geometry功能基本相似,都可使用来创建几何体,只是处理数据的方式有些差异。 比如Geometry对象具有顶点位置属性vertices、顶点颜色属性colors,而BufferGeometry对象不具有这些属性, BufferGeometry对象的顶点位置、颜色等数据需要通过方法.addAttribute()添加。

BufferAttribute

  通过类型数组构造函数Float32Array创建一系列的顶点数据,这些数据可以作为顶点位置、颜色、法向量顶数据,代码中是作为位置使用, THREE.BufferAttribute( vertices, 3 )的含义表示类型数组的元素三个是一组,表示一个顶点的位置,相当于Vector3向量。 对象BufferAttribute可以作为BufferGeometry对象addAttribute方法的参数,实现顶点位置数据与顶点着色器程序中的位置变量块关联。

addAttribute

  geometry.addAttribute('position',verticesPosition);代码的作用相当于在顶点着色器中创建代码“attribute vec4 position”, 然后把包含顶点数据的BufferAttribute对象与着色器程序中的position变量进行关联。直接使用WebGL API编写程序, 需要在着色器程序中编写代码“attribute vec4 position”,有了three.js引擎自然不要,在执行方法.addAttribute('position')的时候, 就相当于在着色器程序中添加了该语句。

//类型数组创建顶点数据
    var vertices = new Float32Array([
        0.5,  0.5,  0.5,//顶点0
        -0.5,  0.5,  0.5,//顶点1
        -0.5, -0.5,  0.5,//顶点2
        0.5, -0.5,  0.5,//顶点3
    ]);
    //类型数组格式顶点数据转为BufferAttribute对象
    var verticesPosition = new THREE.BufferAttribute( vertices, 3 );
    var geometry = new THREE.BufferGeometry();//缓冲几何对象
    //顶点数据关联着色器程序
    geometry.addAttribute('position',verticesPosition);