ThreeJS预定义着色器属性/制服

时间:2013-03-27 16:17:43

标签: three.js glsl shader

我做了一些“常规”WebGL而没有额外的库+ GLSL着色器后,开始使用ThreeJS的WebGL渲染器。我正在尝试在我的ThreeJS程序中编写自定义着色器,我注意到ThreeJS负责很多标准的东西,比如投影和模型/视图矩阵。我的简单顶点着色器现在看起来像这样:

// All of these seem to be predefined:
// vec3 position;
// mat4 projectionMatrix;
// mat4 modelViewMatrix;
// mat3 normalMatrix;
// vec3 normal;

// I added this
varying vec3 vNormal;

void main() {
    vNormal = normalMatrix * vec3(normal);
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

我的问题是:我可以使用哪些其他变量(我假设它们是制服)是为顶点和片段着色器预定义的?例如ThreeJS是否提供光矢量/浅色(当然假设我已经为我的ThreeJS场景添加了一个或多个灯光)?

更新(2014年10月9日):这个问题已经得到了不少观点,用户Killah提到现有的答案不再导致当前版本的解决方案three.js所。我添加并接受了我自己的答案,见下文。

4 个答案:

答案 0 :(得分:21)

对于制服,简短的回答是:

在顶点着色器中

"uniform mat4 modelMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",

并在片段着色器中

"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",

有关制服和属性的完整答案,您的自定义着色器会预先附加字符串变量prefixVertexprefixFragment

var vertexGlsl = prefixVertex + vertexShader;
var fragmentGlsl = prefixFragment + fragmentShader;

var glVertexShader = THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
var glFragmentShader = THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );

可以在prefixVertexprefixFragment的非缩小版本中找到WebGLProgram.jsthree.js变量定义。

编辑:更新为three.js r.73

答案 1 :(得分:11)

您可以在着色器中使用的制服全部取决于您设置材料的方式:您是否启用了灯光?顶点颜色?剥皮? ...

三个JS创建的程序严重依赖于程序顶部注入的某些定义(代码中的#ifdef),具体取决于我上面提到的参数。

我发现知道发生了什么的最好方法是打印三个JS生成的着色器:正如您已经了解GLSL,您将很容易理解代码的含义以及您可以使用的制服。在三个JS源中查找buildProgram,然后(r57):

var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );

在这些行之后,添加:

console.log("fragment shader:", prefix_fragment + fragmentShader);
console.log("vertex shader:", prefix_vertex + vertexShader);

您将能够看到着色器的内容。

[编辑] 重读你的问题,我意识到我回答了一些问题,因为你创建了自己的着色器......

您可以查看WebGLRenderer(https://github.com/mrdoob/three.js/blob/master/src/renderers/WebGLRenderer.js#L6463)的第6463和6490行:您将看到三个JS在着色器中注入的标准制服/属性。您可以查看Wiki中有关于该条目的条目(https://github.com/mrdoob/three.js/wiki - 自定义着色器中有哪些默认属性/制服/变换?)但它会引导您进入上面概述的行。

答案 2 :(得分:4)

这个问题已经得到了不少观点,用户Killah提到现有的答案不再导致当前版本的three.js的解决方案。 这就是我尝试再次解决问题的原因,并且我想概述一些我发现的选项:

  • 最简单快捷的方法(虽然不是很优雅)只是在着色器中添加一个随机错误。您将收到整个着色器代码的控制台错误,包括three.js添加的所有内容。

  • 更好的解决方案是从编译的位置输出着色器源,即THREE.WebGLShader(截至当前的three.js版本,r68)。我已经完成了快速复制和粘贴,应该在编译之前输出所有着色器源。

    在包含three.js之后和您自己的代码之前添加此内容:

    THREE.WebGLShader = ( function () {
        var addLineNumbers = function ( string ) {
            var lines = string.split( '\n' );
            for ( var i = 0; i < lines.length; i ++ ) {
                lines[ i ] = ( i + 1 ) + ': ' + lines[ i ];
            }
            return lines.join( '\n' );
        };
        return function ( gl, type, string ) {
            var shader = gl.createShader( type ); 
            console.log(string);
            gl.shaderSource( shader, string );
            gl.compileShader( shader );
            if ( gl.getShaderParameter( shader, gl.COMPILE_STATUS ) === false ) {
                console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
            }
            if ( gl.getShaderInfoLog( shader ) !== '' ) {
                console.warn( 'THREE.WebGLShader: gl.getShaderInfoLog()', gl.getShaderInfoLog( shader ) );
                console.warn( addLineNumbers( string ) );
            }
            return shader;
        };
    } )();
    

    请注意,此片段只是从three.js源复制(并且稍有更改),应在实际使用代码之前删除。只是为了调试!

  • 还有一个更具侵入性的选项:您可以在创建并至少渲染一次之后检查ShaderMaterial,如下所示:

    var material = new THREE.ShaderMaterial({
        uniforms: {
            uColorMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_colors.png') },
            uSpecularMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_spec.png') }, 
            uNormalMap: { type: 't', value: THREE.ImageUtils.loadTexture('./img/_normal.png') }
        },
        vertexShader: document.getElementById('vShader').innerText,
        fragmentShader: document.getElementById('fShader').innerText
    });
    

    然后,渲染对象后至少一次:

    console.log(material.program.attributes);
    console.log(material.program.uniforms);
    

希望这有助于每个人!如果您了解更多和/或更好的方式来获取着色器代码,请随时添加您的评论。

答案 3 :(得分:2)

现在可以在three.js文档中找到这个问题的答案:https://threejs.org/docs/#api/renderers/webgl/WebGLProgram