由samplerCube

时间:2015-07-27 23:37:28

标签: javascript glsl webgl opengl-es-2.0

我目前正在学习WebGL,每次都用新的东西扩展我的代码。但是,这个错误一直在抛出:

[.WebGLRenderingContext-0111BCC8]GL ERROR :GL_INVALID_OPERATION : glFramebufferTexture2D: <- error from previous GL command

在我的javascript代码中,我设置了一个uniform bool,无论我渲染的对象是否具有反射(在我的渲染代码中较早,我创建了一个立方体贴图并将反射渲染到它)。当它有反射时,我还设置了活动纹理单元,绑定立方体贴图纹理并设置uniform textureCube uReflectionMap,如下所示:

if (obj.reflects && obj.reflectionMap != null) {
    this.gl.activeTexture(this.gl.TEXTURE10);
    this.gl.bindTexture(this.gl.TEXTURE_CUBE_MAP, obj.reflectionMap.glTexture);
    this.gl.uniform1i(p.uniforms["uReflectionMap"], 10);
    this.gl.uniform1i(p.uniforms["uReflects"], true);
} else {
    this.gl.uniform1i(p.uniforms["uReflects"], false);
}

我仅在代码的这一部分使用纹理单元10(仅适用于反射立方体贴图)

片段着色器代码:

if(uReflects){
    vec3 lookup = reflect(eyeDirection, normal);
    color += textureCube(uReflectionMap, -lookup); //no errors when this line is commented
}

当我评论突出显示的&#39;上面的一行,一切正常(除了显然没有反射)。因此,我期望if(uReflects)是错误的(这样即使没有设置uReflectionMap,这段代码也会消除。只需将注释行更改为color += vec4(1.),并且仅将对象改为uReflectionMap。设置反映完全是白色。

我之后尝试了解决问题的方法是将this.gl.uniform1i(p.uniforms["uReflectionMap"], 10);设置为纹理单元10(在else语句中为var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_CUBE_MAP, texture); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.NEAREST); var size = 1024; this.reflectionFrameBuffers = []; this.reflectionRenderBuffers = []; for (var i = 0; i < 6; i++) { gl.texImage2D(gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, size, size, 0, gl.RGBA, gl.UNSIGNED_BYTE, null); this.reflectionRenderBuffers[i] = gl.createRenderbuffer(); gl.bindRenderbuffer(gl.RENDERBUFFER, this.reflectionRenderBuffers[i]); gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, size, size); this.reflectionFrameBuffers[i] = gl.createFramebuffer(); gl.bindFramebuffer(gl.FRAMEBUFFER, this.reflectionFrameBuffers[i]); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, texture, 0); gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, this.reflectionRenderBuffers[i]); gl.checkFramebufferStatus(gl.FRAMEBUFFER);//this throws no errors } gl.bindTexture(gl.TEXTURE_2D, null); gl.bindFramebuffer(gl.FRAMEBUFFER, null); gl.bindRenderbuffer(gl.RENDERBUFFER, null); ),无论我的对象是否具有reflectionMap。

这对我来说似乎很奇怪,因为当uReflects为false时,不执行textureCube函数,但是当未设置uReflectionMap时仍然会生成错误。

我希望这个问题是可以理解的,我有很多代码,并且不知道我应该在问题中添加什么(因为可能还有其他东西在干扰,我已经监督过了。)

我已经在Google Chrome 43.0.2357.134 m中完成了所有这些测试。只是在IE中运行它,它似乎给出了一个更详细的错误信息,虽然它写得如此糟糕的荷兰语,我不知道如何解释它,更不用说翻译了。 现在就试试firefox。 Firefox没有发出任何警告,但它也不起作用......

<小时/> 回复@gman:

这是我创建立方体贴图纹理()的代码:

this.gl.colorMask(true, true, true, true);
this.gl.clearColor(0, 0, 0, 1);
this.gl.cullFace(this.gl.BACK);

for (var j = 0; j < 6; j++) {
    this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, obj.reflectionFrameBuffers[j]);
    this.gl.clear(this.gl.COLOR_BUFFER_BIT | this.gl.DEPTH_BUFFER_BIT);
}

这件作品在渲染前清除所有边:

for (var k = 0; k < 6; k++) {
    this.gl.bindFramebuffer(this.gl.FRAMEBUFFER, obj.reflectionFrameBuffers[k]);
    this.gl.uniformMatrix4fv(p.uniforms["uViewMatrix"], false, obj.reflectionViewMatrices[k].array);//these view matrices determine which direction to look in
    this.gl.drawArrays(this.gl.TRIANGLES, 0, mesh.facesArray.length / 9);
}

这是渲染到立方体贴图的代码(它被其他for循环和代码包围以供给reflectionMapper着色器):

test2.jpg

1 个答案:

答案 0 :(得分:1)

问题是你有2个不同类型的统一采样器指向相同的纹理单元。

着色器通常执行所有路径。我的意思是如果你在着色器中有这个

if (someCondition) {
  a = value1;
} else {
  a = value2;
}

着色器中真正发生的事情就像是

a = value1 * (someCondition ? 1 : 0) + value2 * (someCondition ? 0 : 1);

或更好

// mix will be 1.0 if someCondition is true, else 0.0
float mix = step(0.5, 1.0 - float(someCondition)); 

a = value1 * mix + value2 * (1 - mix);

现在没有分支机构。 GPU不会分支,这是他们如何获得速度的。注意我提出了这个例子,但它表明无论条件如何都使用value1和value2。这假设条件是可变的。在你的例子中

uniform bool uIsCube;
uniform sampler2D uTwoD;
uniform samplerCube uCube;

varying vec3 vTexCoord;

void main(void){
    if(uIsCube){
        gl_FragColor = textureCube(uCube, vTexCoord);
    } else {
        gl_FragColor = texture2D(uTwoD, vTexCoord.st);
    }
}

uIsCube是可变的。我无法在编译时知道,只能在运行时知道,因此始终使用uCubeuTwoD,并且需要使用gl.uniform1i

将其设置为不同的纹理单元

如果另一方面如果条件是这样的常数

#define IsCube false

void main(void){
    if(IsCube){
        gl_FragColor = textureCube(uCube, vTexCoord);
    } else {
        gl_FragColor = texture2D(uTwoD, vTexCoord.st);
    }
}

然后在编译时编译器可能删除其中一个采样器。我说可能是因为IIRC规范并不要求驱动程序优化着色器中未使用的代码。

另请注意,制服都默认为0,所以如果你不设置制服,那么两个采样器都将指向纹理单元。

您可以通过检查制服的位置来检查制服是否已经过优化

var uCubeLoc = gl.getUniformLocation(program, "uCube");
if (!uCubeLoc) {
  // uCubeLoc does not exist or was optimized out
}

要查看代码中是否存在与指向同一纹理单元的不同类型的多个采样器相关的错误,您可以在每次gl.draw___调用之前调用此类函数。

function checkForConflictingSamplers() {
  var prg = gl.getParameter(gl.CURRENT_PROGRAM);
  var units = {};
  var numUniforms = gl.getProgramParameter(prg, gl.ACTIVE_UNIFORMS);

  function checkUniform(name, type) {
    var unit = gl.getUniform(prg, gl.getUniformLocation(prg, name));
    var unitInfo = units[unit];
    if (unitInfo === undefined) {
      units[unit] = { 
        type: type,
        name: name,
      };
    } else if (unitInfo.type !== type) {
      console.error("unit " + unit + " is being used by conflicting samplers " + name + " and " + unitInfo.name);
    }
  }    

  for (var ii = 0; ii < numUniforms; ++ii) {
    var uniformInfo = gl.getActiveUniform(prg, ii);
    if (!uniformInfo) {
      continue;
    }
    var name = uniformInfo.name;
    var type = uniformInfo.type;
    var isArray = (uniformInfo.size > 1 && name.substr(-3) === "[0]");
    // remove the array suffix.
    if (name.substr(-3) === "[0]") {
      name = name.substr(0, name.length - 3);
    }

    if (type === gl.SAMPLER_2D || type === gl.SAMPLER_CUBE) {
      if (isArray) {
        for (var ii = 0; ii < uniformInfo.size; ++ii) {
          checkUniform(name + "[" + ii + "]", type);
        }
      } else {
        checkUniform(name, type);
      }
    }
  }
}