2015-03-30 139 views
1

我已经阅读了有关此问题的以前的一篇StackOverflow文章,并且仍然在让两个不同的着色器集合在一个WebGL程序中正常工作时遇到问题。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(); 
    } 
+0

[您可能会发现这有帮助](http://webglfundamentals.org/webgl/lessons/webgl-drawing-multiple-things.html)? – gman 2015-03-31 05:14:53

回答

5

gl.useProgram(shaderProgram);基本上说:“好,从这一刻起,我就用这种材料遮阳对象”。

这就是说,你正在做的是在webGLStart()是:initGL,使用A材质,使用B材质,创建对象,用当前材质绘制对象(那就是材质B)。

OpenGL/webGL作为状态机工作。当你尝试渲染某些东西时,它会使用当前设置的状态机的参数绘制。例如,对于OpenGL,您说draw,但该方法正在寻找绑定到状态机的缓冲区,它还查找当前使用的材质(着色器)等等。因此,您将所有内容都设置好并启动了一些操作。因此,如果要使用两个不同着色器呈现两个对象,则应绑定一个对象(实际上是缓冲区),使用第一个对象(gl.useProgram(shaderProgramA))并调度绘制。然后绑定第二个对象,设置第二个对象(gl.useProgram(shaderProgramB))并发送另一个调用。这就是OpenGL/WebGL的工作原理。

此外,一个建议。尝试命名函数的方式不同。 initShadersA应该执行诸如获取源字符串,创建顶点和片段着色器,创建程序和链接所有内容等,而像useShadersA这样的函数应该将当前材质设置为精确着色器程序。

我希望这有助于!

+0

谢谢gman - 你的教程是非常有用的......不像我的教科书。并感谢您提供反馈抽象算法。我得到了设计工作!我将initShadersA和initShadersB从webGLStart()移到了相关的drawScene()区域。就如此容易。将来我会考虑你的命名约定评论。 – user2781042 2015-04-01 09:53:56

+0

如果有帮助,请接受答案以帮助SO社区。祝你好运! – 2015-04-01 11:30:49