2014-10-04 156 views
0

下面的代碼用於我的Android OpenGL-ES遊戲中,在屏幕上繪製帶紋理的矩形。唯一的問題是,不是加載的PNG,而是在矩形上繪製黑色紋理。OpenGL ES繪製黑色紋理

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

這是一個Q&A網站相當多的代碼,我說你需要隔離你的問題有點多。你的紋理是2的權力?如果你用FFFFFF(白色)字節填充它們會發生什麼? – 2014-10-04 17:48:13

+0

紋理是兩個冪(256x256)。用'(char)255'填充圖像數據不會改變。我意識到這是一個很多代碼的事實。但我不知道問題出在哪裏。我認爲片段着色器是正確的。因爲將其更改爲'gl_FragColor = vec4(1,0,0,1)'會產生紅色正方形。由於lodepng返回正確的尺寸,我非常肯定'unsigned char image []'包含正確的字節。但是因爲這是我的第一個OpenGL-ES C++項目,所以我不知道。 – TheDutchDevil 2014-10-04 18:26:25

回答

0

好的,我找出了問題所在。在Renderer創建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);