简体   繁体   English

OpenGL ES绘制黑色纹理

[英]OpenGL ES draws a black texture

The below code is used in my Android OpenGL-ES game to draw a textured rectangle on the screen. 我的Android OpenGL-ES游戏中使用以下代码在屏幕上绘制带纹理的矩形。 The only problem is that instead of the loaded PNG a black texture is drawn on the rectangle. 唯一的问题是,在矩形上绘制了黑色纹理,而不是已加载的PNG。

AssetManager.cpp (Loads the file from the file system into memory) 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 (Takes the data read and decodes it into raw image data. I assume this part works because the read width and height is correct. image is defined as unsigned char* image ) 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 (Contains the image data, and links it with OpenGL) 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 (Texture is linked to the shader, throuh a simple getter. TextureShader::Setup is then called by the Renderer) TextureShader.cpp(通过简单的获取器将纹理链接到着色器。然后,Renderer调用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 (Maintains the renderable entities and renders them) 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 (Which extends Rectangle.cpp) 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 ( verts is float verts[8] and contains a list of rectangle relative coordinates) 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);

    }

Because of the inheritance between Rectangle and TexturedRectangle colors is never used. 由于Rectangle和TexturedRectangle之间的继承关系,因此从未使用过colors Yes I know it's ugly, and I'm planning to clean up the whole inheritance model soon. 是的,我知道这很丑陋,并且我打算尽快清理整个继承模型。

Does anyone have any idea why the texture is being drawn completely black? 有谁知道为什么将纹理绘制为全黑? I've been looking at this code all day, so any help is appreciated! 我整天都在看这段代码,感谢您的帮助!

Okay, I figured out what the problem is. 好的,我知道了问题所在。 I was calling Texture::Init(), which sets up the texture data, before the Renderer created an OpenGL context. 在渲染器创建OpenGL上下文之前,我正在调用Texture :: Init()来设置纹理数据。

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

Creating the context is done by this line: 通过以下行创建上下文:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM