WebGL 多个着色器
WebGL multiple Shaders
我已经阅读了关于此问题的先前 Whosebug post,但在使两个不同的着色器集在一个 WebGL 程序中正常工作方面仍然存在问题。
下面是代码的骨架框架。我有两组独立的着色器,具有不同的变量名以防止交叉污染。我创建了两个 initShader() 函数,每组着色器一个,然后调用 initBuffers() 和 draw() 函数。结果是只有第二个着色器生效,并且只显示使用此着色器绘制的项目,尽管着色器在 drawscene() 中被单独识别和调用。
任何有关如何解决此问题的建议都将不胜感激。
Declare: vertexShaderA
Declare: fragmentShaderA
Declare: vertexShaderB (use distinct variable names to that of vertexShaderA)
Declare: fragmentShaderB (use distinct variable names to that of fragmentShaderA)
// main script
initShadersA(){
…
gl.useProgram(shaderProgramA);
…
}
initShadersB(){
…
gl.useProgram(shaderProgramB);
…
}
…
setMatrixUniformsA();
setMatrixUniformsB();
function initBuffers(){
…
}
function drawScene(){
…
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
gl.vertexAttribPointer(shaderProgramA.vertexPositionAttributeA, vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
…
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
gl.uniform1i(shaderProgramA.samplerUniform, 0);
setMatrixUniformsA();
gl.drawElements(gl.TRIANGLES, vertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
…
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
gl.vertexAttribPointer(shaderProgramB.vertexPositionAttributeB, vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
…
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
gl.uniform1i(shaderProgramB.samplerUniform, 0);
setMatrixUniformsB();
gl.drawElements(gl.TRIANGLES, vertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
}
function draw() {
requestAnimFrame(draw);
animate();
drawScene();
}
function animate() {
…
}
function webGLStart() {
initGL(canvas);
initShadersA();
initShadersB();
initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
draw();
}
gl.useProgram(shaderProgram);
基本上表示:"okay, from this moment on, I will use this material to shade objects".
也就是说,您在 webGLStart()
中所做的是:initGL,使用 A material,使用 B material,创建对象,使用当前 material(也就是material B)。
OpenGL/webGL 作为状态机工作。当您尝试渲染某些东西时,它是使用当前设置的状态机参数绘制的。例如,您对 OpenGL 说 draw
,但该方法正在寻找绑定到状态机的缓冲区,它还会寻找当前使用的 material(着色器)...等等。所以您设置一切并启动一些操作。
所以,如果你想用两个不同的着色器渲染两个对象,你应该绑定一个对象(实际上是缓冲区),首先使用 material (gl.useProgram(shaderProgramA)
) 并调度绘制。然后绑定第二个对象,设置第二个 material (gl.useProgram(shaderProgramB)
) 并调度另一个调用。这就是 OpenGL/WebGL 的工作原理。
还有一个建议。尝试以不同的方式命名函数。 initShadersA
应该做一些事情,比如获取源字符串、创建顶点和片段着色器、创建程序和链接所有内容,而像 useShadersA
这样的函数应该将当前 material 设置为确切的着色器程序。
希望对您有所帮助!
我已经阅读了关于此问题的先前 Whosebug post,但在使两个不同的着色器集在一个 WebGL 程序中正常工作方面仍然存在问题。
下面是代码的骨架框架。我有两组独立的着色器,具有不同的变量名以防止交叉污染。我创建了两个 initShader() 函数,每组着色器一个,然后调用 initBuffers() 和 draw() 函数。结果是只有第二个着色器生效,并且只显示使用此着色器绘制的项目,尽管着色器在 drawscene() 中被单独识别和调用。
任何有关如何解决此问题的建议都将不胜感激。
Declare: vertexShaderA
Declare: fragmentShaderA
Declare: vertexShaderB (use distinct variable names to that of vertexShaderA)
Declare: fragmentShaderB (use distinct variable names to that of fragmentShaderA)
// main script
initShadersA(){
…
gl.useProgram(shaderProgramA);
…
}
initShadersB(){
…
gl.useProgram(shaderProgramB);
…
}
…
setMatrixUniformsA();
setMatrixUniformsB();
function initBuffers(){
…
}
function drawScene(){
…
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
gl.vertexAttribPointer(shaderProgramA.vertexPositionAttributeA, vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
…
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
gl.uniform1i(shaderProgramA.samplerUniform, 0);
setMatrixUniformsA();
gl.drawElements(gl.TRIANGLES, vertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
…
gl.bindBuffer(gl.ARRAY_BUFFER, vertexPositionBuffer);
gl.vertexAttribPointer(shaderProgramB.vertexPositionAttributeB, vertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0);
…
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndexBuffer);
gl.uniform1i(shaderProgramB.samplerUniform, 0);
setMatrixUniformsB();
gl.drawElements(gl.TRIANGLES, vertexIndexBuffer.numItems, gl.UNSIGNED_SHORT, 0);
}
function draw() {
requestAnimFrame(draw);
animate();
drawScene();
}
function animate() {
…
}
function webGLStart() {
initGL(canvas);
initShadersA();
initShadersB();
initBuffers();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.enable(gl.DEPTH_TEST);
draw();
}
gl.useProgram(shaderProgram);
基本上表示:"okay, from this moment on, I will use this material to shade objects".
也就是说,您在 webGLStart()
中所做的是:initGL,使用 A material,使用 B material,创建对象,使用当前 material(也就是material B)。
OpenGL/webGL 作为状态机工作。当您尝试渲染某些东西时,它是使用当前设置的状态机参数绘制的。例如,您对 OpenGL 说 draw
,但该方法正在寻找绑定到状态机的缓冲区,它还会寻找当前使用的 material(着色器)...等等。所以您设置一切并启动一些操作。
所以,如果你想用两个不同的着色器渲染两个对象,你应该绑定一个对象(实际上是缓冲区),首先使用 material (gl.useProgram(shaderProgramA)
) 并调度绘制。然后绑定第二个对象,设置第二个 material (gl.useProgram(shaderProgramB)
) 并调度另一个调用。这就是 OpenGL/WebGL 的工作原理。
还有一个建议。尝试以不同的方式命名函数。 initShadersA
应该做一些事情,比如获取源字符串、创建顶点和片段着色器、创建程序和链接所有内容,而像 useShadersA
这样的函数应该将当前 material 设置为确切的着色器程序。
希望对您有所帮助!