239 lines
9.0 KiB
C++
239 lines
9.0 KiB
C++
#include "mesh.h"
|
|
|
|
|
|
Mesh::Mesh(float blockWidth): m_blockWidth(blockWidth)
|
|
{
|
|
|
|
}
|
|
|
|
Mesh::~Mesh()
|
|
{
|
|
glDeleteVertexArrays(1, &m_vao);
|
|
glDeleteBuffers(1, &m_vbo);
|
|
glDeleteBuffers(1, &m_ebo);
|
|
}
|
|
|
|
|
|
GLuint Mesh::addVertex(const TypedVertex &v)
|
|
{
|
|
m_vertices.push_back(v);
|
|
|
|
return GLuint(m_vertices.size() - 1);
|
|
}
|
|
|
|
GLuint Mesh::addTriangle(GLuint v1, GLuint v2, GLuint v3)
|
|
{
|
|
GLuint index = GLuint(m_indexes.size());
|
|
m_indexes.push_back(v1);
|
|
m_indexes.push_back(v2);
|
|
m_indexes.push_back(v3);
|
|
return index;
|
|
}
|
|
|
|
void Mesh::normalizeNormals()
|
|
{
|
|
for (uint i = 0; i < m_vertices.size(); i ++) {
|
|
float length = std::sqrt(m_vertices[i].normalX * m_vertices[i].normalX +
|
|
m_vertices[i].normalY * m_vertices[i].normalY +
|
|
m_vertices[i].normalZ * m_vertices[i].normalZ);
|
|
|
|
m_vertices[i].normalX /= length;
|
|
m_vertices[i].normalY /= length;
|
|
m_vertices[i].normalZ /= length;
|
|
}
|
|
}
|
|
|
|
void Mesh::removeDoubles()
|
|
{
|
|
if (!m_vertices.size()) {
|
|
return;
|
|
}
|
|
|
|
bool* done = new bool[m_vertices.size()]{false};
|
|
|
|
std::vector<uint> indexMap;
|
|
indexMap.resize(m_vertices.size());
|
|
std::vector<TypedVertex> newVertices;
|
|
std::vector<uint> newIndexes;
|
|
|
|
std::vector<uint> mergePosition;
|
|
std::vector<uint> mergeNormal;
|
|
uint sameVerticesCount = 0;
|
|
TypedVertex reference;
|
|
bool computeAverage;
|
|
|
|
for (uint vertexIndex = 0; vertexIndex < m_vertices.size(); vertexIndex++) {
|
|
if (done[vertexIndex]) {
|
|
continue;
|
|
}
|
|
sameVerticesCount = 1;
|
|
mergePosition.clear();
|
|
mergeNormal.clear();
|
|
computeAverage = true;
|
|
reference = m_vertices[vertexIndex];
|
|
|
|
for (uint otherVertexIndex = vertexIndex + 1; otherVertexIndex < m_vertices.size(); otherVertexIndex++) {
|
|
bool samePosition = std::abs(reference.x - m_vertices[otherVertexIndex].x) < 0.05f &&
|
|
std::abs(reference.y - m_vertices[otherVertexIndex].y) < 0.05f &&
|
|
std::abs(reference.z - m_vertices[otherVertexIndex].z) < 0.05f;
|
|
|
|
if (samePosition) {
|
|
float distanceBorderX = std::fmod(m_vertices[otherVertexIndex].x, m_blockWidth);
|
|
float distanceBorderY = std::fmod(m_vertices[otherVertexIndex].y, m_blockWidth);
|
|
float distanceBorderZ = std::fmod(m_vertices[otherVertexIndex].z, m_blockWidth);
|
|
|
|
bool isOnBorder = std::abs(distanceBorderX) < 0.05f || std::abs(distanceBorderY) < 0.05f || std::abs(distanceBorderZ) < 0.05f;
|
|
|
|
if (isOnBorder) {
|
|
m_vertices[vertexIndex].x = m_vertices[otherVertexIndex].x - (std::abs(distanceBorderX) < 0.05f ? distanceBorderX : 0);
|
|
m_vertices[vertexIndex].y = m_vertices[otherVertexIndex].y - (std::abs(distanceBorderY) < 0.05f ? distanceBorderY : 0);
|
|
m_vertices[vertexIndex].z = m_vertices[otherVertexIndex].z - (std::abs(distanceBorderZ) < 0.05f ? distanceBorderZ : 0);
|
|
computeAverage = false;
|
|
} else if (computeAverage) {
|
|
m_vertices[vertexIndex].x += m_vertices[otherVertexIndex].x;
|
|
m_vertices[vertexIndex].y += m_vertices[otherVertexIndex].y;
|
|
m_vertices[vertexIndex].z += m_vertices[otherVertexIndex].z;
|
|
}
|
|
|
|
mergePosition.push_back(otherVertexIndex);
|
|
|
|
float dotProduct = reference.normalX * m_vertices[otherVertexIndex].normalX +
|
|
reference.normalY * m_vertices[otherVertexIndex].normalY +
|
|
reference.normalZ * m_vertices[otherVertexIndex].normalZ;
|
|
|
|
if (m_vertices[otherVertexIndex].biome == reference.biome && dotProduct > float(std::cos(45 * M_PI / 180))) {
|
|
|
|
// TODO: Pondérer la moyenne des normals
|
|
m_vertices[vertexIndex].normalX += m_vertices[otherVertexIndex].normalX;
|
|
m_vertices[vertexIndex].normalY += m_vertices[otherVertexIndex].normalY;
|
|
m_vertices[vertexIndex].normalZ += m_vertices[otherVertexIndex].normalZ;
|
|
|
|
sameVerticesCount++;
|
|
|
|
mergeNormal.push_back(otherVertexIndex);
|
|
done[otherVertexIndex] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (computeAverage) {
|
|
m_vertices[vertexIndex].x /= (mergePosition.size() + 1);
|
|
m_vertices[vertexIndex].y /= (mergePosition.size() + 1);
|
|
m_vertices[vertexIndex].z /= (mergePosition.size() + 1);
|
|
}
|
|
|
|
m_vertices[vertexIndex].normalX /= (mergeNormal.size() + 1);
|
|
m_vertices[vertexIndex].normalY /= (mergeNormal.size() + 1);
|
|
m_vertices[vertexIndex].normalZ /= (mergeNormal.size() + 1);
|
|
|
|
indexMap[vertexIndex] = uint(newVertices.size());
|
|
newVertices.push_back(m_vertices[vertexIndex]);
|
|
|
|
for (uint mergePositionIndex: mergePosition) {
|
|
m_vertices[mergePositionIndex].x = m_vertices[vertexIndex].x;
|
|
m_vertices[mergePositionIndex].y = m_vertices[vertexIndex].y;
|
|
m_vertices[mergePositionIndex].z = m_vertices[vertexIndex].z;
|
|
}
|
|
|
|
for (uint mergedIndex: mergeNormal) {
|
|
m_vertices[mergedIndex].normalX = m_vertices[vertexIndex].normalX;
|
|
m_vertices[mergedIndex].normalY = m_vertices[vertexIndex].normalY;
|
|
m_vertices[mergedIndex].normalZ = m_vertices[vertexIndex].normalZ;
|
|
|
|
indexMap[mergedIndex] = uint(newVertices.size()) - 1;
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < m_indexes.size(); i += 3) {
|
|
uint i1 = indexMap[m_indexes[i]];
|
|
uint i2 = indexMap[m_indexes[i + 1]];
|
|
uint i3 = indexMap[m_indexes[i + 2]];
|
|
|
|
if (i1 != i2 && i2 != i3 && i3 != i1) {
|
|
newIndexes.push_back(i1);
|
|
newIndexes.push_back(i2);
|
|
newIndexes.push_back(i3);
|
|
}
|
|
}
|
|
|
|
m_vertices = newVertices;
|
|
m_indexes = newIndexes;
|
|
|
|
}
|
|
|
|
std::vector<GLuint>& Mesh::indexes()
|
|
{
|
|
return m_indexes;
|
|
}
|
|
|
|
std::vector<TypedVertex>& Mesh::vertices()
|
|
{
|
|
return m_vertices;
|
|
}
|
|
|
|
void Mesh::initGl(Shader* meshProgram, Shader* normalProgram)
|
|
{
|
|
initializeOpenGLFunctions();
|
|
glGenVertexArrays(1, &m_vao);
|
|
glGenBuffers(1, &m_vbo);
|
|
glGenBuffers(1, &m_ebo);
|
|
|
|
m_meshProgram = meshProgram;
|
|
m_normalProgram = normalProgram;
|
|
|
|
int locationPos = m_meshProgram->attributeLocation("in_position");
|
|
int locationNormal = m_meshProgram->attributeLocation("in_normal");
|
|
int locationBiome = m_meshProgram->attributeLocation("in_biome");
|
|
|
|
glBindVertexArray(m_vao);
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
|
glVertexAttribPointer(GLuint(locationPos), 3, GL_FLOAT, GL_FALSE, sizeof(TypedVertex), reinterpret_cast<void *>(offsetof(TypedVertex, x)));
|
|
glEnableVertexAttribArray(GLuint(locationPos));
|
|
|
|
glVertexAttribPointer(GLuint(locationNormal), 3, GL_FLOAT, GL_FALSE, sizeof(TypedVertex), reinterpret_cast<void *>(offsetof(TypedVertex, normalX)));
|
|
glEnableVertexAttribArray(GLuint(locationNormal));
|
|
|
|
glVertexAttribIPointer(GLuint(locationBiome), 1, GL_UNSIGNED_INT, sizeof(TypedVertex), reinterpret_cast<void *>(offsetof(TypedVertex, biome)));
|
|
glEnableVertexAttribArray(GLuint(locationBiome));
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
glBindVertexArray(0);
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
|
|
glBufferData(GL_ARRAY_BUFFER,
|
|
GLsizei(m_vertices.size() * sizeof(TypedVertex)),
|
|
m_vertices.data(),
|
|
GL_STATIC_DRAW);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
|
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER,
|
|
GLsizei(m_indexes.size() * sizeof(GLuint)),
|
|
m_indexes.data(),
|
|
GL_STATIC_DRAW);
|
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
}
|
|
|
|
void Mesh::render(QMatrix4x4 &model)
|
|
{
|
|
QMatrix3x3 normalMatrix = model.normalMatrix();
|
|
m_meshProgram->bind();
|
|
glUniformMatrix3fv(m_meshProgram->uniformLocation("u_normalMatrix"), 1, GL_FALSE, normalMatrix.data());
|
|
glUniformMatrix4fv(m_meshProgram->uniformLocation("u_model"), 1, GL_FALSE, model.data());
|
|
glBindVertexArray(m_vao);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
|
|
glDrawElements(GL_TRIANGLES, GLsizei(m_indexes.size()), GL_UNSIGNED_INT, reinterpret_cast<void *>(0));
|
|
glBindVertexArray(0);
|
|
m_meshProgram->release();
|
|
}
|
|
|
|
void Mesh::renderNormals(QMatrix4x4 &model)
|
|
{
|
|
QMatrix3x3 normalMatrix = model.normalMatrix();
|
|
m_normalProgram->bind();
|
|
glUniformMatrix3fv(m_meshProgram->uniformLocation("u_normalMatrix"), 1, GL_FALSE, normalMatrix.data());
|
|
glUniformMatrix4fv(m_meshProgram->uniformLocation("u_model"), 1, GL_FALSE, model.data());
|
|
glBindVertexArray(m_vao);
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_ebo);
|
|
glDrawElements(GL_POINTS, GLsizei(m_indexes.size()), GL_UNSIGNED_INT, reinterpret_cast<void *>(0));
|
|
glBindVertexArray(0);
|
|
m_normalProgram->release();
|
|
}
|