ThreeJS 预定义着色器属性/制服
Posted
技术标签:
【中文标题】ThreeJS 预定义着色器属性/制服【英文标题】:ThreeJS predefined shader attributes / uniforms 【发布时间】:2013-03-17 19:54:49 【问题描述】:在做了一些“常规”WebGL 之后,我开始使用 ThreeJS 的 WebGL 渲染器,没有额外的库 + GLSL 着色器。我现在正在尝试在我的 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 提到现有的答案不再导致当前版本的解决方案三.js。我添加并接受了我自己的答案,请参见下文。
【问题讨论】:
【参考方案1】:这个问题的答案现在可以在 three.js 文档中找到:https://threejs.org/docs/#api/renderers/webgl/WebGLProgram
【讨论】:
【参考方案2】:对于制服,简短的回答如下:
在顶点着色器中
"uniform mat4 modelMatrix;",
"uniform mat4 modelViewMatrix;",
"uniform mat4 projectionMatrix;",
"uniform mat4 viewMatrix;",
"uniform mat3 normalMatrix;",
"uniform vec3 cameraPosition;",
在片段着色器中
"uniform mat4 viewMatrix;",
"uniform vec3 cameraPosition;",
对于涉及制服和属性的完整答案,您的自定义着色器预先附加了字符串变量 prefixVertex
和 prefixFragment
。
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 );
prefixVertex
和prefixFragment
变量定义可以在WebGLProgram.js
或three.js
的非缩小版本中找到。
编辑:更新到 three.js r.73
【讨论】:
对不起,您(非常有帮助的)答案的最后一部分让我感到困惑。这些变量定义究竟做了什么?你列出了var glVertexShader = new THREE.WebGLShader( _gl, _gl.VERTEX_SHADER, prefix_vertex + vertexShader );
,但我不确定我们什么时候需要这些。【参考方案3】:
这个问题已经获得了相当多的关注,用户 Killah 提到现有的答案在当前版本的 three.js 中不再提供解决方案。 这就是我尝试再次解决问题的原因,我想概述一下我发现的几个选项:
最快和最简单的方法(虽然不是很优雅)是在着色器中放置一个随机错误。整个着色器代码都会出现控制台错误,包括 three.js 添加的所有内容。
更好的解决方案是从编译的地方输出着色器源,即 THREE.WebGLShader(从当前的 three.js 版本开始,r68)。我已经完成了快速复制和粘贴,它应该在编译之前输出所有着色器源。
在包含三个.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;
;
)();
请注意,此 sn-p 只是从 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);
希望对大家有帮助!如果您知道更多和/或更好的方法来获取您的着色器代码,请随意添加您的 cmets。
【讨论】:
【参考方案4】:您可以在着色器中使用的制服都取决于您如何设置材质:您是否启用了灯光?顶点颜色?剥皮? ...
三个 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 - 自定义着色器中可以使用哪些默认属性/制服/变量?)但它会将您引导至我上面概述的行。
【讨论】:
代码的链接已过时,自从给出答案后,行已更改。 @Killah 我将研究并用另一个答案更新这个问题。感谢您的提醒以上是关于ThreeJS 预定义着色器属性/制服的主要内容,如果未能解决你的问题,请参考以下文章
SCNProgram - 如何将“mat4”类型的制服传递给自定义着色器?