Last active
April 12, 2021 18:28
-
-
Save tuket/32951040ca0a4b31395175ee3e075d46 to your computer and use it in GitHub Desktop.
generate icosahedron
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <glm/glm.hpp> | |
#include <glm/gtc/constants.hpp> | |
constexpr float PI = glm::pi<float>(); | |
using glm::vec3; | |
/*static void generateIcosahedronVerts(vec3 verts[12]) | |
{ | |
using glm::sqrt; | |
using glm::mat2; | |
constexpr float PI = glm::pi<float>(); | |
const mat2 rot36 = rotY(0.2f * PI); | |
const float r = 1 / (2*sin(0.2f*PI)); | |
const float h = sqrt(1 - r*r); | |
const float a = sqrt(r*r - 0.25f); | |
const float h2 = 0.5f * sqrt(1 - (r-a)*(r-a) - 0.25f); | |
verts[0] = vec3(0, h2+h, 0); | |
vec2 p(r, 0); | |
for(int i = 0; i < 5; i++) { | |
verts[1+i] = {p.y, h2, -p.x}; | |
p = rot36 * p; | |
verts[6+i] = {p.y, -h2, -p.x}; | |
p = rot36 * p; | |
} | |
verts[11] = -verts[0]; | |
for(int i = 0; i < 12; i++) | |
verts[i] = glm::normalize(verts[i]); | |
}*/ | |
static const vec3 icosahedronVerts[12] = { | |
{0.0000000000000000000000000, 1.0000000000000000000000000, 0.0000000000000000000000000}, | |
{0.0000000000000000000000000, 0.4472136497497558593750000, -0.8944272398948669433593750}, | |
{-0.8506507873535156250000000, 0.4472136497497558593750000, -0.2763932347297668457031250}, | |
{-0.5257311463356018066406250, 0.4472136497497558593750000, 0.7236067652702331542968750}, | |
{0.5257310271263122558593750, 0.4472136497497558593750000, 0.7236068248748779296875000}, | |
{0.8506507873535156250000000, 0.4472136497497558593750000, -0.2763930857181549072265625}, | |
{-0.5257310867309570312500000, -0.4472136497497558593750000, -0.7236068248748779296875000}, | |
{-0.8506507873535156250000000, -0.4472136497497558593750000, 0.2763931453227996826171875}, | |
{-0.0000000626720364493849047, -0.4472136497497558593750000, 0.8944271802902221679687500}, | |
{0.8506507277488708496093750, -0.4472136497497558593750000, 0.2763932645320892333984375}, | |
{0.5257312059402465820312500, -0.4472136497497558593750000, -0.7236067056655883789062500}, | |
{-0.0000000000000000000000000, -1.0000000000000000000000000, -0.0000000000000000000000000}, | |
}; | |
/* Example usage: | |
int numVerts, numInds; | |
generateIcosphere(numVerts, numInds, nullptr, nullptr, 8); | |
vec3* verts = new vec3[numVerts]; | |
int* inds = new int[numInds]; | |
generateIcosphere(numVerts, numInds, &verts, &inds, 8); | |
*/ | |
void generateIcosphere(u32& numVerts, u32& numInds, vec3* verts, u32* inds, u32 subDivs) | |
{ | |
const int fnl = 1 << subDivs; // num levels per face | |
numVerts = | |
2 + // top and bot verts | |
2 * 5 * (fnl-1) * fnl / 2 + // top and bot caps | |
5 * (fnl+1) * fnl; // middle | |
numInds = 3 * (20 * (1 << (2 * subDivs))); | |
if(verts) | |
{ | |
int vi = 0; | |
auto addVert = [&](vec3 p) { | |
verts[vi++] = glm::normalize(p); | |
}; | |
addVert(s_icosahedronVerts[0]); | |
using glm::mix; | |
for(int l = 1; l < fnl; l++) { | |
const float vertPercent = float(l) / fnl; | |
for(int f = 0; f < 5; f++) { | |
const vec3 pLeft = mix(s_icosahedronVerts[0], s_icosahedronVerts[1+f], vertPercent); | |
const vec3 pRight = mix(s_icosahedronVerts[0], s_icosahedronVerts[1+(f+1)%5], vertPercent); | |
for(int x = 0; x < l; x++) { | |
const vec3 p = mix(pLeft, pRight, float(x) / l); | |
addVert(p); | |
} | |
} | |
} | |
for(int l = 0 ; l < fnl; l++) { | |
const float vertPercent = float(l) / fnl; | |
for(int f = 0; f < 5; f++) { | |
const vec3 topLeft = s_icosahedronVerts[1+f]; | |
const vec3 topRight = s_icosahedronVerts[1+(f+1)%5]; | |
const vec3 botLeft = s_icosahedronVerts[6+f]; | |
const vec3 botRight = s_icosahedronVerts[6+(f+1)%5]; | |
const vec3 left = mix(topLeft, botLeft, vertPercent); | |
const vec3 mid = mix(topRight, botLeft, vertPercent); | |
const vec3 right = mix(topRight, botRight, vertPercent); | |
for(int x = 0; x < fnl-l; x++) { | |
const vec3 p = mix(left, mid, float(x) / (fnl-l)); | |
addVert(p); | |
} | |
for(int x = 0; x < l; x++) { | |
const vec3 p = mix(mid, right, float(x) / l); | |
addVert(p); | |
} | |
} | |
} | |
for(int l = 0; l < fnl; l++) { | |
const float vertPercent = float(l) / fnl; | |
for(int f = 0; f < 5; f++) { | |
const vec3 pLeft = mix(s_icosahedronVerts[6+f], s_icosahedronVerts[11], vertPercent); | |
const vec3 pRight = mix(s_icosahedronVerts[6+(f+1)%5], s_icosahedronVerts[11], vertPercent); | |
for(int x = 0; x < fnl-l; x++) { | |
const vec3 p = mix(pLeft, pRight, float(x) / (fnl-l)); | |
addVert(p); | |
} | |
} | |
} | |
addVert(s_icosahedronVerts[11]); | |
assert(vi == (int)numVerts); | |
} | |
if(inds) | |
{ | |
int i = 0; | |
auto addTri = [&](int i0, int i1, int i2) { | |
inds[i++] = i0; | |
inds[i++] = i1; | |
inds[i++] = i2; | |
}; | |
// top | |
for(int f = 0; f < 5; f++) | |
addTri(0, 1+f, 1+(f+1)%5); | |
int rowOffset = 1; | |
for(int l = 1; l < fnl; l++) { | |
const int rowLen = l*5; | |
const int nextRowLen = (l+1)*5; | |
for(int f = 0; f < 5; f++) { | |
for(int x = 0; x < l; x++) { | |
const int topLeft = rowOffset + l*f + x; | |
const int topRight = rowOffset + (l*f + x + 1) % rowLen; | |
const int botLeft = rowOffset + rowLen + (l+1) * f + x; | |
addTri( | |
topLeft, | |
botLeft, | |
botLeft + 1); | |
addTri( | |
topLeft, | |
botLeft + 1, | |
topRight); | |
} | |
addTri( | |
rowOffset + (l*(f+1)) % rowLen, // review! | |
rowOffset + rowLen + (l+1) * f + l, | |
rowOffset + rowLen + ((l+1) * f + l + 1) % nextRowLen); | |
} | |
rowOffset += rowLen; | |
} | |
{ // middle | |
const int rowLen = 5 * fnl; | |
for(int l = 0; l < fnl; l++) { | |
for(int x = 0; x < rowLen; x++) { | |
const int topLeft = rowOffset + x; | |
const int topRight = rowOffset + (x+1) % rowLen; | |
const int botLeft = rowOffset + rowLen + x; | |
const int botRight = rowOffset + rowLen + (x+1) % rowLen; | |
addTri(topLeft, botLeft, topRight); | |
addTri(topRight, botLeft, botRight); | |
} | |
rowOffset += rowLen; | |
} | |
} | |
// bottom | |
for(int l = 0; l < fnl-1; l++) { | |
const int faceLen = fnl - l; | |
const int rowLen = faceLen*5; | |
const int nextRowLen = (faceLen-1)*5; | |
for(int f = 0; f < 5; f++) { | |
for(int x = 0; x < fnl-l-1; x++) { | |
const int topLeft = rowOffset + faceLen*f + x; | |
const int topRight = rowOffset + faceLen*f + x + 1; | |
const int botLeft = rowOffset + rowLen + (faceLen-1) * f + x; | |
const int botRight = rowOffset + rowLen + ((faceLen-1) * f + x + 1) % nextRowLen; | |
addTri(topLeft, botLeft, topRight); | |
addTri(topRight, botLeft, botRight); | |
} | |
addTri( | |
rowOffset + faceLen*(f+1) - 1, | |
rowOffset + rowLen + ((faceLen-1) * (f+1)) % nextRowLen, | |
rowOffset + faceLen*(f+1) % rowLen); | |
} | |
rowOffset += rowLen; | |
} | |
for(int f = 0; f < 5; f++) | |
addTri(numVerts-6+f, numVerts-1, numVerts-6 + (f+1)%5); | |
assert(i == (int)numInds); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://tuket.github.io/posts/2020-06-10-generate-icosphere-mesh-fast/