【问题标题】:OpenGL ES draws a black textureOpenGL ES 绘制黑色纹理
【发布时间】:2014-11-29 10:33:04
【问题描述】:

以下代码在我的 Android OpenGL-ES 游戏中用于在屏幕上绘制一个带纹理的矩形。唯一的问题是在矩形上绘制黑色纹理而不是加载的 PNG。

AssetManager.cpp(将文件从文件系统加载到内存中)

    void AssetManager::Retrieve() {
    auto file = File("spritesheet_full.png");

    if (!file.Open()) {
        PrintVerbose("Woops");
    }
    unsigned char dataA[file.Length()];
    size_t position = 0;

    file.Read(dataA, file.Length(), position);

    auto data = std::vector<unsigned char>(dataA, dataA + file.Length());

    auto png = PNG(data);

    Texture::Header textureHeader;
    textureHeader.width = png.getWidth();
    textureHeader.height = png.getHeight();
    textureHeader.bytesPerPixel = 4;
    textureHeader.dataSize = textureHeader.width * textureHeader.height
            * textureHeader.bytesPerPixel;

    texture.SetData(textureHeader, png.getData());
    texture.Init();
}

PNG.cpp(将读取的数据解码为原始图像数据。我认为这部分有效,因为读取的宽度和高度是正确的。image 定义为unsigned char* image

    PNG::PNG(std::vector<unsigned char> data)
{
    std::vector<unsigned char> rawImage;

    lodepng::decode(rawImage, width, height, data);

    image = new unsigned char[width *  height* 4];

    for(int i = 0; i < width * height * 4; i++)
    {
        image[i] = rawImage[i];
    }
}

Texture.cpp(包含图像数据,并与OpenGL链接)

Texture::Texture() :
        id(GL_INVALID_VALUE) {

}

Texture::~Texture() {

}

void Texture::SetData(Texture::Header& header, void* pImageData) {
    headerData = header;
    imageData = pImageData;
}

void Texture::Init() {
    GLint packBits = 4;
    GLint internalFormat = GL_RGBA;
    GLenum format = GL_RGBA;
    switch (headerData.bytesPerPixel) {
    case 1: {
        packBits = 1;
        internalFormat = GL_ALPHA;
        format = GL_ALPHA;
    }
        break;
    };

    glGenTextures(1, &id);

    glBindTexture(GL_TEXTURE_2D, id);

    glPixelStorei(GL_UNPACK_ALIGNMENT, packBits);

    glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, headerData.width,
            headerData.height, 0, format, GL_UNSIGNED_BYTE, imageData);
}

TextureShader.cpp(纹理通过一个简单的 getter 链接到着色器。TextureShader::Setup 然后由渲染器调用)

TextureShader::TextureShader() :
        texture(NULL) {
    vertexShaderCode = "attribute vec2 position;        \n"
            "attribute vec2 a_texCoord;         \n"
            "varying   vec2 v_texCoord;         \n"
            "uniform mat4 projView; \n"
            "uniform mat4 transformMatrix; \n"
            "uniform mat4 cameraTransform; \n"
            "void main(){                       \n"
            "     gl_Position = projView * (cameraTransform * (transformMatrix * vec4(position, 0.0, 1.0)));    \n"
            "    v_texCoord = a_texCoord;       \n"
            "}                                  \n";

    fragmentShaderCode = "precision highp float;                                \n"
            "varying vec2 v_texCoord;                               \n"
            "uniform sampler2D s_texture;                           \n"
            "void main(){                                           \n"
            "    gl_FragColor = texture2D(s_texture, v_texCoord);   \n"
            "}                                                      \n";
}

TextureShader::~TextureShader() {

}

void TextureShader::Link() {
    Shader::Link();

    this->positionAttributeHandle = glGetAttribLocation(programId, "position");
    this->texCoordAttributeHandle = glGetAttribLocation(programId, "a_texCoord");
    this->samplerHandle = glGetUniformLocation(programId, "s_texture");
    this->projectionViewUniformHandle = glGetUniformLocation(programId, "projView");
    this->transformationUniformHandle = glGetUniformLocation(programId, "transformMatrix");
    this->cameraTransformUniformHandle = glGetUniformLocation(programId, "cameraTransform");
}

void TextureShader::Setup(Renderable* renderable, GLfloat* cameraTransform,
        GLfloat* projectionView) {

    Geometry* pGeometry = renderable->GetGeometry();
    if (pGeometry && texture) {
        Shader::Setup(renderable, cameraTransform, projectionView);

        glActiveTexture (GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, texture->GetId());
        glUniform1i(samplerHandle, 0);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        glUniformMatrix4fv(projectionViewUniformHandle, 1, GL_FALSE, projectionView);
        glUniformMatrix4fv(transformationUniformHandle, 1, GL_FALSE, renderable->GetTransform()->GetTranslateMatrix());
        glUniformMatrix4fv(cameraTransformUniformHandle, 1, GL_FALSE, cameraTransform);

        glVertexAttribPointer(positionAttributeHandle,
                pGeometry->GetNumVertexPositionElements(), GL_FLOAT, GL_FALSE,
                pGeometry->GetVertexStride(), pGeometry->GetVertexBuffer());
        glEnableVertexAttribArray(positionAttributeHandle);

        glVertexAttribPointer(texCoordAttributeHandle,
                pGeometry->GetNumTexCoordElements(), GL_FLOAT, GL_FALSE,
                pGeometry->GetTextStride(),
                pGeometry->GetTextureCoordinates());

        glEnableVertexAttribArray(texCoordAttributeHandle);
    }
}

Renderer.cpp(维护可渲染实体并渲染它们)

void Renderer::Init()
{
    // initialize OpenGL ES and EGL

    /*
     * Here specify the attributes of the desired configuration.
     * Below, we select an EGLConfig with at least 8 bits per color
     * component compatible with on-screen windows
     */
    const EGLint attribs[] =
    { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE };

    EGLint format;
    EGLint numConfigs;
    EGLConfig config;

    display = eglGetDisplay(EGL_DEFAULT_DISPLAY);

    eglInitialize(display, NULL, NULL);

    /* Here, the application chooses the configuration it desires. In this
     * sample, we have a very simplified selection process, where we pick
     * the first EGLConfig that matches our criteria */
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);

    /* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
     * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
     * As soon as we picked a EGLConfig, we can safely reconfigure the
     * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
    eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);

    ANativeWindow_setBuffersGeometry(appState->window, 0, 0, format);

    drawingSurface = eglCreateWindowSurface(display, config, appState->window,
            NULL);

    EGLint contextAttribs[] =
    { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
    context = eglCreateContext(display, config, NULL, contextAttribs);

    eglMakeCurrent(display, drawingSurface, drawingSurface, context);

    eglQuerySurface(display, drawingSurface, EGL_WIDTH, &width);
    eglQuerySurface(display, drawingSurface, EGL_HEIGHT, &height);

    this->SetProjectionMatrix();
    this->SetCameraTransform();

    for (ShaderVectorIterator iter = shaders.begin(); iter != shaders.end();
            ++iter)
    {
        Shader* pCurrent = *iter;
        pCurrent->Link();
    }

    initialized = true;
}

void Renderer::Draw(Renderable* pRenderable)
{
    assert(pRenderable);
    if (pRenderable)
    {
        Geometry* pGeometry = pRenderable->GetGeometry();
        Shader* pShader = pRenderable->GetShader();
        assert(pShader && pGeometry);
        if (pShader && pGeometry)
        {
            pShader->Setup(pRenderable, cameraTransform, projectionMatrix);

            glDrawElements(GL_TRIANGLES, pGeometry->GetNumIndices(),
                    GL_UNSIGNED_SHORT, pGeometry->GetIndexBuffer());
        }
    }
}

void Renderer::Update()
{
    if (initialized)
    {
        glClearColor(0.95f, 0.95f, 0.95f, 1);
        glClear(GL_COLOR_BUFFER_BIT);

        for (RenderableVectorIterator iter = renderables.begin();
                iter != renderables.end(); ++iter)
        {
            Renderable* pRenderable = *iter;
            if (pRenderable)
            {
                Draw(pRenderable);
            }
        }

                eglSwapBuffers(display, drawingSurface);
    }
}

TexturedRectangle.cpp(扩展了 Rectangle.cpp)

TexturedRectangle::TexturedRectangle(int posX, int posY, int width, int height, Texture* texture)
    : Engine::Rectangle(posX, posY, width, height),
      texture(texture),
      textCords({0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f})
{
    shader = new TextureShader();

    auto texShader = (TextureShader*)shader;

    texShader->SetTexture(texture);

    SetShader(texShader);

    GetGeometry()->SetTextureCoordinates(&textCords);
    GetGeometry()->SetTexStride(sizeof(float) * 2);
    GetGeometry()->SetNumTexCoordElements(2);

}

Rectangle.cpp(vertsfloat verts[8] 并包含一个矩形相对坐标列表)

 Rectangle::Rectangle(int posX, int posY, int width, int height) :
            verts(), 
        indices( { 0, 2, 1, 2, 3, 1 }), 
        colors( { 0.8, 0.8, 0.3, 1.0,
                0.8, 0.8, 0.3, 1.0, 
                0.8, 0.8, 0.3, 1.0, 
                0.8, 0.8, 0.3, 1.0, 
                0.8, 0.8, 0.3, 1.0, 
                0.8, 0.8, 0.3, 1.0, }),
                shader(new OrthoGraphicShader())
    {
        float leftX = 0 - (width / 2.f);
        float rightX = width / 2.f;
        float upperY = 0 - (height / 2.f);
        float lowerY = height / 2.f;

        verts[0] = leftX;
        verts[1] = upperY;
        verts[2] = rightX;
        verts[3] = upperY;
        verts[4] = leftX;
        verts[5] = lowerY;
        verts[6] = rightX;
        verts[7] = lowerY;

        this->SetGeometry(&geometry);
        this->SetShader(shader);
        this->SetTransform(&transform);

        this->Translate(posX, posY);

        geometry.SetVertexBuffer(verts);
        geometry.SetNumVertices(4);
        geometry.SetIndexBuffer(indices);
        geometry.SetNumIndices(6);
        geometry.SetName("quad");
        geometry.SetNumVertexPositionElements(2);
        geometry.SetVertexStride(sizeof(float) * 2);
        geometry.SetColor(colors);

    }

由于 Rectangle 和 TexturedRectangle colors 之间的继承关系,从未使用过。是的,我知道它很丑,我打算很快清理整个继承模型。

有谁知道为什么纹理被绘制成全黑的?我整天都在看这个代码,所以任何帮助都非常感谢!

【问题讨论】:

  • 对于一个问答网站来说,这已经是相当多的代码了,我想说你需要更多地隔离你的问题。你的纹理是 2 的幂吗?如果你用 FFFFFF(白色)字节填充它们会发生什么?
  • 纹理是 2 的幂 (256x256)。用(char)255 填充图像数据不会改变任何事情。我知道它有很多代码。但我不知道问题出在哪里。我假设片段着色器是正确的。因为将其更改为gl_FragColor = vec4(1, 0, 0, 1) 会导致出现红色方块。由于 lodepng 返回正确的尺寸,我很确定 unsigned char image[] 包含正确的字节。但由于这是我的第一个 OpenGL-ES C++ 项目,我不知道。

标签: android c++ opengl-es-2.0


【解决方案1】:

好的,我发现了问题所在。在渲染器创建 OpenGL 上下文之前,我调用了 Texture::Init(),它设置了纹理数据。

glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, headerData.width, headerData.height, 0, format, GL_UNSIGNED_BYTE, imageData);

通过这一行创建上下文:

context = eglCreateContext(display, config, NULL, contextAttribs);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-14
    相关资源
    最近更新 更多