9.3 着色器完整实例

着色器程序的位置


着色器代码可以写在单独的文件中(顶点着色器的文件名后缀为.vs,片元着色器的文件名后缀为.fs),也可以在HTML文件中定义script标签实现。通常对于较长的着色器代码,建议使用单独的文件;对于较短的着色器代码,在HTML文件中定义也是一个不错的选择。当然,从代码可维护性的角度看,本书更建议使用单独的着色器文件。

单独的着色器文件

使用单独的着色器文件,需要在javascript代码中导入着色器文件。我们假设顶点着色器定义在shader/my.vs文件中,片元着色器定义在shader/my.fs中。

可以使用Ajax完成导入文件的工作,而如果使用jQueryget函数就可以更方便地实现。

// load shader
$.get('shader/my.vs', function(vShader){
    $.get('shader/my.fs', function(fShader){
        // TODO
    });
});

jQuery的get函数第一个参数为文件路径,第二个参数为导入文件后的回调函数,这里我们在加载完顶点着色器后加载片元着色器。vShaderfShader分别为导入的着色器程序,用来构造着色器材质。

接下来,我们需要在加载完两个着色器后,新建一个THREE.ShaderMaterial,需要传入属性vertexShaderfragmentShader

$.get('shader/my.vs', function(vShader){
    $.get('shader/my.fs', function(fShader){
        material = new THREE.ShaderMaterial({
            vertexShader: vShader,
            fragementShader: fShader
        });
    });
});

之后可以将material应用于需要该着色器效果的物体上。

HTML中的着色器代码

在HTML中,可以使用

<script id="vs" type="x-shader/x-vertex">
    这里的内容相当于.vs文件中的内容
</script>

定义顶点着色器;使用

<script id="fs" type="x-shader/x-fragment">
   这里的内容相当于.fs文件中的内容
</script>

定义片元着色器。

定义材质时的方法:

material = new THREE.ShaderMaterial({
    vertexShader: document.getElementById('vs').textContent,
    fragmentShader: document.getElementById('fs').textContent
});

完整实例


下面,我们通过完整的例子了解着色器的应用。

例9.3.1例9.3.2

首先,我们创建一个绿色的正方体在场景中旋转,这些都是在前几章中讲解过的:

var scene = null;
var camera = null;
var renderer = null;
var cube = null;

function init() {
    renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById('mainCanvas')
    });
    scene = new THREE.Scene();

    camera = new THREE.OrthographicCamera(-5, 5, 3.75, -3.75, 0.1, 100);
    camera.position.set(5, 15, 25);
    camera.lookAt(new THREE.Vector3(0, 0, 0));
    scene.add(camera);

    var light = new THREE.DirectionalLight();
    light.position.set(3, 2, 5);
    scene.add(light);

    cube = new THREE.Mesh(new THREE.CubeGeometry(2, 2, 2),
            new THREE.MeshLambertMaterial({color: 0x00ff00}));
    scene.add(cube);

    draw();
}

function draw() {
    cube.rotation.y += 0.01;
    if (cube.rotation.y > Math.PI * 2) {
        cube.rotation.y -= Math.PI * 2;
    }

    renderer.render(scene, camera);

    requestAnimationFrame(draw);
}

然后,我们需要定义着色器代码,并导入到应用中。着色器程序参见上节,导入着色器的两种方法在本节也做了介绍。因此,最终得到的结果是: