【问题标题】:WebGL renderable texture not rendering. RENDER WARNING: texture bound to texture unit 0 is not renderableWebGL 可渲染纹理未渲染。渲染警告:绑定到纹理单元 0 的纹理不可渲染
【发布时间】:2014-02-05 16:31:41
【问题描述】:

我正在一个 Web 查看器中工作,该查看器有许多渲染到同一页面的着色器程序。我正在添加另一个使用纹理渲染四边形的程序。四边形渲染得很好。纹理给我带来了问题。

Mesh.prototype.initTexture = function(ctx) {

    this.texture = this.ctx.createTexture();
    this.texture.image = new Image();

    // ctx.bindTexture(this.ctx.TEXTURE_2D, this.texture);
    // ctx.texImage2D(this.ctx.TEXTURE_2D, 0, this.ctx.RGBA, 1, 1, 0, this.ctx.RGBA, this.ctx.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255])); // red

    mesh.texture.image.onload = function () {
        //Upon callback, 'this' is different, so we use the global variable for now
        mesh.handleLoadedTexture(mesh.texture,mesh.texture.image);
    }

    this.texture.image.src = "/path/to/images/nehe.gif";

}

那是我的 initTexture 函数。我可以取消注释加载红色方块的两行(a la WebGL - wait for texture to load),然后纹理呈现为红色并且不再弹出错误,但我的纹理永远不会加载。纹理本身是我从 LearningWebGL 下载的可渲染纹理。我有一个演示下载表单,该站点在我的本地主机上运行良好,与该项目并行。

这里是handleLoadedTexture函数

Mesh.prototype.handleLoadedTexture = function(texture, image) {

    mesh.ctx.bindTexture(mesh.ctx.TEXTURE_2D, texture);
    mesh.ctx.pixelStorei(mesh.ctx.UNPACK_FLIP_Y_WEBGL, true);
    mesh.ctx.texImage2D(mesh.ctx.TEXTURE_2D, 0, mesh.ctx.RGBA, this.ctx.RGBA, mesh.ctx.UNSIGNED_BYTE, image);
    mesh.ctx.texParameteri(mesh.ctx.TEXTURE_2D, mesh.ctx.TEXTURE_MAG_FILTER, mesh.ctx.NEAREST);
    mesh.ctx.texParameteri(mesh.ctx.TEXTURE_2D, mesh.ctx.TEXTURE_MIN_FILTER, mesh.ctx.NEAREST);
    mesh.ctx.generateMipmap(mesh.ctx.TEXTURE_2D);
    mesh.ctx.bindTexture(mesh.ctx.TEXTURE_2D, null);
}

然后我们在整个渲染管道中有调用这个渲染的块:

if (mesh != null) {
    mesh = new Mesh();
    ctx.useProgram(meshShader);
    // I set the camera and projection matrices here
    glCheck();
    if(!mesh.vbo) {
        mesh.loadGL(ctx);
    }
    if(!mesh.texture){
        mesh.initTexture(ctx);
    }
    mesh.render(meshShader);
    glCheck();
}

没有什么太革命性的了。

渲染函数:

Mesh.prototype.render = function(program) {
    assert(this.vbo != null, "VBO is null");
    assert(this.tcbo != null, "TCBO is null");

    // Arguments here are (index, size, type, normalized(bool), stride, offset)
    this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.vbo);
    this.ctx.vertexAttribPointer(program.a.vertex, this.sizevertices, this.ctx.FLOAT, false, 0, 0);

    this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.tcbo);
    this.ctx.vertexAttribPointer(program.a.textureCoordinate, this.sizetexco, this.ctx.FLOAT, false, 0, 0);

    this.ctx.activeTexture(this.ctx.TEXTURE0);
    this.ctx.bindTexture(this.ctx.TEXTURE_2D, this.texture);
    this.ctx.uniform1i(program.uSampler, 0);

    this.ctx.drawArrays(this.ctx.TRIANGLE_STRIP, 0, this.numvertices);
    render.glCheck();
}

顶点着色器:

varying vec2 vTextureCoord;

attribute vec3 vertex;
attribute vec2 textureCoordinate;

//other unrelated uniforms

void main(void) {

//position settings omitted
    vTextureCoord = textureCoordinate;
}

片段着色器:

precision mediump float;

varying vec2 vTextureCoord;

uniform sampler2D uSampler;

void main(void) {
    gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));
}

【问题讨论】:

  • 如果你要使用最近邻缩小过滤器,那么调用mesh.ctx.generateMipmap(mesh.ctx.TEXTURE_2D); 是没有意义的。您所做的只是无缘无故地将纹理数据的大小增加了 33%。
  • 嗯,我明白了。我想说那条线是在解决这个问题时留下来的。我删除了那条线,但是加载纹理的结果是一样的。不过感谢您的信息!
  • 您确定调用了handleLoadedTexture 吗?您是否检查过(使用 Chrome 的 WebGL Inspector)纹理是否已加载到 WebGL?
  • @virtualnobi 完全忽略了这个事实。好的。我仍然建议使用标志来检查某些内容,而不是将完整对象与某个值进行比较。
  • @AbstractAlgorithm 我不确定你的意思 - 我指的是一些基本的调试检查,以确保执行正确的代码并将纹理传输到 WebGL 空间......

标签: javascript opengl-es textures webgl


【解决方案1】:

我想知道您在 initTexture 函数中引用了哪个 mesh - 它肯定没有在您提供的代码中的任何地方定义...

也许你想写

this.texture.image.onload = function....

您已经了解到函数内部的this 与外部不同。但我想你需要使用另一个变量,而不是全局变量,就像这样:

that = this;
this.texture.image.onload = function () {
    that.handleLoadedTexture(mesh.texture,mesh.texture.image);
}

【讨论】:

  • 正确!我没有添加该代码,它是相当样板的东西,但如果你愿意,我可以添加它。在代码中,mesh 是一个全局定义的变量,我最初设置为null。加载其他对象后,我进入 js 控制台并执行 mesh = 1。此时,if (!mesh) {... 会被评估。我对 js 也很陌生,但如果我能做类似that = this 的事情,那就太好了。这是建立上下文的标准程序吗?
  • 还有另一种可能性,即修复函数执行上下文的bind 函数,但(我认为)在这里使用局部变量更容易。只需谷歌“Javascript 绑定功能”并选择您最信任的网站...
【解决方案2】:
if(!mesh.texture) {    // isn't it 'undefined'
    mesh.initTexture(ctx);
}

也许最好为整个事情设置适当的标志。

// when creating mesh
mesh.texInit = false;

加载时:

Mesh.prototype.initTexture = function(ctx) {

    this.texture = this.ctx.createTexture();
    this.texture.image = new Image();

    // ctx.bindTexture(this.ctx.TEXTURE_2D, this.texture);
    // ctx.texImage2D(this.ctx.TEXTURE_2D, 0, this.ctx.RGBA, 1, 1, 0, this.ctx.RGBA, this.ctx.UNSIGNED_BYTE, new Uint8Array([255, 0, 0, 255])); // red

    mesh.texture.image.onload = function () {
        //Upon callback, 'this' is different, so we use the global variable for now
        mesh.handleLoadedTexture(mesh.texture,mesh.texture.image);
        mesh.texInit = true;
        // note ^ here
    }
    this.texture.image.src = "/path/to/images/nehe.gif";
}

对于渲染:

if(mesh.texInit) { doMagic(); } // aka render

【讨论】:

  • 啊,所以添加一个标志,说明纹理已经初始化?我试过一次,但我敢打赌我错过了一些东西。我敢打赌,它唯一一次有机会使用纹理进行渲染,它还没有准备好。明天我会试一试,然后报告。谢谢!!
  • 是的,只需使用标志即可知道您是否已完全完成创建WebGLTexture 对象。这比将整个对象与某个值进行比较要好得多。说说进展如何。
  • 嗯,还是什么都没有。纹理仍然是我的临时 1x1 红色。我在对象实例化中添加了mesh.texinit = false。我确保纹理仅应用于纹理加载的逻辑有效:if (mesh.texinit == false) { mesh.initTexture(ctx); } 此外,我在控制台中检查了mesh.texinit 日志truemesh.texture.image.height 日志256。本次运行未出现错误。
  • 您的评论让我走上了正确的道路。我有逻辑覆盖我的对象,相当于:``` if (mesh != null) { mesh = new Mesh(); ...}```这很尴尬。我解决了这个问题,它加载得非常好。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多