2014-11-21 1 views
-1

절차 적으로 생성 된 메쉬를 렌더링 할 때 몇 가지 문제가 있습니다. 높은 폴리 카운트 메쉬를 렌더링 할 때 (실제로는 그렇게 많지는 않음) 일부 실제적으로 이상한 아티팩트가 있습니다. 문제를 격리 할 수 ​​있었지만 왜 이런 일이 일어나는지 알 수 없습니다. 낮은 폴리 메쉬를 생성 할 때 문제가 발생하지 않습니다.OpenGL을 사용하여 고 폴리 프로 시저 메쉬를 렌더링하는 아티클

작은 데모를 만들었으므로 소스를 다운로드 할 수 있습니다. (아래 참조)

이러한 아티팩트는 대략 90 개의 삼각형 (120 개의 꼭지점과 270 개의 인덱스)이 나타날 때부터 시작됩니다. 데모에 나타나는 것을 보려면 initMesh를 150 개의 링과 150 개의 섹터로 설정하십시오.

일주일 내내이 일을하고 있으며 왜 이런 일이 일어나고 있는지 이유는 없습니다. 그것은 무엇 일 수 있는가? 여기

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; 
} 

렌더링 : OpenGL을 초기화하는 코드 여기

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); 
} 

됩니다 : 여기

#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); 
} 

메쉬를 생성하는 코드 : 여기

내 메쉬 클래스 기능 :

,831,526,623,210

그리고 이러한 버텍스 셰이더를

#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() 방법에서는,이 바이트 크기를 계산한다

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

:

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

그것은 나중에 바이트 크기 필요한가 glBufferData()의 인수와 동일한 방법으로 올바르게 사용 그러나 그것은 또한 glDrawElements()의 인수로 Render() 방법에 사용 :

이때
glDrawElements(GL_TRIANGLES, _indicesSize, GL_UNSIGNED_INT, 0); 

를 값 통과 에이드가 인 숫자 이어야하며 크기는 바이트가 아닙니다. 따라서 인수의 가치는 4 배가됩니다.

_indicesSize = indices.size(); 

하지만 여전히 gBufferData() 바이트의 크기를 통과 않도록주의 :

당신은 아마 멤버 변수에 지수의 단지 수를 설정하는 것이 좋습니다.

또 다른 문제는 적어도 게시 된 코드 부분에서 절대로 깊이 테스트를 사용하지 않는다는 것입니다. 초기화하는 동안 어딘가에해야합니다 :

glEnable(GL_DEPTH_TEST);