Jump to content
  • Advertisement
Sign in to follow this  
keyofrassilon

Plotting objects on a sphere....

This topic is 4839 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Could someone that has access to the search capabilities of this forum conjure up all the relevant posts on the subject or point me in the right direction here.... I am currently using glRotate *shudders* to try and place an object (more a billboard) of a tree on the surface of a sphere...I tried using the normals that I calculated and those didnt give accurate results....or I was going about it all wrong....Currently I am using something along these lines...
angleX1 = RADTODEG(double(j) * PI / (double(n)/2));
angleX2 = RADTODEG(double(j+1) * PI / (double(n)/2));
angleY1 = RADTODEG(double(i) * TWOPI / double(n))-90;
angleY2 = RADTODEG(double(i+1) * TWOPI / double(n))-90;

I split my array build up with two for loops i and j in the update and in the render output it obviously...The actual terrain, texturing and normals are all correct but the objects when placed offset one of the x, y or z planes start to lean dramatically the further away from each of these planes...I suppose glRotate is the problem and I should possibly build a vertex buffer of billboards instead of a single display list or static vertex buffer rotated each time? The actual class in its entirety is as listed below:
#include "sphere.h"
#include "stellartrader.h"
#include "gl_graph.h"
#include "perlin.h"

char debugText[255];

float obj_billboard_norm[12][3] = {0.7071, 0.0000, 0.7071,
		0.7071, 0.0000, 0.7071,0.7071, 0.0000, 0.7071,
		0.7071, 0.0000, 0.7071,0.7071, 0.0000, 0.7071,
		0.7071, 0.0000, 0.7071,-0.7071, 0.0000, 0.7071,
		-0.7071, 0.0000, 0.7071,-0.7071, 0.0000, 0.7071,
		-0.7071, 0.0000, 0.7071,-0.7071, 0.0000, 0.7071,
		-0.7071, 0.0000, 0.7071};

float obj_billboard_vert[12][3] = {-0.3536, 1.0000, 0.3536,
		-0.3536, 0.0000, 0.3536,0.3536, 1.0000, -0.3536,
		0.3536, 0.0000, -0.3536,0.3536, 1.0000, -0.3536,
		-0.3536, 0.0000, 0.3536,-0.3536, 1.0000, -0.3536,
		-0.3536, 0.0000, -0.3536,0.3536, 1.0000, 0.3536,
		0.3536, 0.0000, 0.3536,0.3536, 1.0000, 0.3536,
		-0.3536, 0.0000, -0.3536};

float obj_billboard_tex[12][3] = {0.9995, 0.9995,
		0.9995, 0.0005,0.0005, 0.9995,
		0.0005, 0.0005,0.0005, 0.9995,
		0.9995, 0.0005,0.0000, 1.0000,
		0.0000, 0.0000,1.0000, 1.0000,
		1.0000, 0.0000,1.0000, 1.0000,
		0.0000, 0.0000};


Sphere::Sphere(int n, int bwidth, int bheight) {
	normals.reserve(n * n * 4);
	texes.reserve(n * n * 4);
	verts.reserve(n * n * 4);
	colors.reserve(n * n * 4);
	objnormals.reserve(n * n * 4);
	objverts.reserve(n * n * 4);
	buffer.reserve((bwidth+1) * (bheight+1) * 4);
	l_buffer.reserve((bwidth+1) * (bheight+1) * 4);
	bufferWidth = bwidth;
	bufferHeight = bheight;
	maxSlices = n;
	numVerts = 0;
	vertCount = 0;
	hi = 0;
	lo = 10000;
}

Sphere::~Sphere() {
}

void Sphere::assignBuffer(unsigned char *b, unsigned char *l, int bwidth, int bheight, double bump) {
	for(int i=0;i<bufferWidth*bufferHeight*3;i++) {
		buffer = b;
		l_buffer = l;
	}

	bufferWidth = bwidth;
	bufferHeight = bheight;
	bumpHeight = bump;
}

Vec3d Sphere::CalculateNormals(Vec3d v1, Vec3d v2, Vec3d v3)
{
	// Reduce each vert's normal to unit
	float length;
	float u[3], v[3];
	Vec3d unit;

	// V2 - V3;
	u[0] = v2.x - v3.x;
	u[1] = v2.y - v3.y;
	u[2] = v2.z - v3.z;

	// V2 - V1;
	v[0] = v2.x - v1.x;
	v[1] = v2.y - v1.y;
	v[2] = v2.z - v1.z;

	unit.x = (u[1]*v[2] - u[2]*v[1]);
	unit.y = (u[2]*v[0] - u[0]*v[2]);
	unit.z = (u[0]*v[1] - u[1]*v[0]);

	length = (double)sqrt((unit.x*unit.x) + (unit.y*unit.y) + (unit.z*unit.z));

	if (length == 0.0f)
		length = 1.0f;

	unit.x /= length;
	unit.y /= length;
	unit.z /= length;

	return unit;
}

void Sphere::setScale(double scale) {
	scaleSet = scale;
}

double Sphere::getHi() {
	return hi;
}

double Sphere::getLo() {
	return lo;
}

Vec2f Sphere::getSphereEyeCoord(Vec3d pos, Vec3d cam) {
	Vec2f coord;
	double x,y,z;

	coord.x = PI + (atan2(pos.z - cam.z,pos.x - cam.x));
	x = pos.x - cam.x;
	y = pos.y - cam.y;
	z = pos.z - cam.z;
	coord.y = -(PI * 0.5f - atan2(sqrt(x*x+z*z),y));
	return coord;
}

void Sphere::Update(Vec3d pos, Vec3d cam, double r,int n, bool useClip, bool useArea, bool useHeight)
{
   int i,j,index = 0;
   double theta1,theta2,theta3;
   double angleX1, angleX2, angleY1, angleY2;
   double u, v, height;
   double hu, hv;
   double per;
   double part;
   float slice, restslice;
   int objindex = 0, objinc = 0;
   Vec3d e,p;
   Vec2d lalpha;

   // take horizontal camera - 90 degrees = center on closest vert;

   if(n > maxSlices) n = maxSlices;
   slices = n;
   radius = r;

   if (r < 0)
      r = -r;
   if (n < 0)
      n = -n;
	
	eyeSphere = getSphereEyeCoord(pos,cam);

	for (j=0;j<n/2;j++) { // rotate X for objects
		if(useArea)
			part = FABS((j / (n/2)) - 0.5) * 0.1;
		else
			part = 0.1;

		theta1 = double(j) * TWOPI / double(n) - PIDIV2; // vertical shift
		theta2 = (double(j) + 1) * TWOPI / double(n) - PIDIV2;
		slice = CLAMP(FABS(eyeSphere.y) * 0.25f * part * 10,0.1,1);
		if(theta1 > eyeSphere.y - PI * part && theta1 < eyeSphere.y + PI * part || n < 64 || !useArea && !useClip) {
			for (i=0;i<n;i++) {
				 // rotate Y for objects
				theta3 = double(i) * TWOPI / double(n); // horizontal shift
				angleX1 = RADTODEG(double(j) * PI / (double(n)/2));
				angleX2 = RADTODEG(double(j+1) * PI / (double(n)/2));
				angleY1 = RADTODEG(double(i) * TWOPI / double(n))-90;
				angleY2 = RADTODEG(double(i+1) * TWOPI / double(n))-90;
				restslice = TWOPI - (TWOPI - PIDIV2 * slice);
				if(theta3 > eyeSphere.x - PI * slice && theta3 < eyeSphere.x + PI * slice ||
					eyeSphere.x > TWOPI - PI * slice && theta3 > eyeSphere.x - PI * slice || eyeSphere.x > TWOPI - PI * slice && theta3 < restslice ||
					eyeSphere.x < PI * slice && theta3 < eyeSphere.x + PI * slice || eyeSphere.x < PI * slice && theta3 > TWOPI - restslice || slice > 0.25f || n < 64 || !useArea) {
					u = (double(i)+0.08)/(double)n;
					v = 2*(double(j)+1.08)/(double)n;
					hu = i/(double)n * bufferWidth;
					hv = 2*(double(j)+1)/(double)n * bufferHeight;
					
					per = ((PerlinNoise2D(u * n,v * n,1,1,1.5)+1)/2);
					if(per > hi)
						hi = per;
					if(per < lo)
						lo = per;
					
					if(useHeight) {
						height = double(buffer[(hv * 3) * bufferWidth + hu * 3]) / 255 * bumpHeight;
						height = height * 2 - height;
						height = height * per;
					}
					else
						height = 0;

					e.x = cos(theta2) * cos(theta3);
					e.y = sin(theta2);
					e.z = cos(theta2) * sin(theta3);
					p.x = (r + height)  * e.x;
					p.y = (r + height)  * e.y;
					p.z = (r + height)  * e.z;
					
					colors[index] = float(l_buffer[(hv * 3) * bufferWidth + hu * 3]) / 255.0f * per * 1.25;
					normals[index] = e;
					texes[index] = Vec2f(u,v);
					verts[index] = p;
					index++;
					objnormals[objindex] = Vec3d(angleX2,0,angleY1);
					objverts[objindex] = verts[index];
					objindex++;

					u = (double(i)+0.08)/(double)n;
					v = 2*(double(j)+0.08)/(double)n;
					hu = i/(double)n * bufferWidth-0;
					hv = 2*(double(j)-0)/(double)n * bufferHeight;
					if(hv < 0) hv = 0;

					per = ((PerlinNoise2D(u * n,v * n,1,1,1.5)+1)/2);
					if(per > hi)
						hi = per;
					if(per < lo)
						lo = per;
					
					if(useHeight) {
						height = double(buffer[(hv * 3) * bufferWidth + hu * 3]) / 255 * bumpHeight;
						height = height * 2 - height;
						height = height * per;
					}
					else
						height = 0;

					e.x = cos(theta1) * cos(theta3);
					e.y = sin(theta1);
					e.z = cos(theta1) * sin(theta3);
					p.x = (r + height)  * e.x;
					p.y = (r + height)  * e.y;
					p.z = (r + height)  * e.z;
					
					colors[index] = float(l_buffer[(hv * 3) * bufferWidth + hu * 3]) / 255.0f * per * 1.25;
					normals[index] = e;
					texes[index] = Vec2f(u,v);
					verts[index] = p;
					index++;

					theta3 = (double(i)+1) * TWOPI / double(n);

					u = (double(i)+1.08)/(double)n;
					v = 2*(double(j)+0.08)/(double)n;
					hu = (i+1)/(double)n * bufferWidth-0;
					hv = 2*(double(j)-0)/(double)n * bufferHeight;
					if(hv < 0) hv = 0;

					per = ((PerlinNoise2D(u * n,v * n,1,1,1.5)+1)/2);
					if(per > hi)
						hi = per;
					if(per < lo)
						lo = per;
					
					if(useHeight) {
						height = double(buffer[(hv * 3) * bufferWidth + hu * 3]) / 255 * bumpHeight;
						height = height * 2 - height;
						height = height * per;
					}
					else
						height = 0;

					e.x = cos(theta1) * cos(theta3);
					e.y = sin(theta1);
					e.z = cos(theta1) * sin(theta3);
					p.x = (r + height)  * e.x;
					p.y = (r + height)  * e.y;
					p.z = (r + height)  * e.z;
					
					colors[index] = float(l_buffer[(hv * 3) * bufferWidth + hu * 3]) / 255.0f * per * 1.25;
					normals[index] = e;
					texes[index] = Vec2f(u,v);
					verts[index] = p;
					index++;
					objnormals[objindex] = Vec3d(angleX1,0,angleY2);
					objverts[objindex] = verts[index];
					objindex++;

					u = (double(i)+1.08)/(double)n;
					v = 2*(double(j)+1.08)/(double)n;
					hu = (i+1)/(double)n * bufferWidth-0;
					hv = 2*(double(j)+1)/(double)n * bufferHeight;

					per = ((PerlinNoise2D(u * n,v * n,1,1,1.5)+1)/2);
					if(per > hi)
						hi = per;
					if(per < lo)
						lo = per;
					
					if(useHeight) {
						height = double(buffer[(hv * 3) * bufferWidth + hu * 3]) / 255 * bumpHeight;
						height = height * 2 - height;
						height = height * per;
					}
					else
						height = 0;

					e.x = cos(theta2) * cos(theta3);
					e.y = sin(theta2);
					e.z = cos(theta2) * sin(theta3);
					p.x = (r + height)  * e.x;
					p.y = (r + height)  * e.y;
					p.z = (r + height)  * e.z;
					
					colors[index] = float(l_buffer[(hv * 3) * bufferWidth + hu * 3]) / 255.0f * per * 1.25;
					normals[index] = e;
					texes[index] = Vec2f(u,v);
					verts[index] = p;
					index++;
				}
			}
		}
	}
	numVerts = index;
	numObjects = objindex;
}

int Sphere::getCount() {
	return vertCount;
}

int Sphere::getVert() {
	return numVerts;
}

double Sphere::getClosestVecDistance(double scale, Vec3d cam) {
	return fabs(objverts[closestVec].distanceTo(cam)) - scale;
}

Vec3d Sphere::getClosestVecNormal() {
	return objnormals[closestVec];
}

void Sphere::setBump(double scale, double bump) {
	bumpHeight = bump / scale;
}

void Sphere::setLightPos(Vec3d light) {
	lightPos = light;
}

void Sphere::Draw(double scale, int lod, Vec3d pos, Vec3d cam, bool useClip, bool useArea, bool useHeight, bool useMulti, float alpha)
{
	double dist = 0, closest = 1e20, farthest = 0;
	double cdist = fabs(pos.distanceTo(cam));
	double area = cdist / scale * (1 - (0.9 / scale));
	double distCenter = fabs(cdist - radius);
	double clip = cdist / scale * (1 - (0.025 / scale));
	Vec3d p;
	Vec2f eye = getSphereEyeCoord(pos,cam);

	if(eye.distanceTo(eyeSphere) > PI * 0.005f && useArea ||
		eye.distanceTo(eyeSphere) > PI * 0.005f && useClip)
		Update(pos,cam,1,lod,useClip, useArea,useHeight);	

	closestVec = 0;
	farthestVec = 0;

	glPushMatrix();
	glTranslated(pos.x, pos.y, pos.z);
	glEnable(GL_NORMALIZE);
	glScaled(scale,scale,scale);
	glBegin(GL_QUADS);

	vertCount = 0;
	if(numVerts > 0) {
		for (int i=0;i<numVerts;i+=4) {
			p = pos + verts;
			dist = fabs(p.distanceTo(cam)) / scale;

			if(dist < closest) {
				closest = dist;
				closestVec = i;
			}
			if(dist > farthest) {
				farthest = dist;
				farthestVec = i;
			}
			
			if(useArea && dist < area || useClip && dist < clip || slices < 160) {
				if(useArea)
					glColor4f(colors,colors,colors,alpha);
				glNormal3dv(&normals.x);
				if(useMulti == true) {
					glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texes.x, texes.y); 
					glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texes.x, texes.y); 
				}
				else
					glTexCoord2fv(&texes.x);
				glVertex3dv(&verts.x);
				
				if(useArea)
					glColor4f(colors[i+1],colors[i+1],colors[i+1],alpha);
				glNormal3dv(&normals[i+1].x);
				if(useMulti == true) {
					glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texes[i+1].x, texes[i+1].y); 
					glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texes[i+1].x, texes[i+1].y); 
				}
				else
					glTexCoord2fv(&texes[i+1].x);
				glVertex3dv(&verts[i+1].x);
				
				if(useArea)
					glColor4f(colors[i+2],colors[i+2],colors[i+2],alpha);
				glNormal3dv(&normals[i+2].x);
				if(useMulti == true) {
					glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texes[i+2].x, texes[i+2].y); 
					glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texes[i+2].x, texes[i+2].y); 
				}
				else
					glTexCoord2fv(&texes[i+2].x);
				glVertex3dv(&verts[i+2].x);
				
				if(useArea)
					glColor4f(colors[i+3],colors[i+3],colors[i+3],alpha);
				glNormal3dv(&normals[i+3].x);
				if(useMulti == true) {
					glMultiTexCoord2fARB(GL_TEXTURE0_ARB, texes[i+3].x, texes[i+3].y); 
					glMultiTexCoord2fARB(GL_TEXTURE1_ARB, texes[i+3].x, texes[i+3].y); 
				}
				else
					glTexCoord2fv(&texes[i+3].x);
				glVertex3dv(&verts[i+3].x);
				vertCount+=4;
			}
		}
		p = pos + verts[farthestVec];
		dist = fabs(p.distanceTo(cam));
	}

	glEnd();
	glDisable(GL_NORMALIZE);
	glPopMatrix();
}

void Sphere::DrawObjects(double scale, Vec3d pos, Vec3d cam, float alpha)
{
	double dist = 0, closest = 1e20, farthest = 0;
	double cdist = fabs(pos.distanceTo(cam));
	double area = cdist * 0.05;
	double distCenter;
	double clip = cdist / scale * (1 - (0.025 / scale));
	Vec3d p, n, v;
	
	glDisable(GL_CULL_FACE);
	glDisable(GL_LIGHTING);
	if(numObjects > 0) {
		for (int i=0;i<numObjects;i++) {
			p = pos + objverts * scale;
			dist = fabs(p.distanceTo(cam));
			distCenter = fabs(p.distanceTo(pos));
			if(dist < closest) {
				closest = dist;
				closestVec = i;
			}
			n.x = objnormals.x;
			n.y = objnormals.y;
			n.z = objnormals.z;
			v.x = pos.x + objverts.x * scale;
			v.y = pos.y + objverts.y * scale;
			v.z = pos.z + objverts.z * scale;
			
			if(dist < area && distCenter > bumpHeight * scale * 150.25 && distCenter < bumpHeight * scale * 150.35) {
				glColor4f(1,1,1,alpha);
				drawTree(0.1,v,n);
			}
		}
	}
	glEnable(GL_CULL_FACE);
	glEnable(GL_LIGHTING);
}

void Sphere::drawTree(float radius, Vec3d pos, Vec3d rot)
{
	glPushMatrix();
	glTranslated(pos.x,pos.y,pos.z);
	glRotated(rot.x, 1.0, 0.0, 0.0);
	glRotated(rot.y, 0.0, 1.0, 0.0);
	glRotated(rot.z, 0.0, 0.0, 1.0);
	glEnable(GL_NORMALIZE);
	glScaled(radius, radius, radius);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState (GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glTexCoordPointer (2, GL_FLOAT, 0, obj_billboard_tex);
	glNormalPointer (GL_FLOAT, 0, obj_billboard_norm);
	glVertexPointer (3, GL_FLOAT, 0, obj_billboard_vert);
	glDrawArrays(GL_TRIANGLES, 0, 12);
	glDisableClientState (GL_VERTEX_ARRAY);
	glDisableClientState (GL_NORMAL_ARRAY);
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisable(GL_NORMALIZE);
	glPopMatrix();
}

I prefer not to have to use something too complicated and would lean more to a simpler approach if at all possible...

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!