Skip to content

Instantly share code, notes, and snippets.

@roxlu
Created July 13, 2011 12:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/1080202 to your computer and use it in GitHub Desktop.
Save roxlu/1080202 to your computer and use it in GitHub Desktop.
//! \p detail can be between 0 ( = icosahedron) and 8 (extremely detailed sphere)
//! a value of 2 yelds already very good results.
ref<Geometry> vl::makeIcosphere(const vec3& pos, Real diameter, int detail, bool remove_doubles)
{
ref<Geometry> geom = new Geometry;
geom->setObjectName("Icosphere");
ref<ArrayFloat3> coords = new ArrayFloat3;
ref<ArrayFloat3> norms = new ArrayFloat3;
ref<DrawElementsUInt> polys = new DrawElementsUInt(PT_TRIANGLES);
const Real X = (Real)0.525731112119133606;
const Real Z = (Real)0.850650808352039932;
std::vector< vec3 > verts;
verts.push_back( vec3(-X, 0, Z) );
verts.push_back( vec3(X, 0, Z) );
verts.push_back( vec3(-X, 0, -Z) );
verts.push_back( vec3(X, 0, -Z) );
verts.push_back( vec3(0, Z, X) );
verts.push_back( vec3(0, Z, -X) );
verts.push_back( vec3(0, -Z, X) );
verts.push_back( vec3(0, -Z, -X) );
verts.push_back( vec3(Z, X, 0) );
verts.push_back( vec3(-Z, X, 0) );
verts.push_back( vec3(Z, -X, 0) );
verts.push_back( vec3(-Z, -X, 0) );
int idxs[] = {
1,4,0, 4,9,0, 4,5,9, 8,5,4, 1,8,4,
1,10,8, 10,3,8, 8,3,5, 3,2,5, 3,7,2,
3,10,7, 10,6,7, 6,11,7, 6,0,11, 6,1,0,
10,1,6, 11,0,9, 2,11,9, 5,2,9, 11,2,7
};
std::vector<int> indices;
for(int i=0; i<4*5*3; ++i)
indices.push_back(idxs[i]);
// triangulate the icosahedron
if (detail>8)
detail = 8;
if (detail<0)
detail = 0;
for(int i=0; i<detail; ++i)
{
std::vector<int> indices2;
std::vector< vec3 > verts2;
for( int j=0, idx=0; j<(int)indices.size(); j+=3)
{
indices2.push_back(idx++); indices2.push_back(idx++); indices2.push_back(idx++);
indices2.push_back(idx++); indices2.push_back(idx++); indices2.push_back(idx++);
indices2.push_back(idx++); indices2.push_back(idx++); indices2.push_back(idx++);
indices2.push_back(idx++); indices2.push_back(idx++); indices2.push_back(idx++);
vec3 v1 = verts[ indices[j+0] ]; v1.normalize();
vec3 v2 = verts[ indices[j+1] ]; v2.normalize();
vec3 v3 = verts[ indices[j+2] ]; v3.normalize();
vec3 a = (v1 + v2) * 0.5f; a.normalize();
vec3 b = (v2 + v3) * 0.5f; b.normalize();
vec3 c = (v3 + v1) * 0.5f; c.normalize();
verts2.push_back(v1); verts2.push_back( a); verts2.push_back(c);
verts2.push_back( a); verts2.push_back(v2); verts2.push_back(b);
verts2.push_back( a); verts2.push_back( b); verts2.push_back(c);
verts2.push_back( c); verts2.push_back( b); verts2.push_back(v3);
}
verts = verts2;
indices = indices2;
}
// generate sphere vertices and connection information
Real radius = diameter / 2;
coords->resize( (int)verts.size() );
norms->resize( (int)verts.size() );
for( int i=0; i<(int)verts.size(); ++i )
{
coords->at(i) = (fvec3)(verts[i]*radius + pos);
vec3 n = verts[i];
n.normalize();
norms->at(i) = (fvec3)n;
}
polys->indices()->resize( (int)indices.size() );
for(int i=0; i<(int)indices.size(); ++i)
{
VL_CHECK( indices[i] < (int)coords->size() )
polys->indices()->at(i) = indices[i];
}
geom->setVertexArray(coords.get());
geom->setNormalArray(norms.get());
geom->drawCalls()->push_back(polys.get());
if (remove_doubles)
{
DoubleVertexRemover dvr;
dvr.removeDoubles(geom.get());
}
#if defined(VL_OPENGL_ES1) || defined(VL_OPENGL_ES2)
geom->makeGLESFriendly();
#endif
return geom;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment