OpenGL ES绘制黑色纹理

时间:2014-10-04 16:15:55

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

以下代码用于我的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之间的继承从未使用过。是的,我知道它很难看,而且我打算尽快清理整个继承模型。

有没有人知道为什么纹理被完全拉成黑色?我一整天都在看这个代码,所以感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

好的,我弄清楚问题是什么。在渲染器创建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);