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

Grü*_*üse 24 shader glsl three.js

在完成一些没有额外库+ GLSL着色器的"常规"WebGL之后,我开始使用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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

Wes*_*ley 23

对于制服,简短的回答如下:

在顶点着色器中

"uniform mat4 modelMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",
Run Code Online (Sandbox Code Playgroud)

并在片段着色器中

"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",
Run Code Online (Sandbox Code Playgroud)

对于包含制服和属性的完整答案,您的自定义着色器具有字符串变量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 );
Run Code Online (Sandbox Code Playgroud)

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

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


Pop*_*pov 11

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

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

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

var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader );
var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader );
Run Code Online (Sandbox Code Playgroud)

在这些行之后,添加:

console.log("fragment shader:", prefix_fragment + fragmentShader);
console.log("vertex shader:", prefix_vertex + vertexShader);
Run Code Online (Sandbox Code Playgroud)

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

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

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


Grü*_*üse 5

这个问题已经获得了相当多的意见,用户 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;
        };
    } )();
    
    Run Code Online (Sandbox Code Playgroud)

    请注意,此代码段只是从 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
    });
    
    Run Code Online (Sandbox Code Playgroud)

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

    console.log(material.program.attributes);
    console.log(material.program.uniforms);
    
    Run Code Online (Sandbox Code Playgroud)

希望这对大家有帮助!如果您了解更多和/或更好的获取着色器代码的方法,请随时添加您的评论。


Kal*_*sen 5

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