【问题标题】:three.js - passing vertex colors to fragment shaderthree.js - 将顶点颜色传递给片段着色器
【发布时间】:2014-11-02 14:31:23
【问题描述】:

我在 three.js 中搜索了从简单到复杂的着色器示例,但似乎找不到将顶点保持的颜色传递给片段着色器的简单示例。我做了一个简单的例子,其中顶点着色器只将顶点留在它们所在的位置,但也通过“vColor”变化将“颜色”统一(我想我在某处看到但尚未使用)传递给片段着色器,然后在片段着色器中,我试图返回相同的颜色。浏览器将三角形渲染为黑色,我猜颜色是空的。我知道这很简单,但我自己无法弄清楚,我无法弄清楚 ShaderMaterial 将什么传递给我可以在那里玩的着色器。有人可以解释一下吗?

代码如下:

<script id="vertexShader" type="x-shader/x-vertex">
    uniform vec3 color;

    varying vec3 vColor;

    void main(){
        vColor = color;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
</script>

<script id="fragmentShader" type="x-shader/x-fragment">
    varying vec3 vColor;

    void main(){
        gl_FragColor = vec4( vColor.rgb, 1.0 );
    }
</script>
<script>
    var container,
        camera,
        controls,
        scene,
        renderer,
        model;

    init();
    animate();

    function init() {
        camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
        camera.position.y = 150;
        camera.position.z = 500;

        scene = new THREE.Scene();

        var geometry = new THREE.Geometry();
        geometry.vertices.push(
            new THREE.Vector3(0, 0, 0),
            new THREE.Vector3(-120, -200, 0),
            new THREE.Vector3(120, -200, 0));

        geometry.faces.push(new THREE.Face3(0, 1, 2));

        geometry.faces[0].vertexColors[0] = new THREE.Color("rgb(255,0,0)");
        geometry.faces[0].vertexColors[1] = new THREE.Color("rgb(0,255,0)");
        geometry.faces[0].vertexColors[2] = new THREE.Color("rgb(0,0,255)");

        var materialShader = new THREE.ShaderMaterial({
            vertexShader: document.getElementById('vertexShader').textContent,
            fragmentShader: document.getElementById('fragmentShader').textContent
        });

        var materialBasic = new THREE.LineBasicMaterial({
            vertexColors: THREE.VertexColors,
            linewidth: 1
        });

        var model = new THREE.Mesh(geometry, materialShader);
        model.position.y = 150;
        scene.add(model);

        renderer = new THREE.WebGLRenderer();
        renderer.setClearColor(0xf0f0f0);
        renderer.setSize(window.innerWidth, window.innerHeight);

        container = document.createElement('div');
        document.body.appendChild(container);
        container.appendChild(renderer.domElement);
        window.addEventListener('resize', onWindowResize, false);
    }

    function onWindowResize() {
        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);
    }

    function animate() {
        requestAnimationFrame(animate);
        render();
    }

    function render() {
        renderer.render(scene, camera);
    }

</script>

请注意,我有两种类型的材料用于测试 - 用于着色器的 materialShader 和作为可正常工作的控制材料的 materialBasic。我没有足够的声誉来发布图片,但如果堆栈溢出继续上传图片,你应该在这里看到渲染的例子:http://i.stack.imgur.com/tjdSt.png

【问题讨论】:

    标签: three.js


    【解决方案1】:

    我通过玩弄变量解决了这个问题。我犯的第一个错误是认为顶点着色器代码中的颜色(统一 vec3 颜色;)是统一的,但它实际上是一个 attribute 。其次,我不必定义它,它已经定义了,我在收到顶点着色器的堆栈跟踪时发现了这一点,并且我弄清楚了最终着色器 GLSL 代码是如何构建的:

    1: precision highp float;
    2: precision highp int;
    3: 
    4: #define VERTEX_TEXTURES
    5: 
    6: 
    7: #define MAX_DIR_LIGHTS 0
    8: #define MAX_POINT_LIGHTS 0
    9: #define MAX_SPOT_LIGHTS 0
    10: #define MAX_HEMI_LIGHTS 0
    11: #define MAX_SHADOWS 0
    12: #define MAX_BONES 58
    13: 
          //a lot of blank space was printed in here, i skipped the lines
    33: 
    34: uniform mat4 modelMatrix;
    35: uniform mat4 modelViewMatrix;
    36: uniform mat4 projectionMatrix;
    37: uniform mat4 viewMatrix;
    38: uniform mat3 normalMatrix;
    39: uniform vec3 cameraPosition;
    40: attribute vec3 position;
    41: attribute vec3 normal;
    42: attribute vec2 uv;
    43: attribute vec2 uv2;
    44: #ifdef USE_COLOR
    45:     attribute vec3 color;
    46: #endif
    47: #ifdef USE_MORPHTARGETS
    48:     attribute vec3 morphTarget0;
    49:     attribute vec3 morphTarget1;
    50:     attribute vec3 morphTarget2;
    51:     attribute vec3 morphTarget3;
    52:     #ifdef USE_MORPHNORMALS
    53:         attribute vec3 morphNormal0;
    54:         attribute vec3 morphNormal1;
    55:         attribute vec3 morphNormal2;
    56:         attribute vec3 morphNormal3;
    57:     #else
    58:         attribute vec3 morphTarget4;
    59:         attribute vec3 morphTarget5;
    60:         attribute vec3 morphTarget6;
    61:         attribute vec3 morphTarget7;
    62:     #endif
    63: #endif
    64: #ifdef USE_SKINNING
    65:     attribute vec4 skinIndex;
    66:     attribute vec4 skinWeight;
    67: #endif
    68: 
    69:         
    70: 
    71:         varying vec3 vColor;
    72: 
    73:         void main(){
    74:             vColor = color;
    75:             gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    76:         }
    77:      
    

    这意味着我不必定义颜色属性。此外,这可以在 Three.js 文件中看到,但它是一个串联的字符串,因此很难阅读。

    我需要做的最后一件事是在 ShaderMaterial 中定义 vertexColors: THREE.VertexColors,就像在 LineBasicMaterial 中一样,我偶然发现了这一点(以“让我们看看会发生什么”的方式)。

    这是最终的有效代码:

    <script id="vertexShader" type="x-shader/x-vertex">
    
    
        varying vec3 vColor;
    
        void main(){
            vColor = color;
            gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
        }
    </script>
    
    <script id="fragmentShader" type="x-shader/x-fragment">
        varying vec3 vColor;
    
        void main(){
            gl_FragColor = vec4( vColor.rgb, 1.0 );
        }
    </script>
    <script>
        var container,
            camera,
            controls,
            scene,
            renderer,
            model;
    
        init();
        animate();
    
        function init() {
            camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 1, 10000);
            camera.position.y = 150;
            camera.position.z = 500;
    
            scene = new THREE.Scene();
    
            var geometry  = new THREE.Geometry();
            geometry.vertices.push(
                new THREE.Vector3(0, 0, 0),
                new THREE.Vector3(-120, -200, 0),
                new THREE.Vector3(120, -200, 0));
    
            geometry.faces.push(new THREE.Face3(0, 1, 2));
    
            geometry.faces[0].vertexColors[0] = new THREE.Color("rgb(255,0,0)");
            geometry.faces[0].vertexColors[1] = new THREE.Color("rgb(0,255,0)");
            geometry.faces[0].vertexColors[2] = new THREE.Color("rgb(0,0,255)");
    
            var materialShader = new THREE.ShaderMaterial({
                vertexShader: document.getElementById('vertexShader').textContent,
                vertexColors: THREE.VertexColors,
                fragmentShader: document.getElementById('fragmentShader').textContent
            });
    
            var materialBasic = new THREE.LineBasicMaterial({
                vertexColors: THREE.VertexColors,
                linewidth: 1
            });
    
            var model = new THREE.Mesh(geometry, materialShader);
            model.position.y = 150;
            scene.add(model);
    
            renderer = new THREE.WebGLRenderer();
            renderer.setClearColor(0xf0f0f0);
            renderer.setSize(window.innerWidth, window.innerHeight);
    
            container = document.createElement('div');
            document.body.appendChild(container);
            container.appendChild(renderer.domElement);
            window.addEventListener('resize', onWindowResize, false);
        }
    
        function onWindowResize() {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
    
            renderer.setSize(window.innerWidth, window.innerHeight);
        }
    
        function animate() {
            requestAnimationFrame(animate);
            render();
        }
    
        function render() {
            renderer.render(scene, camera);
        }
    
    </script>
    

    我希望这将有助于其他人理解着色器中的变量。干杯。

    【讨论】:

    • 还有一件事,在堆栈跟踪中,您可以看到以下行:#ifdef USE_COLOR,然后定义颜色attribute vec3 color;。我猜这只有在您在材料中添加vertexColors: THREE.VertexColors 时才有可能,我只是在猜测,因为我不知道如何复制堆栈跟踪。
    • 属性vertexColors应该设置为true(见:threejs.org/docs/#api/en/materials/ShaderMaterial
    【解决方案2】:

    您可以使用 THREEjs 着色器块来实现相同的结果,而几乎不需要任何工作。

    只需在您的顶点着色器中添加#include &lt;color_vertex&gt;,它将为您的片段着色器提供varying vec3 vColor

    这是添加到您的垂直着色器的内容:

    #ifdef USE_COLOR
        varying vec3 vColor;
    #endif
    

    【讨论】:

    • 依赖 Three.js 自己的 glsl 生态系统是一个不错的建议。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-20
    • 2014-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多