154 lines
4.6 KiB
C++
154 lines
4.6 KiB
C++
#include "parametricmesh.h"
|
|
#include "glm/ext.hpp"
|
|
#include "pbrmaterial.h"
|
|
|
|
#define M_PI 3.14159265358979323846
|
|
#define MAGIC_RATIO 0.37139f
|
|
|
|
Mesh* MeshGenerator::generateParametricMesh(Material* mat, int width, int height, float size, bool alternate)
|
|
{
|
|
m_size = size;
|
|
m_mesh = new Mesh("parametric_mesh");
|
|
m_mesh->setMaterial(mat);
|
|
|
|
for(int i=0; i<=width; ++i)
|
|
{
|
|
for(int j=0; j<=height; ++j)
|
|
{
|
|
createVertex(float(i)/float(width), float(j)/float(height));
|
|
if(i > 0 && j > 0)
|
|
{
|
|
if(alternate && (i+j)%2)
|
|
{
|
|
m_mesh->addTriangle(getVertexId(i, j, height),
|
|
getVertexId(i, j-1, height),
|
|
getVertexId(i-1, j, height));
|
|
m_mesh->addTriangle(getVertexId(i-1, j-1, height),
|
|
getVertexId(i-1, j, height),
|
|
getVertexId(i, j-1, height));
|
|
}
|
|
else
|
|
{
|
|
m_mesh->addTriangle(getVertexId(i, j, height),
|
|
getVertexId(i-1, j-1, height),
|
|
getVertexId(i-1, j, height));
|
|
m_mesh->addTriangle(getVertexId(i, j, height),
|
|
getVertexId(i, j-1, height),
|
|
getVertexId(i-1, j-1, height));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return m_mesh;
|
|
}
|
|
|
|
Mesh* MeshGenerator::generateGeodesicMesh(Material* mat, int n, float size)
|
|
{
|
|
m_size = size;
|
|
m_mesh = new Mesh("geodesic_mesh");
|
|
m_mesh->setMaterial(mat);
|
|
|
|
// icosahedron :
|
|
|
|
// top cap
|
|
createVertex(0, 1);
|
|
for(int i=0; i<5; i++)
|
|
createVertex(i/5.f, 1-MAGIC_RATIO);
|
|
|
|
// bottom cap
|
|
createVertex(0, 0);
|
|
for(int i=0; i<5; i++)
|
|
createVertex((i+0.5f)/5.f, MAGIC_RATIO);
|
|
|
|
// Compute faces
|
|
for(int i=0; i<5; i++){
|
|
int top = 1;
|
|
int bottom = 7;
|
|
int offset = (i+1)%5;
|
|
// top cap
|
|
m_mesh->addTriangle(0, top+offset, top+i);
|
|
// bottom cap
|
|
m_mesh->addTriangle(6, bottom+i, bottom+offset);
|
|
// middle ribbon
|
|
m_mesh->addTriangle(top+i, top+offset, bottom+i);
|
|
m_mesh->addTriangle(top+offset, bottom+offset, bottom+i);
|
|
}
|
|
|
|
// geodesic subdivisions :
|
|
for(int i=0; i<n; i++)
|
|
subdivide();
|
|
|
|
return m_mesh;
|
|
}
|
|
|
|
void MeshGenerator::createVertex(float u, float v)
|
|
{
|
|
m_mesh->addVertex(evalUV(u, v)*m_size, glm::vec2(u, v));
|
|
}
|
|
|
|
int MeshGenerator::getEdge(int a, int b)
|
|
{
|
|
Edge* current = edges+a;
|
|
int vid = -1;
|
|
while(vid == -1)
|
|
{
|
|
if(current->b == b)
|
|
vid = current->vertex;
|
|
else if(current->next == NULL)
|
|
{
|
|
vid = m_mesh->m_positions3D.size();
|
|
// creating subdivision vertex
|
|
|
|
// u/v sphériques, cohérents sur toute la sphère sauf des artefacts au niveau des u==0
|
|
glm::vec3 pos = glm::normalize((m_mesh->m_positions3D[a] + m_mesh->m_positions3D[b]) / 2.f);
|
|
float newU = (pos.x < 0 ? 1.5f : 1.f) + atan(pos.z/pos.x)/(2*M_PI);
|
|
float newV = acos(pos.y)/M_PI;
|
|
// alternative, u/v moyennés :
|
|
/*float newU = (m_mesh->texCoords[a].x + m_mesh->texCoords[b].x) / 2.f;
|
|
float newV = (m_mesh->texCoords[a].y + m_mesh->texCoords[b].y) / 2.f;*/
|
|
createVertex(-(newU - floor(newU)), newV);
|
|
|
|
// inserting the new vertex in the edge collection
|
|
if(current->b == -1)
|
|
{
|
|
current->vertex = vid;
|
|
current->b = b;
|
|
}
|
|
else
|
|
current->next = new Edge(b, vid);
|
|
}
|
|
else
|
|
current = current->next;
|
|
}
|
|
return vid;
|
|
}
|
|
|
|
void MeshGenerator::subdivide()
|
|
{
|
|
edges = new Edge[m_mesh->m_positions3D.size()-1];
|
|
int nb_triangles = m_mesh->m_indices.size()/3;
|
|
for(int j=0; j<nb_triangles; j++)
|
|
{
|
|
int vid[3];
|
|
for(int k=0; k<3; k++)
|
|
{
|
|
int idA = m_mesh->m_indices[j*3 + k];
|
|
int idB = m_mesh->m_indices[j*3 + (k+1)%3];
|
|
int a = idA < idB ? idA : idB;
|
|
int b = idA > idB ? idA : idB;
|
|
vid[k] = getEdge(a, b);
|
|
}
|
|
for(int k=0; k<3; k++)
|
|
m_mesh->addTriangle(m_mesh->m_indices[j*3 + k], vid[k], vid[(k+2)%3]);
|
|
m_mesh->addTriangle(vid[0], vid[1], vid[2]);
|
|
}
|
|
delete[](edges);
|
|
m_mesh->m_indices.erase(m_mesh->m_indices.begin(), m_mesh->m_indices.begin()+nb_triangles*3);
|
|
}
|
|
|
|
int MeshGenerator::getVertexId(int i, int j, int height)
|
|
{
|
|
return i*(height+1) + j;
|
|
}
|