SparrowRenderer/sphere.cpp
2015-07-06 21:46:17 +02:00

109 lines
3.1 KiB
C++

#include "sphere.h"
#define M_PI 3.14159265358979323846
#define MAGIC_RATIO 0.37139f
Sphere::Sphere(int n)
{
// 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
addFace(0, top+i, top+offset);
// bottom cap
addFace(6, bottom+offset, bottom+i);
// middle ribbon
addFace(top+i, bottom+i, top+offset);
addFace(top+offset, bottom+i, bottom+offset);
}
// geodesic subdivisions :
for(int i=0; i<n; i++){
edges = new Edge[vertices.size()-1];
int nb_triangles = indices.size()/3;
for(int j=0; j<nb_triangles; j++)
{
int vid[3];
for(int k=0; k<3; k++)
{
int idA = indices[j*3 + k];
int idB = 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++)
addFace(indices[j*3 + k], vid[k], vid[(k+2)%3]);
addFace(vid[0], vid[1], vid[2]);
}
delete[](edges);
indices.erase(indices.begin(), indices.begin()+nb_triangles*3);
}
}
int Sphere::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)
{
// creating subdivision vertex
Vertex v;
Vertex v0 = vertices[a];
Vertex v1 = vertices[b];
v.position = glm::normalize((v0.position + v1.position)/2.f);
v.normal = v.position;
// u/v sphériques, cohérents sur toute la sphère sauf des artefacts au niveau des u==0
float newU = (v.position.x < 0 ? 1.5f : 1.f) + atan(v.position.z/v.position.x)/(2*M_PI);
float newV = acos(v.position.y)/M_PI;
v.texCoord = glm::vec2(newU - floor(newU), newV);
// alternative, u/v moyennés :
//v.texCoord = (v0.texCoord + v1.texCoord)/2.f;
vid = vertices.size();
addVertex(v);
// 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 Sphere::createVertex(float u, float v)
{
Vertex vert;
vert.position = glm::vec3(cos(u*2*M_PI)*sin(v*M_PI),
cos(v*M_PI),
sin(u*2*M_PI)*sin(v*M_PI));
vert.normal = vert.position;
vert.texCoord = glm::vec2(u, v);
addVertex(vert);
}