У меня возникают некоторые проблемы при рендеринге некоторых обработанных процедурами сеток. Есть некоторые действительно странные артефакты при рендеринге высокоточечных подсчетов (не так много актуальных). Я смог изолировать проблему, но я понятия не имею, почему это происходит. Когда я создаю сетку с низким полигоном, проблема не возникает.Артефакты рендеринга высокополигональных процедурных сеток с 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;
}
В результате при визуализации с низким содержанием поли:
Результат при визуализации high-poly:
И вы можете скачать источник демо здесь: