2014-11-21 2 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

Результат при визуализации high-poly:

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 должно быть количество индексов, а не размер в байтах. Таким образом, значение аргумента в 4 раза слишком велико.

Вы, вероятно, захотите установить переменную-член к только число индексов:

_indicesSize = indices.size(); 

, но будьте осторожны, что вы все-таки передать размер в байтах gBufferData().

Другая проблема заключается в том, что, по крайней мере, в части отправленного кода вы никогда не включаете проверку глубины. Вам нужно будет сделать это где-то во время инициализации:

glEnable(GL_DEPTH_TEST); 
Смежные вопросы