我做了一些“常规”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所。我添加并接受了我自己的答案,见下文。
答案 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;",
有关制服和属性的完整答案,您的自定义着色器会预先附加字符串变量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
答案 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