PDA

View Full Version : Plotting Objects on the surface of a sphere



Rassilon
08-23-2005, 04:29 AM
I figure this is a tad more difficult than a beginners approach so I posted in the advanced section....

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:
</font><blockquote><font size="1" face="Verdana, Arial">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">#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[i] = b[i];
l_buffer[i] = l[i];
}

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

Hlz
08-23-2005, 11:17 AM
You can't use logical OR operators in the code block. It'll cut you off at the knees every time...

PS. What's up with that? :-)

Rassilon
08-23-2005, 01:16 PM
Maybe but that still didnt answer my question...What would be the best approach to placing an object on a sphere?

Heres the rest of the code that seemed to get cut off...

</font><blockquote><font size="1" face="Verdana, Arial">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">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

Rassilon
08-23-2005, 01:25 PM
Ummm why is my post being cut short? And why can I only edit my posts some of the time?

Anyway I cant seem to deliver the rest of the source so Im sorry if its not complete....

The last bit I mentioned was I am not so concerned about the spegetti code but more concerned about plotting the objects correctly on a sphere...

SirKnight
08-23-2005, 01:53 PM
Ummm why is my post being cut short?
Just so you'll know, that is what Hlz was trying to tell you.

-SirKnight