其他分享
首页 > 其他分享> > Android OpenGL ES 2.0黑色纹理

Android OpenGL ES 2.0黑色纹理

作者:互联网

以此作为开头:是的,我已经看了之前在此站点上提出的大量“ Android OpenGL ES 2.0黑色纹理”问题.不,他们都不对我的情况有所帮助.不,我不确定是否可以用适当数量的字符更好地表达标题.

我遵循了许多教程,并能够建立一个非常简单的渲染器类,以正确加载和渲染纹理(项目A).然后,我尝试在游戏引擎(项目B)中实现这个非常简单的渲染系统.一切工作完全相同,除了texture2D()由于某种原因返回黑色.我尝试了很多调试工作,并且进行了很多谷歌搜索,但都无济于事.因此,我寻求帮助.

我的顶点和片段着色器.他们在项目A中工作得很好,所以我认为这不是问题的根源,只是为了完整起见.

private static final String VERTEX_SHADER_SOURCE =
...
"attribute vec2 a_TexCoord;" +
"varying vec2 v_TexCoord;" +

"void main() {" +
"   v_TexCoord = a_TexCoord;" +
...
"}";


private static final String FRAGMENT_SHADER_SOURCE =
"precision mediump float;" +
"uniform sampler2D u_Texture;" +
"varying vec2 v_TexCoord;" +

"void main() {" +
"   gl_FragColor = texture2D(u_Texture, v_TexCoord);" +
"}";

我创建,编译这些着色器,并将它们附加到程序中,没有错误.此后,我相应地设置了句柄-我还将u_Texture设置为指向纹理单元0,因为这不会改变:

...
sTexUniformHandle = GLES20.glGetUniformLocation(sProgramHandle, "u_Texture");
sMVPHandle = GLES20.glGetUniformLocation(sProgramHandle, "u_MVPMatrix");
sPositionHandle = GLES20.glGetAttribLocation(sProgramHandle, "a_Position");
sTexCoordHandle = GLES20.glGetAttribLocation(sProgramHandle, "a_TexCoord");

GLES20.glUseProgram(sProgramHandle);
GLES20.glUniform1i(sTexUniformHandle, 0);
GLES20.glUseProgram(0);
...

然后加载纹理:

...
int[] texData = Utils.createTexture(context, resId);
mTexDataHandle = texData[0];
...
public static int[] createTexture(Context context, int resId) { // returns {textureHandle, width, height}
    int width = -1;
    int height = -1;

    int[] texHandle = new int[1];
    GLES20.glGenTextures(1, texHandle, 0);

    if (texHandle[0] != 0) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inScaled = false;

        final Bitmap bm = BitmapFactory.decodeResource(context.getResources(), resId, opts);
        width = bm.getWidth();
        height = bm.getHeight();

        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texHandle[0]);

        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
        GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);

        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bm, 0);

        bm.recycle();
    }

    if (texHandle[0] == 0) {
        throw new RuntimeException("texture load error");
    }

    return new int[]{texHandle[0], width, height};
}

即使我的纹理是32 x 19,我也不需要在项目A中设置纹理包裹.我将纹理更改为32 x 32并设置纹理包裹以夹紧,以防万一,所以没有人会告诉我这是我的错误.位图正在加载-我写了宽度,高度和一些要调试的选择像素,然后就可以找到它们了.

在我的draw方法中,启用a_TexCoord属性并将其指向数据:

...
GLES20.glEnableVertexAttribArray(sTexCoordHandle);
...
GLES20.glVertexAttribPointer(sTexCoordHandle, mTexCoordDataSize, GLES20.GL_FLOAT, false, 0, mTexCoordBuffer);
...

我将整个mTexCoordBuffer写出到调试消息中,并正确加载了纹理坐标数据.

最后,我将活动纹理单元设置为0,将其纹理数据绑定到该单元,然后绘制:

...
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexDataHandle);

GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 6);
...

对于整个图形库我还是很陌生,但是我已经竭尽全力去理解这里实际发生的事情.我以为我了解全部,但是事实显然并非如此.据我所知,着色器正常工作-黑色矩形正好出现在应有的位置(在项目A中也是如此).我传入的纹理坐标数据与项目A中的数据完全相同,并且我对它的加载方式没有任何更改.这将实际的纹理数据留给主要怀疑者,但是我尝试像在项目A中一样进行设置,这似乎是正确的.如果有人比我更有能力指出我的错误,我将不胜感激.

解决方法:

las,我知道这将是值得面对的事情.尽管我想我应该尽快发现错误,并且确实理解了我正在使用的GLES代码,但我对此感到很高兴.另一方面,我显然不了解Java的基础知识.

无论如何,事实证明,我当时正在Renderer和GameState类的构造函数中做很多事情,这些事情我当时不应该做.我在GameState中创建了一个allocateGameState()方法,并在我的渲染器的onSurfaceCreated()中对其进行了调用;问题解决了.

我仍然感到困惑的部分是:我发现这是我的错误,方法是返回项目A并更改代码,直到它模仿项目B.最后,我很幸运,并且犯了同样的错误,即滥用渲染器的构造函数以实例化纹理/着色器/程序数据.但是,这一次,我为以下错误所困扰:“在没有当前上下文的情况下调用OpenGl ES API”.我很快解决了这个问题,并对项目B应用了相同的修复程序,但是这让我想知道为什么我在项目B中没有遇到相同的错误.

标签:opengl-es,textures,android,opengl-es-2-0
来源: https://codeday.me/bug/20191029/1957816.html