2014-11-21 16 views
-1

我在渲染某些程序生成的網格時遇到了一些問題。渲染高聚合網格物體時會出現一些非常奇怪的工件(並非如此)。我已經能夠找出問題,但我不知道爲什麼會發生這種情況。當我生成一個低多邊形網格時,問題不會發生。使用OpenGL渲染高聚程序網格的工件

我創建了一個小的演示,所以你可以下載源代碼。 (見下)

當我的應用程序中,當網格約爲〜90個三角形(120個頂點和270個索引)時,這些工件開始出現。要看到它出現在演示中,請將initMesh設置爲150個環和150個扇區。

它就像一個星期我正在這個工作,我只是不能說明爲什麼發生這種情況。它會是什麼?

這裏是我的目類:

#include "Mesh.h" 

Mesh::Mesh() 
{ 
    _vao = 0; 

    _verticesVbo = 0; 
    _texCoordsVbo = 0; 
    _normalsVbo = 0; 
    _indicesVbo = 0; 
} 

Mesh::~Mesh() 
{ 
    glDeleteBuffers(1, &_verticesVbo); 
    glDeleteBuffers(1, &_texCoordsVbo); 
    glDeleteBuffers(1, &_normalsVbo); 
    glDeleteBuffers(1, &_indicesVbo); 
    glDeleteVertexArrays(1, &_vao); 
} 

Mesh* Mesh::New(vector<Vertex> &vertices, vector<GLuint> &indices) 
{ 
    Mesh* mesh = new Mesh(); 
    mesh->AddVertices(vertices, indices); 
    return mesh; 
} 

void Mesh::AddVertices(vector<Vertex> &vertices, vector<GLuint> &indices) 
{ 
    _vertices = vertices; 
    _indices = indices; 

    GLuint verticesSize = vertices.size() * 3 * sizeof(GLfloat); 
    GLuint texCoordsSize = vertices.size() * 2 * sizeof(GLfloat); 
    GLuint normalsSize = vertices.size() * 3 * sizeof(GLfloat); 
    _indicesSize = indices.size() * sizeof(GLuint); 

    GLfloat* vertexBuffer = new GLfloat[vertices.size() * 3]; 
    GLfloat* texCoordBuffer = new GLfloat[vertices.size() * 2]; 
    GLfloat* normalBuffer = new GLfloat[vertices.size() * 3]; 

    CreateBuffers(vertices, vertexBuffer, texCoordBuffer, normalBuffer); 

    glGenVertexArrays(1, &_vao); 
    glBindVertexArray(_vao); 

    glGenBuffers(1, &_verticesVbo); 
    glBindBuffer(GL_ARRAY_BUFFER, _verticesVbo); 
    glBufferData(GL_ARRAY_BUFFER, verticesSize, vertexBuffer, GL_STATIC_DRAW); 

    glGenBuffers(1, &_texCoordsVbo); 
    glBindBuffer(GL_ARRAY_BUFFER, _texCoordsVbo); 
    glBufferData(GL_ARRAY_BUFFER, texCoordsSize, texCoordBuffer, GL_STATIC_DRAW); 

    glGenBuffers(1, &_normalsVbo); 
    glBindBuffer(GL_ARRAY_BUFFER, _normalsVbo); 
    glBufferData(GL_ARRAY_BUFFER, normalsSize, normalBuffer, GL_STATIC_DRAW); 

    glGenBuffers(1, &_indicesVbo); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indicesVbo); 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indicesSize, &indices[0], GL_STATIC_DRAW); 

    delete[] vertexBuffer; 
    delete[] texCoordBuffer; 
    delete[] normalBuffer; 
} 

void Mesh::CreateBuffers(vector<Vertex> &vertices, 
         GLfloat* &vertexBuffer, 
         GLfloat* &texCoordBuffer, 
         GLfloat* &normalBuffer) 
{ 
    vector<Vertex>::iterator i; 
    unsigned int vIndex = 0; 
    unsigned int tIndex = 0; 
    unsigned int nIndex = 0; 

    for (i = vertices.begin(); i != vertices.end(); ++i) 
    { 
     Vertex vertex = *i; 

     GLfloat x = vertex.GetPosition().x; 
     GLfloat y = vertex.GetPosition().y; 
     GLfloat z = vertex.GetPosition().z; 

     GLfloat u = vertex.GetTexCoord().x; 
     GLfloat v = vertex.GetTexCoord().y; 

     GLfloat r0 = vertex.GetNormal().x; 
     GLfloat s0 = vertex.GetNormal().y; 
     GLfloat t0 = vertex.GetNormal().z; 

     vertexBuffer[vIndex++] = x; 
     vertexBuffer[vIndex++] = y; 
     vertexBuffer[vIndex++] = z; 

     texCoordBuffer[tIndex++] = u; 
     texCoordBuffer[tIndex++] = v; 

     normalBuffer[nIndex++] = r0; 
     normalBuffer[nIndex++] = s0; 
     normalBuffer[nIndex++] = t0; 
    } 
} 

void Mesh::Render() 
{ 
    glEnableVertexAttribArray(0); 
    glBindBuffer(GL_ARRAY_BUFFER, _verticesVbo); 
    glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); 

    glEnableVertexAttribArray(1); 
    glBindBuffer(GL_ARRAY_BUFFER, _texCoordsVbo); 
    glVertexAttribPointer((GLuint)1, 2, GL_FLOAT, GL_FALSE, 0, 0); 

    glEnableVertexAttribArray(2); 
    glBindBuffer(GL_ARRAY_BUFFER, _normalsVbo); 
    glVertexAttribPointer((GLuint)2, 3, GL_FLOAT, GL_FALSE, 0, 0); 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indicesVbo); 
    glDrawElements(GL_TRIANGLES, _indicesSize, GL_UNSIGNED_INT, 0); 

    glDisableVertexAttribArray(0); 
    glDisableVertexAttribArray(1); 
    glDisableVertexAttribArray(2); 
} 

這裏的代碼來創建網格:

void initMesh(float radius, int rings, int sectors) 
{ 
    float piOver2 = M_PI * 0.5f; 

    vector<Vertex> vertices; 
    vector<unsigned int> indices; 

    float const R = 1.0f/(float)(rings); 
    float const S = 1.0f/(float)(sectors); 
    unsigned int r, s; 

    for(r = 0; r < rings + 1; r++) 
    { 
     for(s = 0; s < sectors + 1; s++) 
     { 
      float y = sin(piOver2 * r * R); 
      float x = cos(2.0 * M_PI * s * S) * sin(piOver2 + piOver2 * r * R); 
      float z = sin(2.0 * M_PI * s * S) * sin(piOver2 + piOver2 * r * R); 

      vec3 position = vec3(x, y, z) * radius; 
      vec3 normal = normalize(vec3(x, y, z)) * radius; 
      vec2 texCoord = vec2(s * R, r * R) * radius; 

      vertices.push_back(Vertex(position, texCoord, normal)); 
     } 
    } 

    for(r = 0; r < rings; r++) 
    { 
     for(s = 0; s < sectors; s++) 
     { 
      int a = r * (sectors + 1) + s; 
      int b = (r + 1) * (sectors + 1) + s; 
      int c = (r + 1) * (sectors + 1) + (s + 1); 
      int d = r * (sectors + 1) + (s + 1); 

      indices.push_back(a); 
      indices.push_back(b); 
      indices.push_back(c); 

      indices.push_back(c); 
      indices.push_back(d); 
      indices.push_back(a); 
     } 
    } 

    _mesh = Mesh::New(vertices, indices); 
} 

這裏是初始化的OpenGL代碼:

bool createGLWindow() 
{ 
    _window = SDL_CreateWindow(
     "TestMesh", 
     SDL_WINDOWPOS_CENTERED, 
     SDL_WINDOWPOS_CENTERED, 
     1024, 
     768, 
     SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL); 

    if(_window == NULL) 
    { 
     LOG("Window could not be created! SDL_Error: " << SDL_GetError()); 
     return false; 
    } 

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); 
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); 
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); 

    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); 
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); 
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); 
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); 
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); 

    _glContext = SDL_GL_CreateContext(_window); 

    if (!_glContext) 
    { 
     LOG("Could not create context:" << SDL_GetError()); 
     return false; 
    } 

    glewExperimental = GL_TRUE; 

    GLenum glewInitStatus = glewInit(); 

    if(glewInitStatus != GLEW_OK) 
    { 
     LOG("Error" << glewGetErrorString(glewInitStatus)) 
      return false; 
    } 

    return true; 
} 

這裏渲染功能:

void render() 
{ 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

    _shader->Bind(); 
    _shader->GetUniform("mvp").Set(_projectionMatrix * _viewMatrix * _modelMatrix); 
    _shader->GetUniform("color").Set(_color); 
    _mesh->Render(); 
    _shader->Unbind(); 
} 

而這些頂點着色器

#version 330 

in vec3 inPosition; 
in vec2 inTexCoord; 
in vec3 inNormal; 

uniform mat4 mvp; 

out vec3 fragPosition; 
out vec2 fragTexCoord; 
out vec3 fragNormal; 

void main() 
{ 
    gl_Position = mvp * vec4(inPosition, 1.0); 

    fragTexCoord = inTexCoord; 
    fragPosition = inPosition; 
    fragNormal = inNormal; 
} 

和片段着色器:

#version 330 

uniform vec4 color; 

in vec3 fragPosition; 
in vec2 fragTexCoord; 
in vec3 fragNormal; 

out vec4 fragColor; 

void main(void) 
{ 
    vec3 lightPos = vec3(1.0, 1.0, 1.0); 
    fragColor = max(dot(lightPos, fragNormal), 0.0) * 0.8 * color + color * 0.1; 
} 

呈現低聚當其結果是:在呈現時

No artifacts

結果高聚物:

enter image description here

而且你可以在這裏下載演示來源:

demo + source code

回答

1

中有用於索引緩衝區大小的單位不一致。在AddVertices()方法,這個計算大小的以字節爲單位:

_indicesSize = indices.size() * sizeof(GLuint); 

它然後被用於正確地在後面的方法相同的方法作爲參數傳遞給glBufferData(),這確實需要以字節爲單位的大小:

glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indicesSize, &indices[0], GL_STATIC_DRAW); 

但它也可用於在Render()方法作爲參數傳遞給glDrawElements()

glDrawElements(GL_TRIANGLES, _indicesSize, GL_UNSIGNED_INT, 0); 

在這種情況下,該值通ed in需要是索引號,而不是以字節爲單位的大小。所以論證的價值是4倍太大。

你可能要設置的成員變量只是索引的數量:

_indicesSize = indices.size(); 

但要小心,你仍然以字節爲單位通過大小gBufferData()

另一個問題是,至少在發佈的代碼部分中,您從未啓用深度測試。在初始化過程中,您需要在某處執行此操作:

glEnable(GL_DEPTH_TEST);