2013-02-28 42 views
3

我正在将一些代码从OpenGL 1.3转换为OpenGL ES 1.1。这是一款2D游戏,所以它主要归结为将纹理渲染成四边形。 OpenGL ES中没有即时模式,所以我不得不使用顶点缓冲区对象。使用顶点缓冲对象渲染的四边形纹理只有一半透明

但似乎组成每个四边形的两个三角形中只有一个处理透明度。下面是截图:

enter image description here

下面是如何呈现的纹理四边形现在,这会导致如下:

glBindTexture2D(GL_TEXTURE_2D, id); 

glEnableClientState(GL_VERTEX_ARRAY); 
glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

const GLfloat texture_coordinates[] = {0, 0, 
             0, 1, 
             1, 1, 
             1, 0}; 
glTexCoordPointer(2, GL_FLOAT, 0, texture_coordinates); 

const GLfloat vertices[] = {0, 0, 
          0, height, 
          width, height, 
          width, 0}; 
glVertexPointer(2, GL_FLOAT, 0, vertices); 

const GLubyte indices[] = {0, 1, 2, 
          0, 2, 3}; 
glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_BYTE, indices); 

glDisableClientState(GL_VERTEX_ARRAY); 
glDisableClientState(GL_TEXTURE_COORD_ARRAY); 

这里是我用来渲染纹理四边形采用即时模式,工作正常:

glBindTexture2D(GL_TEXTURE_2D, id); 

glBegin(GL_QUADS); 

glTexCoord2i(0, 0); 
glVertex2i(0, 0); 

glTexCoord2i(1, 0); 
glVertex2i(width, 0); 

glTexCoord2i(1, 1); 
glVertex2i(width, height); 

glTexCoord2i(0, 1); 
glVertex2i(0, height); 

glEnd(); 

下面是一个重现问题的示例程序。

你可以编译它在Linux上是这样的:

g++ `pkg-config --cflags --libs sdl gl libpng` reproduce.cpp 

和Mac OS X这样的:

clang++ -framework OpenGL `pkg-config --cflags --libs sdl libpng` reproduce.cpp 

这里有一个512x256透明PNG图像可以保存为 “transparent.png” :

enter image description here

#include <cmath> 
#include <cstdio> 
#include <iostream> 
#include <png.h> 
#include <SDL.h> 
#include <SDL_main.h> 
#include <SDL_opengl.h> 
#include <stdexcept> 
#include <sstream> 

#define USE_VBO 1 

struct Pixmap { 
    int width; 
    int height; 
    const unsigned char* data; 
    GLenum format; 
}; 

Pixmap load_png(const std::string& path) 
{ 
    FILE* const file = fopen(path.c_str(), "rb"); 
    if (!file) 
     throw std::runtime_error("Unable to open " + path); 

    png_byte header[8]; 
    fread(header, 1, 8, file); 
    const bool is_png = !png_sig_cmp(header, 0, 8); 
    if (!is_png) 
     throw std::runtime_error(path + " is not a PNG"); 

    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, 
              NULL, NULL, NULL); 
    if (!png) 
     throw std::runtime_error("Failed to create png struct"); 

    png_infop info = png_create_info_struct(png); 
    if (!info) { 
     png_destroy_read_struct(&png, (png_infopp) NULL, (png_infopp) NULL); 
     throw std::runtime_error("Failed to create png info struct"); 
    } 

    png_infop info_end = png_create_info_struct(png); 
    if (!info_end) { 
     png_destroy_read_struct(&png, &info, (png_infopp) NULL); 
     throw std::runtime_error("Failed to create png info struct"); 
    } 

    if (setjmp(png_jmpbuf(png))) { 
     png_destroy_read_struct(&png, &info, &info_end); 
     throw std::runtime_error("Error from libpng"); 
    } 

    png_init_io(png, file); 
    png_set_sig_bytes(png, 8); 
    png_read_info(png, info); 

    int bit_depth; 
    int color_type; 
    png_uint_32 image_width, image_height; 
    png_get_IHDR(png, info, &image_width, &image_height, &bit_depth, 
       &color_type, NULL, NULL, NULL); 

    png_read_update_info(png, info); 

    GLenum format; 
    switch (color_type) { 

    case PNG_COLOR_TYPE_RGBA: 
     format = GL_RGBA; 
     break; 
    case PNG_COLOR_TYPE_RGB: 
     format = GL_RGB; 
     break; 
    default: 
     png_destroy_read_struct(&png, &info, &info_end); 
     std::ostringstream message_stream; 
     message_stream << "Unsupported PNG color type: " << color_type; 
     throw std::runtime_error(message_stream.str()); 
    } 

    const int row_bytes = png_get_rowbytes(png, info); 
    png_byte* image_data = new png_byte[row_bytes * image_height]; 
    png_bytep* row_pointers = new png_bytep[image_height]; 
    for (unsigned int i = 0; i < image_height; i++) 
     row_pointers[i] = image_data + i * row_bytes; 

    png_read_image(png, row_pointers); 

    png_destroy_read_struct(&png, &info, &info_end); 
    delete[] row_pointers; 
    fclose(file); 

    Pixmap pixmap; 
    pixmap.width = image_width; 
    pixmap.height = image_height; 
    pixmap.data = image_data; 
    pixmap.format = format; 
    return pixmap; 
} 

GLuint create_texture(Pixmap pixmap) 
{ 
    GLuint id; 
    glGenTextures(1, &id); 
    glBindTexture(GL_TEXTURE_2D, id); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexImage2D(GL_TEXTURE_2D, 0, pixmap.format, pixmap.width, 
       pixmap.height, 0, pixmap.format, GL_UNSIGNED_BYTE, 
       pixmap.data); 
    return id; 
} 

void draw_texture(const GLuint id, const int width, const int height) 
{ 
    glBindTexture(GL_TEXTURE_2D, id); 

#if USE_VBO 
    glEnableClientState(GL_VERTEX_ARRAY); 
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 

    const GLfloat texture_coordinates[] = {0, 0, 
              0, 1, 
              1, 1, 
              1, 0}; 
    glTexCoordPointer(2, GL_FLOAT, 0, texture_coordinates); 

    const GLfloat vertices[] = {0, 0, 
           0, height, 
           width, height, 
           width, 0}; 
    glVertexPointer(2, GL_FLOAT, 0, vertices); 

    const GLubyte indices[] = {0, 1, 2, 
           0, 2, 3}; 
    glDrawElements(GL_TRIANGLE_STRIP, 6, GL_UNSIGNED_BYTE, indices); 

    glDisableClientState(GL_VERTEX_ARRAY); 
    glDisableClientState(GL_TEXTURE_COORD_ARRAY); 
#else 
    glBegin(GL_QUADS); 

    glTexCoord2i(0, 0); 
    glVertex2i(0, 0); 

    glTexCoord2i(1, 0); 
    glVertex2i(width, 0); 

    glTexCoord2i(1, 1); 
    glVertex2i(width, height); 

    glTexCoord2i(0, 1); 
    glVertex2i(0, height); 

    glEnd(); 
#endif 
} 

int main(int argc, char* argv[]) 
{ 
    const int width = 512; 
    const int height = 256; 

    SDL_Init(SDL_INIT_VIDEO); 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 
    SDL_SetVideoMode(width, height, 0, SDL_OPENGL); 

    glEnable(GL_TEXTURE_2D); 
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
    glEnable(GL_BLEND); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    glOrtho(0, width, height, 0, -1, 1); 
    glMatrixMode(GL_MODELVIEW); 

    glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 
    glClear(GL_COLOR_BUFFER_BIT); 

    try { 
     Pixmap pixmap = load_png("transparent.png"); 
     GLuint texture = create_texture(pixmap); 
     draw_texture(texture, pixmap.width, pixmap.height); 
    } catch (std::exception& e) { 
     std::cerr << e.what() << std::endl; 
    } 

    SDL_GL_SwapBuffers(); 

    SDL_Event event; 
    for (;;) { 
     SDL_WaitEvent(&event); 
     if (event.type == SDL_QUIT) 
      return 0; 
    } 

    return 0; 
} 

回答

4

看到你使用一个简单的三角形带索引绘图为一个四方让我想知道,而事实上,这是你的问题。您的索引数组看起来像要绘制两个索引三角形而不是单个三角形条。因此,您绘制了一个带有6个顶点的三角形条,因此绘制了4个三角形,这意味着额外的三角形会以某种方式包裹在其他两个三角形之后并导致双重绘制,从而导致较暗的部分。

因此最简单的解决办法是改变GL_TRIANGLE_STRIPGL_TRIANGLES,但也许重新排序顶点/索引一点,否则你绘制你的三角形以顺时针方向,而你的1.3的四例使用逆时针顺序(它可能因为这与你的情况无关,但这首先是错误的做法,决不会忽视你的排序)。

但是你知道吗,它是两个三角形的三角形条,它只需要4个顶点。因此,根本不需要任何索引数组,只需使用旧的glDrawArrays并按顺序绘制顶点。但重新排序它们(三角形条使用锯齿形图案,因此从左到右,从上到下排列):

const GLfloat texture_coordinates[] = {0, 1, 
             0, 0, 
             1, 1, 
             1, 0}; 
glTexCoordPointer(2, GL_FLOAT, 0, texture_coordinates); 

const GLfloat vertices[] = {0, height, 
          0, 0, 
          width, height, 
          width, 0}; 
glVertexPointer(2, GL_FLOAT, 0, vertices); 

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); 
相关问题