feat: subdivide isosphere
https://schneide.blog/2016/07/15/generating-an-icosphere-in-c/
This commit is contained in:
parent
74ccc647f4
commit
a444deb51a
|
@ -1,32 +1,46 @@
|
||||||
#include "icosphere.hpp"
|
#include "icosphere.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <array>
|
||||||
|
|
||||||
Icosphere::Icosphere(int subdivisions)
|
Icosphere::Icosphere(int subdivisions)
|
||||||
{
|
{
|
||||||
|
VertexList vertices = _isocahedronVertices;
|
||||||
|
TriangleList triangles = _isocahedronTriangles;
|
||||||
|
for (int i = 0; i < subdivisions; i++)
|
||||||
|
{
|
||||||
|
triangles = subdivide(vertices, triangles);
|
||||||
|
}
|
||||||
|
std::cout <<
|
||||||
|
"subdivisions: " << subdivisions <<
|
||||||
|
" vertices: " << vertices.size() <<
|
||||||
|
" triangles: " << triangles.size() << std::endl;
|
||||||
|
|
||||||
glGenVertexArrays(1, &_vao);
|
glGenVertexArrays(1, &_vao);
|
||||||
glGenBuffers(1, &_vbo);
|
glGenBuffers(1, &_vbo);
|
||||||
glGenBuffers(1, &_ebo);
|
glGenBuffers(1, &_ebo);
|
||||||
|
|
||||||
glBindVertexArray(_vao);
|
glBindVertexArray(_vao);
|
||||||
|
|
||||||
for (const auto& v : _isocahedronVertices)
|
for (const auto& v : vertices)
|
||||||
{
|
{
|
||||||
_vertices.push_back(v[0]);
|
_vertices.push_back(v[0]);
|
||||||
_vertices.push_back(v[1]);
|
_vertices.push_back(v[1]);
|
||||||
_vertices.push_back(v[2]);
|
_vertices.push_back(v[2]);
|
||||||
}
|
}
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
|
||||||
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(float), &_vertices[0], GL_STATIC_DRAW);
|
size_t vboBufferSize = _vertices.size() * sizeof(float);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, vboBufferSize, &_vertices[0], GL_STATIC_DRAW);
|
||||||
|
|
||||||
for (const auto& tri : _isocahedronTriangles)
|
for (const auto& tri : triangles)
|
||||||
{
|
{
|
||||||
_indices.push_back(tri.vertex[0]);
|
_indices.push_back(tri.vertex[0]);
|
||||||
_indices.push_back(tri.vertex[1]);
|
_indices.push_back(tri.vertex[1]);
|
||||||
_indices.push_back(tri.vertex[2]);
|
_indices.push_back(tri.vertex[2]);
|
||||||
}
|
}
|
||||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _ebo);
|
||||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, _indices.size() * sizeof(unsigned int), &_indices[0], GL_STATIC_DRAW);
|
size_t egoBufferSize = _indices.size() * sizeof(unsigned int);
|
||||||
|
glBufferData(GL_ELEMENT_ARRAY_BUFFER, egoBufferSize, &_indices[0], GL_STATIC_DRAW);
|
||||||
|
|
||||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
@ -36,6 +50,59 @@ Icosphere::Icosphere(int subdivisions)
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Icosphere::vertexForEdge(Lookup& lookup, VertexList& vertices, int first, int second)
|
||||||
|
{
|
||||||
|
Lookup::key_type key(first, second);
|
||||||
|
// Normalize edge directions so that we don't store edges twice
|
||||||
|
if (key.first > key.second)
|
||||||
|
{
|
||||||
|
std::swap(key.first, key.second);
|
||||||
|
}
|
||||||
|
|
||||||
|
// .insert returns a pair with a pointer to the newly-inserted (or already
|
||||||
|
// existing) element in the lookup as the first element and a boolean
|
||||||
|
// indicating a successful new insertion as the second.
|
||||||
|
auto inserted = lookup.insert({key, vertices.size()});
|
||||||
|
|
||||||
|
// If the insertion was successful - i.e this is a newly inserted element
|
||||||
|
if (inserted.second)
|
||||||
|
{
|
||||||
|
// Two vectors determined by two existing points
|
||||||
|
auto& edge0 = vertices[first];
|
||||||
|
auto& edge1 = vertices[second];
|
||||||
|
// Combine and normalize the vectors to get the halfway point on the
|
||||||
|
// unit sphere.
|
||||||
|
auto point = normalize(edge0 + edge1);
|
||||||
|
vertices.push_back(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inserted.first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
Icosphere::TriangleList Icosphere::subdivide(VertexList& vertices, TriangleList triangles)
|
||||||
|
{
|
||||||
|
Lookup lookup;
|
||||||
|
TriangleList result;
|
||||||
|
|
||||||
|
for (auto&& triangle : triangles)
|
||||||
|
{
|
||||||
|
std::array<int, 3> mid;
|
||||||
|
for (int edge = 0; edge < 3; edge++)
|
||||||
|
{
|
||||||
|
mid[edge] = vertexForEdge(lookup, vertices,
|
||||||
|
triangle.vertex[edge], triangle.vertex[(edge + 1) % 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create four new triangles from the original triangle
|
||||||
|
result.push_back({triangle.vertex[0], mid[0], mid[2]});
|
||||||
|
result.push_back({triangle.vertex[1], mid[1], mid[0]});
|
||||||
|
result.push_back({triangle.vertex[2], mid[2], mid[1]});
|
||||||
|
result.push_back({mid[0], mid[1], mid[2]});
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
void Icosphere::render()
|
void Icosphere::render()
|
||||||
{
|
{
|
||||||
glBindVertexArray(_vao);
|
glBindVertexArray(_vao);
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include <GL/glew.h>
|
#include <GL/glew.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include "glm/glm.hpp"
|
#include "glm/glm.hpp"
|
||||||
|
|
||||||
|
@ -22,12 +23,12 @@ private:
|
||||||
std::vector<float> _vertices;
|
std::vector<float> _vertices;
|
||||||
std::vector<unsigned int> _indices;
|
std::vector<unsigned int> _indices;
|
||||||
|
|
||||||
struct IcoTriangle
|
struct Triangle
|
||||||
{
|
{
|
||||||
unsigned int vertex[3];
|
int vertex[3];
|
||||||
};
|
};
|
||||||
|
|
||||||
using IcoTriangleList = std::vector<IcoTriangle>;
|
using TriangleList = std::vector<Triangle>;
|
||||||
using VertexList = std::vector<glm::vec3>;
|
using VertexList = std::vector<glm::vec3>;
|
||||||
|
|
||||||
const float X=.525731112119133606f;
|
const float X=.525731112119133606f;
|
||||||
|
@ -41,11 +42,16 @@ private:
|
||||||
{Z,X,N}, {-Z,X, N}, {Z,-X,N}, {-Z,-X, N}
|
{Z,X,N}, {-Z,X, N}, {Z,-X,N}, {-Z,-X, N}
|
||||||
};
|
};
|
||||||
|
|
||||||
const IcoTriangleList _isocahedronTriangles =
|
const TriangleList _isocahedronTriangles =
|
||||||
{
|
{
|
||||||
{0,4,1},{0,9,4},{9,5,4},{4,5,8},{4,8,1},
|
{0,4,1},{0,9,4},{9,5,4},{4,5,8},{4,8,1},
|
||||||
{8,10,1},{8,3,10},{5,3,8},{5,2,3},{2,7,3},
|
{8,10,1},{8,3,10},{5,3,8},{5,2,3},{2,7,3},
|
||||||
{7,10,3},{7,6,10},{7,11,6},{11,0,6},{0,1,6},
|
{7,10,3},{7,6,10},{7,11,6},{11,0,6},{0,1,6},
|
||||||
{6,1,10},{9,0,11},{9,11,2},{9,2,5},{7,2,11}
|
{6,1,10},{9,0,11},{9,11,2},{9,2,5},{7,2,11}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using Lookup = std::map<std::pair<int, int>, int>;
|
||||||
|
|
||||||
|
int vertexForEdge(Lookup& lookup, VertexList& vertices, int first, int second);
|
||||||
|
TriangleList subdivide(VertexList& vertices, TriangleList triangles);
|
||||||
};
|
};
|
Loading…
Reference in New Issue