View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

# Epic fail on my terrain.... Now what?

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

13 replies to this topic

### #1Hawkblood  Members

Posted 12 August 2013 - 01:59 PM

Ok. I had a post recently, talking about putting a plane over a sphere. I was going to use that idea as a skirt for a more detailed terrain. The concept depended on the plane being wrapped over the sphere in a fashion that kept each square of the terrain a constant size. This is an utter failure! It is NOT possible to do that-- there will always be a "crumpling" of the vertices at one edge or the other (at least).

My desire is to create a terrain that would move with the player as he crosses over the planet's surface. This approach would give a little detail to an otherwise smooth sphere. As the player gets closer to the planet's surface, the detail would become greater. All of this should happen in real time. I'm shooting low on the detail to keep it fast, but as I said, my earlier approach failed.

I'm looking at an article http://acko.net/blog/making-worlds-1-of-spheres-and-cubes/ to generate the terrain. The article uses a cube that is projected into a sphere. This cube is made up of 6 quad-trees. I'm slowly trying to understand how to implement a quad-tree, but I think I need to be able to convert a spherical coordinate into a plane coordinate in order to know where on the quad-tree the player is.... How would you do that?

I wasted about a week of programming before discovering my flaw; I hope I'm not going down another dead-ended road.

Posted 12 August 2013 - 10:11 PM

Sounds like you want to map a point on the sphere to a point on one of the cube faces? Like how a cubic environment map works?

Try this link, I've not tested whether it works or not:

http://petrocket.blogspot.co.uk/2010/04/sphere-to-cube-mapping.html

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

### #3Hawkblood  Members

Posted 13 August 2013 - 10:00 AM

Thanks for the link. I thought going from a cube to a sphere would simply be taking a normaled vector of each point on the cube and pushing it out to a specific radius. I’ve never actually made a sphere that way, so I really don’t know. This article indicates another mathematical way to do it, but I think to be consistent, so I will use the way presented in the article first. As for the sphere-to-cube, I thought using a function utilizing cosine and angles would be the way. Again, I think I will try the article first…. Does anyone have more info?

### #4swiftcoder  Senior Moderators

Posted 13 August 2013 - 10:39 AM

I thought going from a cube to a sphere would simply be taking a normaled vector of each point on the cube and pushing it out to a specific radius.

While this does give you a mapping from a cube to a sphere, if you try and tile a quad tree across the resulting mapping, you'll have a lot of distortion (i.e. quads near the center of the cube face will be very large compared to quads at the corners of the cube face).

The mapping defined in that blog post squishes things a little, so that the resulting quads are more evenly distributed. This has a big impact on the quality of terrain around the edges of the cube.

Tristam MacDonald - Software Engineer @ Amazon - [swiftcoding] [GitHub]

### #5Hawkblood  Members

Posted 13 August 2013 - 11:06 AM

It sounds like you think the one in the article is better, right?

### #6swiftcoder  Senior Moderators

Posted 13 August 2013 - 01:22 PM

It sounds like you think the one in the article is better, right?

It results in less distortion, yes.

* "better" is a very subjective quality. It depends on the precise use case.

Tristam MacDonald - Software Engineer @ Amazon - [swiftcoding] [GitHub]

### #7Hawkblood  Members

Posted 16 August 2013 - 10:18 AM

I'm still trying to figure out how to do this...... I've never done a quad-tree, so this is a hard concept to wrap my head around.

I think I need to make 6 quad-trees, one for each face of the cube. Then, for each mesh created (depending on detail etc...), I will have to convert the flat planes into their spot on the sphere. Then, using some noise function (like perlin noise), generate the elevation (which is in/out from center of the sphere)..... This is getting complicated.....

The problem is that I can't take this "one step at a time", because I can't see true results until I get it nearly finished.....

### #8swiftcoder  Senior Moderators

Posted 16 August 2013 - 11:49 AM

The problem is that I can't take this "one step at a time", because I can't see true results until I get it nearly finished.....

Nah, you just aren't breaking this down quite right

1. Start with a single plane, defined either by the 4 corners, or by the center, orientation and extents.
2. Figure out how to use 6 of those to render a cube.
3. Figure out how to subdivide a plane into 4 children.
4. Figure out how to recursively subdivide planes.
5. Figure out the sphere->cube mapping, so you can dynamically subdivide the planes based on camera position.
6. Profit?

Each of the above stages has a well-defined visual result, so you can build this up iteratively, and carefully work out all the bugs at each stage...

Tristam MacDonald - Software Engineer @ Amazon - [swiftcoding] [GitHub]

### #9Hawkblood  Members

Posted 16 August 2013 - 01:40 PM

I'm already at the beginning of step 4 because up to this point, I can see it in my head. If I made code to visualize these, I would have to make it in a different way than is needed for the final product. I can make a single plane to visualize step 4 before implementing all 6 cube faces though.....

### #10swiftcoder  Senior Moderators

Posted 16 August 2013 - 01:58 PM

If I made code to visualize these, I would have to make it in a different way than is needed for the final product.

Aye, that's definitely one of the costs of iterative development.

Well worth it in most cases, I might add - plus, you usually want to leave the debug visualisations in until near the ship date.

Tristam MacDonald - Software Engineer @ Amazon - [swiftcoding] [GitHub]

### #11Hawkblood  Members

Posted 16 August 2013 - 11:41 PM

So far so good. I have the cube faces using quad-tree and the verts "spherified" using the math from the link you gave me.

Now I need to "find a point on the sphere and calc where it is on the cube".... This might be a problem, because the function shown in the article will only give a single point on a single plane. I need to find the point on 3 different planes to do it right.

Gotta sleep now........

### #12Hawkblood  Members

Posted 17 August 2013 - 01:30 PM

Ok. Now I have 2 problems. The first is that in my quad-tree, there can exist squares that have a detail order of 2 greater than an adjacent one. Here's an image to illustrate:

As you can see, there are three detail levels prominently in the picture. You can see that one of them has 4 times the number of vertices as the one to its left (it should be x2). What am I doing wrong to get this problem?

Second problem: When the detail level transitions from higher to lower ,or vice versa, there are frequently gaps where the higher order square has a vertex that isn't lined up with the lower level. I know I need to lerp the values, but I don't quite understand how to get the information from a separate tree "limb". Is there a tried and trued method for doing this?

### #13GeneralQuery  Members

Posted 17 August 2013 - 03:11 PM

As you can see, there are three detail levels prominently in the picture. You can see that one of them has 4 times the number of vertices as the one to its left (it should be x2). What am I doing wrong to get this problem?

Hard to tell without any code. What is the point of reference being used to determine LOD distance and visibility?

Second problem: When the detail level transitions from higher to lower ,or vice versa, there are frequently gaps where the higher order square has a vertex that isn't lined up with the lower level. I know I need to lerp the values, but I don't quite understand how to get the information from a separate tree "limb". Is there a tried and trued method for doing this?

You could look into something like clipmaps, it's fairly simple to implement.

### #14Hawkblood  Members

Posted 17 August 2013 - 05:12 PM

Hard to tell without any code

There's a lot of code.


E_D3DVERTEX vert32[32][32];
E_D3DVERTEX vert16[16][16];//the templates

LPDIRECT3DINDEXBUFFER9 i_buff32=NULL,i_buff16=NULL;
const float InvPowerOf2[]={1,1.0f/2.0f,1.0f/4.0f,1.0f/8.0f,1.0f/16.0f,1.0f/32.0f,1.0f/64.0f,1.0f/128.0f,1.0f/256.0f,1.0f/512.0f,1.0f/1024.0f};

struct QTTOPLEVEL{
struct QTNODE{
QTNODE(){Child[0][0]=Child[0][1]=Child[1][0]=Child[1][1]=Parent=NULL;Level=-1;Type=-1;pVertexObject=NULL;}
QTNODE(QTNODE* P,int L){Child[0][0]=Child[0][1]=Child[1][0]=Child[1][1]=NULL; Parent=P;Level=L;Type=-1;pVertexObject=NULL;}
~QTNODE(){
if (pVertexObject!=NULL) pVertexObject->Release();
}
QTNODE* Parent;
QTNODE* Child[2][2];

LPDIRECT3DVERTEXBUFFER9 pVertexObject ;//this is the final product mesh after all the calcs are done...
//no need to have an index buffer because it is a generic IB that is pre-calculated and referenced by Type
int Type;//this refers to a generic flat mesh and index.
E_D3DVERTEX vert[32][32];//may make this a **pointer ???

float locX,locZ;//location that this node is on the "plane"
float sizeSquared;//used when checking the distance from "detail center".... uses THE SQUARE so calcs are faster
int Level;//how far from the top level

void UpdateNode(QTTOPLEVEL *Top,GAMEENGINE *GE);//test for radius (of this level) going through this node
void CreateLevel(QTTOPLEVEL *Top,GAMEENGINE *GE);//QTNODE *Top refers to the top most (where float detailRadius[6]; ,float plocX,plocZ; and int MaxLevel; are located
};

QTNODE TopLevelNode[2][2];
int Planet;
float planetSizeX,planetSizeY;//this is the texture and heightmap size
bool Detailed;//this is true if it is one of the 3 sides of the cube that is being detailed
int MaxLevel;//the detail level
float plocX,plocZ; //the point of detail. Where the "detail center" is on the plane.

float detailRadius[6];//these will determine how far each node needs to go to get correct detail..... max of 6 levels of detail...?
//in order of largest radius to smallest(nearest and highest detail).... SQUARE VALUE?

D3DXMATRIX faceOrientation;//********** the templates are oriented as y==1 is up. this matrix is used to convert that to the cube's face orientation that this QTTOPLEVEL represents

void UpdateQT(GAMEENGINE *GE);
};

/*
cube point to sphere point:

sx = x * sqrtf(1.0f - y * y * 0.5f - z * z * 0.5f + y * y * z * z / 3.0f);

sy = y * sqrtf(1.0f - z * z * 0.5f - x * x * 0.5f + z * z * x * x / 3.0f);

sz = z * sqrtf(1.0f - x * x * 0.5f - y * y * 0.5f + x * x * y * y / 3.0f);

*/

//point on sphere to point on cube:

struct dVect3{
double x,y,z;
};
void cubizePoint(D3DXVECTOR3& p){
dVect3 position;
position.x=p.x;
position.y=p.y;
position.z=p.z;
double x,y,z;
x = position.x;
y = position.y;
z = position.z;

double fx, fy, fz;
fx = abs(x);
fy = abs(y);
fz = abs(z);

const double inverseSqrt2 = 0.70710676908493042;

if (fy >= fx && fy >= fz) {
double a2 = x * x * 2.0;
double b2 = z * z * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrt((inner * inner) - 12.0 * a2);

if(x == 0.0 || x == -0.0) {
position.x = 0.0;
}
else {
position.x = sqrt(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}

if(z == 0.0 || z == -0.0) {
position.z = 0.0;
}
else {
position.z = sqrt(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}

if(position.x > 1.0) position.x = 1.0;
if(position.z > 1.0) position.z = 1.0;

if(x < 0) position.x = -position.x;
if(z < 0) position.z = -position.z;

if (y > 0) {
// top face
position.y = 1.0;
}
else {
// bottom face
position.y = -1.0;
}
}
else if (fx >= fy && fx >= fz) {
double a2 = y * y * 2.0;
double b2 = z * z * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrt((inner * inner) - 12.0 * a2);

if(y == 0.0 || y == -0.0) {
position.y = 0.0;
}
else {
position.y = sqrt(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}

if(z == 0.0 || z == -0.0) {
position.z = 0.0;
}
else {
position.z = sqrt(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}

if(position.y > 1.0) position.y = 1.0;
if(position.z > 1.0) position.z = 1.0;

if(y < 0) position.y = -position.y;
if(z < 0) position.z = -position.z;

if (x > 0) {
// right face
position.x = 1.0;
}
else {
// left face
position.x = -1.0;
}
}
else {
double a2 = x * x * 2.0;
double b2 = y * y * 2.0;
double inner = -a2 + b2 -3;
double innersqrt = -sqrt((inner * inner) - 12.0 * a2);

if(x == 0.0 || x == -0.0) {
position.x = 0.0;
}
else {
position.x = sqrt(innersqrt + a2 - b2 + 3.0) * inverseSqrt2;
}

if(y == 0.0 || y == -0.0) {
position.y = 0.0;
}
else {
position.y = sqrt(innersqrt - a2 + b2 + 3.0) * inverseSqrt2;
}

if(position.x > 1.0) position.x = 1.0;
if(position.y > 1.0) position.y = 1.0;

if(x < 0) position.x = -position.x;
if(y < 0) position.y = -position.y;

if (z > 0) {
// front face
position.z = 1.0;
}
else {
// back face
position.z = -1.0;
}
}
p=D3DXVECTOR3(float(position.x),float(position.y),float(position.z));
}



void PLANETTERRAIN::Init(GAMEENGINE *GE,int Planet){
//delete any old stuff
Delete();

//determine parameters for the terrain from the planet
for (int cf=0;cf<6;cf++){
CubeFaces[cf].Detailed=true;
CubeFaces[cf].Planet=Planet;
CubeFaces[cf].MaxLevel=5;//**************** will be higher when I am sure it works right
//		CubeFaces[cf].detailRadius[1]=SolarSystem.Planet[Planet].Size;//************ this is where I will need to decide what the radius size is for each detail level
CubeFaces[cf].detailRadius[1]=CubeFaces[cf].detailRadius[0]/2.0f;//************ this is where I will need to decide what the radius size is for each detail level

CubeFaces[cf].TopLevelNode[0][0].locX=-500;
CubeFaces[cf].TopLevelNode[0][0].locZ=-500;
CubeFaces[cf].TopLevelNode[1][0].locX=0;
CubeFaces[cf].TopLevelNode[1][0].locZ=-500;
CubeFaces[cf].TopLevelNode[0][1].locX=-500;
CubeFaces[cf].TopLevelNode[0][1].locZ=0;
CubeFaces[cf].TopLevelNode[1][1].locX=0;
CubeFaces[cf].TopLevelNode[1][1].locZ=0;

CubeFaces[cf].TopLevelNode[0][0].sizeSquared=500000.0f;//this is 500*500+500*500
CubeFaces[cf].TopLevelNode[1][0].sizeSquared=500000.0f;
CubeFaces[cf].TopLevelNode[0][1].sizeSquared=500000.0f;
CubeFaces[cf].TopLevelNode[1][1].sizeSquared=500000.0f;

CubeFaces[cf].planetSizeX=720;
CubeFaces[cf].planetSizeY=360;
if (SolarSystem.Planet[Planet].Size<2000.0f){
CubeFaces[cf].planetSizeX/=2;
CubeFaces[cf].planetSizeY/=2;
}
}

}
void PLANETTERRAIN::Delete(){
for (int cf=0;cf<6;cf++){
for (int tlnx=0;tlnx<2;tlnx++){
for (int tlnz=0;tlnz<2;tlnz++){
if (CubeFaces[cf].TopLevelNode[tlnx][tlnz].Child[0][0]!=NULL){
CubeFaces[cf].TopLevelNode[tlnx][tlnz].Child[0][0]->~QTNODE();
CubeFaces[cf].TopLevelNode[tlnx][tlnz].Child[1][0]->~QTNODE();
CubeFaces[cf].TopLevelNode[tlnx][tlnz].Child[0][1]->~QTNODE();
CubeFaces[cf].TopLevelNode[tlnx][tlnz].Child[1][1]->~QTNODE();
}
if (CubeFaces[cf].TopLevelNode[tlnx][tlnz].pVertexObject!=NULL) CubeFaces[cf].TopLevelNode[tlnx][tlnz].pVertexObject->Release();
CubeFaces[cf].TopLevelNode[tlnx][tlnz].pVertexObject=NULL;
}
}
}
}
void PLANETTERRAIN::Update(GAMEENGINE *GE){
GE->d3ddev->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
//update the center position
//	SphereDetailCenter;
//testing
D3DXVECTOR3 point;
D3DXVECTOR2 facePoint[6];//facePoint[] uses x,y values only
point=GE->MyCamera.m_viewDir*-1.0f;
//D3DXMATRIX tmp;
//D3DXMatrixRotationY(&tmp,-D3DX_PI/5.0f);
//D3DXVec3TransformCoord(&point,&point,&tmp);
cubizePoint(point);
point*=500.0f;
if (point.x==500.0f){//cf==3 E
for (int i=0;i<6;i++) facePoint[i]=D3DXVECTOR2(1000000,1000000);
facePoint[3].x=point.z;
facePoint[3].y=point.y;
if (point.z>0.0f){
facePoint[5].x=point.z-1000.0f;
facePoint[5].y=point.y;
}
else{
facePoint[4].x=point.z+1000.0f;
facePoint[4].y=point.y;
}
if (point.y>0.0f){
facePoint[0].y=point.z;
facePoint[0].x=-(point.y-1000.0f);
}
else{
facePoint[1].y=-point.z;
facePoint[1].x=point.y+1000.0f;
}

}
if (point.x==-500.0f){//cf==2 W
for (int i=0;i<6;i++) facePoint[i]=D3DXVECTOR2(1000000,1000000);
facePoint[2].x=-point.z;
facePoint[2].y=point.y;
if (point.z>0.0f){
facePoint[5].x=-(point.z-1000.0f);
facePoint[5].y=point.y;
}
else{
facePoint[4].x=-(point.z+1000.0f);
facePoint[4].y=point.y;
}
if (point.y>0.0f){
facePoint[0].y=point.z;
facePoint[0].x=point.y-1000.0f;
}
else{
facePoint[1].y=-point.z;
facePoint[1].x=-(point.y+1000.0f);
}
}
if (point.z==500.0f){//cf==5
for (int i=0;i<6;i++) facePoint[i]=D3DXVECTOR2(1000000,1000000);
facePoint[5].x=-point.x;
facePoint[5].y=point.y;
if (point.x<0.0f){
facePoint[2].x=-point.x-1000.0f;
facePoint[2].y=point.y;
}
else{
facePoint[3].x=1000.0f-point.x;
facePoint[3].y=point.y;
}
if (point.y>0.0f){
facePoint[0].x=point.x;
facePoint[0].y=1000.0f-point.y;
}
else{
facePoint[1].x=point.x;
facePoint[1].y=-(point.y+1000.0f);
}
}
if (point.z==-500.0f){//cf==4
for (int i=0;i<6;i++) facePoint[i]=D3DXVECTOR2(1000000,1000000);
facePoint[4].x=point.x;
facePoint[4].y=point.y;
if (point.x>0.0f){
facePoint[3].x=point.x-1000.0f;
facePoint[3].y=point.y;
}
else{
facePoint[2].x=point.x+1000.0f;
facePoint[2].y=point.y;
}
if (point.y>0.0f){
facePoint[0].x=point.x;
facePoint[0].y=point.y-1000.0f;
}
else{
facePoint[1].x=point.x;
facePoint[1].y=point.y+1000.0f;
}
}
if (point.y==500.0f){//cf==0
for (int i=0;i<6;i++) facePoint[i]=D3DXVECTOR2(1000000,1000000);
facePoint[0].x=point.x;
facePoint[0].y=point.z;
if (point.x<0.0f){
facePoint[2].y=point.x+1000.0f;
facePoint[2].x=-point.z;
}
else{
facePoint[3].y=1000.0f-point.x;
facePoint[3].x=point.z;
}
if (point.z>0.0f){
facePoint[5].x=-point.x;
facePoint[5].y=1000.0f-point.z;
}
else{
facePoint[4].x=point.x;
facePoint[4].y=point.z+1000.0f;
}
}
if (point.y==-500.0f){//cf==1
for (int i=0;i<6;i++) facePoint[i]=D3DXVECTOR2(1000000,1000000);
facePoint[1].x=point.x;
facePoint[1].y=-point.z;
if (point.x<0.0f){
facePoint[2].y=-(point.x+1000.0f);
facePoint[2].x=-point.z;
}
else{
facePoint[3].y=point.x-1000.0f;
facePoint[3].x=point.z;
}
if (point.z>0.0f){
facePoint[5].x=-point.x;
facePoint[5].y=point.z-1000.0f;
}
else{
facePoint[4].x=point.x;
facePoint[4].y=-(point.z+1000.0f);
}
}

for (int cf=4;cf<5;cf++){
CubeFaces[cf].plocX=facePoint[cf].x;
CubeFaces[cf].plocZ=facePoint[cf].y;
CubeFaces[cf].UpdateQT(GE);
}
GE->d3ddev->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID);
}


void GenerateTerrainTemplates(GAMEENGINE *GE){
short index32[5766];//index buffres for the templates
short index16[1350];//total number of faces*3
//do the 32x32
for (int z=0;z<32;z++){
for (int x=0;x<32;x++){
vert32[x][z].v=D3DXVECTOR3(float(31-x)/31.0f,0,float(z)/31.0f);
vert32[x][z].tu=float(x)/32.0f;
vert32[x][z].tv=float(z)/32.0f;
//the normals will have to be calculated when it is in place on the sphere
}
}
int pos=0;
for (int ty=0;ty<31;ty++){
for (int tx=0;tx<31;tx++){
index32[pos]=short((ty*32)+tx+1);
index32[pos+2]=short((ty*32)+tx);
index32[pos+1]=short(((ty+1)*32)+tx);

pos+=3;
index32[pos]=short((ty*32)+tx+1);
index32[pos+2]=short(((ty+1)*32)+tx);
index32[pos+1]=short(((ty+1)*32)+tx+1);
pos+=3;
}
}
GE->d3ddev->CreateIndexBuffer(5766 *sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&i_buff32,
NULL);
void *pVoid;
i_buff32->Lock(0, 0, (void**)&pVoid, 0);
short *pint=(short*)pVoid;
for (UINT i=0;i<5766;i++){
pint[i]=index32[i];
}
i_buff32->Unlock();
//do the 16x16
for (int z=0;z<16;z++){
for (int x=0;x<16;x++){
vert16[x][z].v=D3DXVECTOR3(float(15-x)/15.0f,0,float(z)/15.0f);
vert16[x][z].tu=float(x)/16.0f;
vert16[x][z].tv=float(z)/16.0f;
//the normals will have to be calculated when it is in place on the sphere
}
}
pos=0;
for (int ty=0;ty<15;ty++){
for (int tx=0;tx<15;tx++){
index16[pos]=short((ty*16)+tx+1);
index16[pos+2]=short((ty*16)+tx);
index16[pos+1]=short(((ty+1)*16)+tx);

pos+=3;
index16[pos]=short((ty*16)+tx+1);
index16[pos+2]=short(((ty+1)*16)+tx);
index16[pos+1]=short(((ty+1)*16)+tx+1);
pos+=3;
}
}
GE->d3ddev->CreateIndexBuffer(1350 *sizeof(short),
0,
D3DFMT_INDEX16,
D3DPOOL_MANAGED,
&i_buff16,
NULL);
i_buff16->Lock(0, 0, (void**)&pVoid, 0);
pint=(short*)pVoid;
for (UINT i=0;i<1350;i++){
pint[i]=index16[i];
}
i_buff16->Unlock();
}

void QTTOPLEVEL::UpdateQT(GAMEENGINE *GE){
TopLevelNode[0][0].UpdateNode(this,GE);
TopLevelNode[0][1].UpdateNode(this,GE);
TopLevelNode[1][0].UpdateNode(this,GE);
TopLevelNode[1][1].UpdateNode(this,GE);
}
void QTTOPLEVEL::QTNODE::UpdateNode(QTTOPLEVEL *Top,GAMEENGINE *GE){
float shift=500.0f*InvPowerOf2[Level+2];

float Dist=((locX-Top->plocX+shift)*(locX-Top->plocX+shift))+((locZ-Top->plocZ+shift)*(locZ-Top->plocZ+shift));
Dist-=sizeSquared;
if (Child[0][0]!=NULL){
//destroy only if no children and is not the top level
if (Child[0][0]->Child[0][0]==NULL){
//destroy the childs
if (Child[0][0]->pVertexObject!=NULL) Child[0][0]->pVertexObject->Release();
delete Child[0][0];
Child[0][0]=NULL;

if (Child[1][0]->pVertexObject!=NULL) Child[1][0]->pVertexObject->Release();
delete Child[1][0];
Child[1][0]=NULL;

if (Child[0][1]->pVertexObject!=NULL) Child[0][1]->pVertexObject->Release();
delete Child[0][1];
Child[0][1]=NULL;

if (Child[1][1]->pVertexObject!=NULL) Child[1][1]->pVertexObject->Release();
delete Child[1][1];
Child[1][1]=NULL;

}
}
}

//determine if current level is generated

//determine the level (16 or 32)
float D=((locX-Top->plocX+shift)*(locX-Top->plocX+shift))+((locZ-Top->plocZ+shift)*(locZ-Top->plocZ+shift));
D-=sizeSquared;
if (Type!=0){
if (pVertexObject!=NULL) pVertexObject->Release();
GE->d3ddev->CreateVertexBuffer(32*32 *sizeof(E_D3DVERTEX), 0,
E_D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVertexObject, NULL);

float size=500.0f*InvPowerOf2[Level+1];
//copy from the template
for (int z=0;z<32;z++){
for (int x=0;x<32;x++){
vert[x][z]=vert32[x][z];
vert[x][z].v*=size;
vert[x][z].v.x+=locX;
vert[x][z].v.z+=locZ;
vert[x][z].v.x*=0.002f;
vert[x][z].v.z*=0.002f;
vert[x][z].v.y=1.0f;

D3DXVec3TransformCoord(&vert[x][z].v,&vert[x][z].v,&Top->faceOrientation);

//******** spherify the coordinates
float sx = vert[x][z].v.x * sqrtf(1.0f - vert[x][z].v.y * vert[x][z].v.y * 0.5f - vert[x][z].v.z * vert[x][z].v.z * 0.5f + vert[x][z].v.y * vert[x][z].v.y * vert[x][z].v.z * vert[x][z].v.z / 3.0f);

float sy = vert[x][z].v.y * sqrtf(1.0f - vert[x][z].v.z * vert[x][z].v.z * 0.5f - vert[x][z].v.x * vert[x][z].v.x * 0.5f + vert[x][z].v.z * vert[x][z].v.z * vert[x][z].v.x * vert[x][z].v.x / 3.0f);

float sz = vert[x][z].v.z * sqrtf(1.0f - vert[x][z].v.x * vert[x][z].v.x * 0.5f - vert[x][z].v.y * vert[x][z].v.y * 0.5f + vert[x][z].v.x * vert[x][z].v.x * vert[x][z].v.y * vert[x][z].v.y / 3.0f);

vert[x][z].n=vert[x][z].v;//use this for normal unless something else is needed
//get the lat/lon for each point and convert it into texture coordinates
float lat=atan2(vert[x][z].v.x,vert[x][z].v.z)+D3DX_PI;//********* this is wrong, but it allows me to see the problem without having to move
//					float lat=atan2(vert[x][z].v.z,vert[x][z].v.x)+D3DX_PI;
lat/=D3DX_PI*2.0f;
float lon=asin(-vert[x][z].v.y)+D3DX_PI/2.0f;
lon/=D3DX_PI;
if ((x==0)&&(lat>0.999f)) lat=0.0f;
vert[x][z].tu=1.25f-lat;
vert[x][z].tv=lon;
lat=1.0f-lat;
if (lat>=1.0f) lat=0.0f;
lat+=0.25f;
if (lat>=1.0f) lat-=1.0f;
float elev=SolarSystem.Planet[Top->Planet].PlanetTopography[int(Top->planetSizeX*lat)][int(Top->planetSizeY*lon)]/500.0f;
vert[x][z].v*=1000.0f;//+elev;

//*********************** HERE IS WHERE I NEED TO DO THE TEXTURE COORDINATES (IF AT TOP LEVEL ONLY?)
//************ ALSO NEED TO GENERATE TEXTURES FOR LOWER LEVEL STUFF????
//********** MAY USE THE PLANET'S TEXTURE ONLY.... NOT GENERATING TEXTURES FOR THIS TERRAIN SKIRT?
}
}
void *pVoid;
E_D3DVERTEX *vertb=(E_D3DVERTEX*) pVoid;
int c=0;
for (int z=0;z<32;z++){
for (int x=0;x<32;x++){
vertb[c]=vert[x][z];
c++;
}
}

Type=0;
pVertexObject->Unlock();
}
}
else{//size 16
if (Type!=1){
if (pVertexObject!=NULL) pVertexObject->Release();
GE->d3ddev->CreateVertexBuffer(16*16 *sizeof(E_D3DVERTEX), 0,
E_D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &pVertexObject, NULL);

void *pVoid;
E_D3DVERTEX *vertb=(E_D3DVERTEX*) pVoid;
int c=0;
float size=500.0f*InvPowerOf2[Level+1];
//copy from the template
for (int z=0;z<32;z+=2){
for (int x=0;x<32;x+=2){
vert[x][z]=vert16[x/2][z/2];
vert[x][z].v*=size;
vert[x][z].v.x+=locX;
vert[x][z].v.z+=locZ;
vert[x][z].v.x*=0.002f;
vert[x][z].v.z*=0.002f;
vert[x][z].v.y=1.0f;
D3DXVec3TransformCoord(&vert[x][z].v,&vert[x][z].v,&Top->faceOrientation);

//******** spherify the coordinates
float sx = vert[x][z].v.x * sqrtf(1.0f - vert[x][z].v.y * vert[x][z].v.y * 0.5f - vert[x][z].v.z * vert[x][z].v.z * 0.5f + vert[x][z].v.y * vert[x][z].v.y * vert[x][z].v.z * vert[x][z].v.z / 3.0f);

float sy = vert[x][z].v.y * sqrtf(1.0f - vert[x][z].v.z * vert[x][z].v.z * 0.5f - vert[x][z].v.x * vert[x][z].v.x * 0.5f + vert[x][z].v.z * vert[x][z].v.z * vert[x][z].v.x * vert[x][z].v.x / 3.0f);

float sz = vert[x][z].v.z * sqrtf(1.0f - vert[x][z].v.x * vert[x][z].v.x * 0.5f - vert[x][z].v.y * vert[x][z].v.y * 0.5f + vert[x][z].v.x * vert[x][z].v.x * vert[x][z].v.y * vert[x][z].v.y / 3.0f);

vert[x][z].n=vert[x][z].v;//use this for normal unless something else is needed
//get the lat/lon for each point and convert it into texture coordinates
float lat=atan2(vert[x][z].v.x,vert[x][z].v.z)+D3DX_PI;//********* this is wrong, but it allows me to see the problem without having to move
//					float lat=atan2(vert[x][z].v.z,vert[x][z].v.x)+D3DX_PI;
lat/=D3DX_PI*2.0f;
float lon=asin(-vert[x][z].v.y)+D3DX_PI/2.0f;
lon/=D3DX_PI;
if ((x==0)&&(lat>0.999f)) lat=0.0f;
vert[x][z].tu=1.25f-lat;
vert[x][z].tv=lon;
lat=1.0f-lat;
if (lat>=1.0f) lat=0.0f;
lat+=0.25f;
if (lat>=1.0f) lat-=1.0f;
float elev=SolarSystem.Planet[Top->Planet].PlanetTopography[int(Top->planetSizeX*lat)][int(Top->planetSizeY*lon)]/500.0f;
vert[x][z].v*=1000.0f;//+elev;

//*********************** HERE IS WHERE I NEED TO DO THE TEXTURE COORDINATES (IF AT TOP LEVEL ONLY?)
//************ ALSO NEED TO GENERATE TEXTURES FOR LOWER LEVEL STUFF????
//********** MAY USE THE PLANET'S TEXTURE ONLY.... NOT GENERATING TEXTURES FOR THIS TERRAIN SKIRT?
vertb[c]=vert[x][z];
c++;
}
}

Type=1;
pVertexObject->Unlock();
}
}

//update the childs
if (Child[0][0]!=NULL){//if first child is good, then all are there
Child[0][0]->UpdateNode(Top,GE);
Child[0][1]->UpdateNode(Top,GE);
Child[1][0]->UpdateNode(Top,GE);
Child[1][1]->UpdateNode(Top,GE);
}
else{//determine if children are needed
//*********************** render here????????????????????
//getting here indicates that there are no childs (or they were just created). So this is the most detailed level
D3DXMATRIX wm;
D3DXMatrixIdentity(&wm);
D3DXVECTOR3 lv(0,0,1000);//put it somewhere in front of the camera
lv=GE->MyCamera.m_viewDir*2000.0f;
wm(3,0)=lv.x;
wm(3,1)=lv.y;
wm(3,2)=lv.z;
GE->d3ddev->SetTransform(D3DTS_WORLD,&wm);
GE->d3ddev->SetMaterial(&GlowMatl);//DefaultMatl
GE->d3ddev->SetTexture(0,TextureList[SolarSystem.Planet[Top->Planet].BodyTex].Texture);
GE->d3ddev->SetFVF(E_D3DFVF_CUSTOMVERTEX);

if (Type==0){
GE->d3ddev->SetIndices(i_buff32);
GE->d3ddev->SetStreamSource(0, pVertexObject, 0, sizeof(E_D3DVERTEX));
GE->d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 1024, 0, 1922);
}
if (Type==1){
GE->d3ddev->SetIndices(i_buff16);
GE->d3ddev->SetStreamSource(0, pVertexObject, 0, sizeof(E_D3DVERTEX));
GE->d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, 256, 0, 450);
}

if (Top->Detailed){
if (Level<Top->MaxLevel){
//get the distance of the center to the point of intersection
float D=((locX-Top->plocX+shift)*(locX-Top->plocX+shift))+((locZ-Top->plocZ+shift)*(locZ-Top->plocZ+shift));
D-=sizeSquared;
CreateLevel(Top,GE);
}
}
}
}

}

void QTTOPLEVEL::QTNODE::CreateLevel(QTTOPLEVEL *Top,GAMEENGINE *GE){

float size=500.0f*InvPowerOf2[Level+2];//yea, +2 is right
float SS=size*size*2.0f;

Child[0][0]=new QTTOPLEVEL::QTNODE(this,Level+1);
Child[0][0]->locX=locX;
Child[0][0]->locZ=locZ;
//do the size.....
Child[0][0]->sizeSquared=SS;

Child[0][1]=new QTTOPLEVEL::QTNODE(this,Level+1);
Child[0][1]->locX=locX;
Child[0][1]->locZ=locZ+size;
//do the size.....
Child[0][1]->sizeSquared=SS;

Child[1][0]=new QTTOPLEVEL::QTNODE(this,Level+1);
Child[1][0]->locX=locX+size;
Child[1][0]->locZ=locZ;
//do the size.....
Child[1][0]->sizeSquared=SS;

Child[1][1]=new QTTOPLEVEL::QTNODE(this,Level+1);
Child[1][1]->locX=locX+size;
Child[1][1]->locZ=locZ+size;
//do the size.....
Child[1][1]->sizeSquared=SS;

}


So far, EVERYTHING is being rendered. As I stated in the OP, I am trying to implement 6 quad-trees that form a cube and then (when generating the cube faces) converted into a sphere. So far it is working out. I just can't figure out how to tell what each squares neighbors are. If I knew how to get it, I think I could fix the "seams not lining up" problem (problem 2).

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.