So currently my cube has thousands of vertices when i export it from
blender and load it into my application. I'd like to cut this loading
time a lot.
Oh, now I know what you mean when you said that you were having trouble deciding which vertices go to which of the 6 planes. I think it would be a lot easier if instead you were to build the sphere inside the application, instead of loading a sphere made somewhere else. Before I show you how I build the sphere in-program, let me show you the struct I use first. I removed a few things specific to my app, so it's pretty basic:
#define EDGE_LEFT 0
#define EDGE_RIGHT 1
#define EDGE_TOP 2
#define EDGE_BOTTOM 3
typedef struct quadarray_s
{
gx_vbuffer_t* vb; //vertex buffer storing geometry for this patch
vindex startindex; //start and end draw index for this patch
vindex endindex;
zint32 w; //2d array dimension. w and h can both be 33 for example, for 33x33 patch
zint32 h;
struct quadarray_s* children[4]; //4 children patches to subdivide
struct quadarray_s* parent;
int self; //which one of my parent's children am i?
vec3 center; //center of the quadarray
float size; //area metric
float dsize; //displacement metric
//neighbors
struct quadarray_s* adjacent[4]; //the 4 adjacent neighbors at the same detail level
int adjacent_edge[4]; //inverse relationship from neighbor
} quadarray_t ;
Probably the most confusing part is tracking neighbors, but you can probably ignore that at the moment. You can get started without it, there will just be cracks and seems between patches.
I create 6 quadarray patches, one for each face of the cube: (warning, messing C code!)
for (face = 0; face < 6; face++) //6 sides of cube...
{
//make quadarray
qa = quadarray_mk(33,33);
qa->size = .3; //I set the 'size' of this patch to .3. it's rather arbitray, I just declared this patch has area metric of .3
qa->dsize = .01; //I set the detail size of this patch to .1. It's also arbitray, it just affects how 'big' the displacements are
// a and b will visit each vertex in the quadarray.
for (a=0;a < qa->w;a++) //0 to 'width'
{
for (b=0;b<qa->h;b++) //0 to 'height'
{
vec3* vv = quadarray_get_vertex(qa, a, b);
//convert each of the integer vertex coordinates to float -1 to 1
fa = ((a-qa->w/2)/ (float) (qa->w-1)) *2 ;
fb = ((b-qa->h/2)/ (float) (qa->h-1)) *2 ;
//now decide on a plane depending on what face we are on
switch (face)
{
case 0: //top Y=1
vec3set(*vv, fa, 1, fb);
break;
case 1: //bottom Y=-1
vec3set(*vv, -fa, -1, fb);
break;
case 2: //front Z=1
vec3set(*vv, -fa, fb, 1);
break;
case 3: //back Z=-1
vec3set(*vv, fa, fb, -1);
break;
case 4: //left X=-1
vec3set(*vv, -1, fb, -fa);
break;
case 5: //right X=1
vec3set(*vv, 1, fb, fa);
break;
}
//normalize vv to unit length
d = vec3dot(*vv,*vv);
d = sqrt(d);
vec3scale(*vv, 1/d);
}
}
vector_add(active_quadarrays, qa); /* Add to the vector of enabled quadarrays */
}
The above creates a perfect ball radius 1 centered around <0,0,0>. The quadarrays vector stores the current list of active quadarrays. 'Active' means current detail level.
The main algorithm I use is in the pseudocode here:
//once per render/update loop:
for qa = all quadarray_t* in active_quadarrays {
//test for visibility and draw
if ( qa is in camera frustum )
draw (qa);
if ( patch_too_small( qa, camera_position))
split_patch(qa);
if (patch_too_big(qa, camera_position))
combine_patches(qa);
}
split_patch (quadarray_t* qa)
{
remove qa from active_quadarrays
if (!qa->children[0])
{
//patch has bot been split before, need to generate or load children
qa->children[0] = ...
qa->children[1] =...;
qa->children[2] =...
qa->children[3] = ...
}
add qa->children[0] , children[1], children[2], and children[3] to active_quadarrays
}
combine_patch (quadarray_t* qa) {
//remove all siblings from active_quadarrays
remove qa->parent->child[0]
remove qa->parent->child[1]
remove qa->parent->child[2]
remove qa->parent->child[3]
place qa->parent on active_quadarrays
}
I currently alpha-blend details in and out, so I am doing something more complicated than this. I have a 'fade in' and 'fade out' list. I hope to find some time to fix the cracks between detail levels and then cleanup the code. After that, I'll put it on github, and everyone can rip it apart and flame my archaic C style :)