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

Started by
12 comments, last by Hawkblood 10 years, 8 months ago

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........

Advertisement

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:

[attachment=17467:Untitled.png]

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?

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.


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[0]=1024;//ALWAYS ???
//		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].detailRadius[2]=CubeFaces[cf].detailRadius[1]/2.0f;
		CubeFaces[cf].detailRadius[3]=CubeFaces[cf].detailRadius[2]/2.0f;
		CubeFaces[cf].detailRadius[4]=CubeFaces[cf].detailRadius[3]/2.0f;
		CubeFaces[cf].detailRadius[5]=CubeFaces[cf].detailRadius[4]/2.0f;

		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 (Dist>Top->detailRadius[Level+1]){
		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 (D<Top->detailRadius[Level+1]){//size 32
		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].v=D3DXVECTOR3(sx,sy,sz);//this is already normalized
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;
			pVertexObject->Lock(0, 32*32*sizeof(E_D3DVERTEX), &pVoid, D3DLOCK_DISCARD);
			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;
			pVertexObject->Lock(0, 16*16*sizeof(E_D3DVERTEX), &pVoid, D3DLOCK_DISCARD);
			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].v=D3DXVECTOR3(sx,sy,sz);//this is already normalized
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;
				if (D<Top->detailRadius[Level+1]){
					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).

This topic is closed to new replies.

Advertisement