在做了一些没有额外库 + 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);
}
我的问题是:为我可以使用的顶点和片段着色器预定义了哪些其他变量(我假设它们是统一的)?例如,ThreeJS 是否可以帮助处理光矢量/光颜色(当然假设我已经在 ThreeJS 场景中添加了一个或多个灯光)?
更新(2014 年 10 月 9 日):这个问题已经获得了相当多的浏览量,用户 Killah 提到现有的答案对于当前版本的 Three.js 来说不再能找到解决方案。我添加并接受了我自己的答案,请参阅下面。
对于制服,简短的回答如下:
在顶点着色器中
"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
。
const vertexGlsl = prefixVertex + vertexShader;
const fragmentGlsl = prefixFragment + fragmentShader;
const glVertexShader = THREE.WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );
const glFragmentShader = THREE.WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );
prefixVertex
和prefixFragment
变量定义可以在WebGLProgram.js
或three.js
的非缩小版本中找到。
编辑:更新到 Three.js r.73
您可以在着色器中使用的制服完全取决于您如何设置材质:是否启用了灯光?顶点颜色 ?剥皮? ...
三个 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的第6463行和6490行(https://github.com/mrdoob/ Three.js/blob/master/src/renderers/WebGLRenderer.js#L6463):您将看到标准制服/ 三个 JS 在着色器中注入的属性。您可以查看 Wiki,其中有相关条目(https://github.com/mrdoob/ Three.js/wiki - 自定义着色器中可以使用哪些默认属性/制服/变量?)引导您到我上面概述的线路。
这个问题的答案现在可以在 Three.js 文档中找到:https://thirdjs.org/docs/#api/renderers/webgl/WebGLProgram
这个问题已经得到了相当多的浏览,用户 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
});
然后,after渲染对象至少一次:
console.log(material.program.attributes);
console.log(material.program.uniforms);
希望这对大家有帮助!如果您知道更多和/或更好的方法来获取着色器代码,请随时添加您的评论。