Jump to content
  • Advertisement
Sign in to follow this  
Cristian Decu

Mapping a Sphere to a Cube

This topic is 941 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

Hello,

 

I'm working on my planet renderer for a while now, and i'm stuck with the quadtree sphere.

So i constructed 6 quadtrees and formed a cube, but how can i map my sphere to this cube?

 

For instance, think of a line tangent to the surface of my sphere; the center of the line is the closest point to the sphere,

the more you go sideways, the more the distance increases. But that's for a sphere, for the cube all the points are equally distanced from the

side of the cube.

 

In order to make this work i'm thinking to somehow project a position from sphere space to cube space (excuse my terminology, i'm a self taught programmer).

 

Now, getting back to my tangent line, if projected to a cube, my tangent line should look like a parabola,but how can this be achieved for an arbitrary point around the sphere?

 

In other words, a circular orbit around my planet should describe a square path in the "deformed" space.

 

I need an algorithm that takes a vec3 as input, representing the local space (sphere space) and to output a vec3 representing the "deformed" cube space.

 

vec3 cubify(vec3 p);

 

I've noticed that the quadtree way of managing the sphere level of detail is used almost everywhere, and it makes most sense, however i couldn't find any information about this particular issue.

 

Thank you so much for your help!

Edited by Cristian D.

Share this post


Link to post
Share on other sites
Advertisement
assuming you use the simple transfrom from cube surface to sphere surface: vec3 sphereS = cubeS.Unit(),
going from sphere to cube is very easy - i'll show two methods:

1. intersection ray - plane

vec3 ray = (playerPos - planitCenter).Unit();
Find the largest dimension of (fabs(ray.x), fabs(ray.y), fabs(ray.z)) and it's sign to classify which cubeface to select.
Build a plane for that face, e.g. planeNormal = vec3(1,0,0) of positive x has been chosen.
Assuming the cube has a side length of 2, we can use the normal also for the plane position.

vec3 intersectionPoint = IntersectRayPlane (qVec3 (0,0,0), ray, planeNormal, planeNormal);

Get the coords for the quadtree from y&z, still assuming normal is x:
float u = (intersectionPoint.y + 1.0f) / 2.0f;
float v = (intersectionPoint.z + 1.0f) / 2.0f;


inline float IntersectRayPlane (qVec3 &rO, qVec3 &rD, qVec3 &pO, qVec3 &pN)
	{
		// rD does not need to be unit length
		float d = pN.Dot(rD);
		float n = pN.Dot(pO - rO);

		if (fabs(d) < FP_EPSILON) // ray parallel to plane
		{           
			if (fabs(n) < FP_EPSILON) return 0; // ray lies in plane
			else return FLT_MAX; // no intersection
		}
		float t = n / d;
		return t;
	}
... you can optimize and remove the branches because those case will not happen.



2. interstion ray - box

struct AABox 
	{
		vec minmax[2]; // would be [(-1,-1,-1), (1,1,1)] for the same cube as above

		void DistanceRayFrontAndBackface (float &ffd, float& bfd, const vec& rayOrigin, const vec& rayInvDirection)
		{
			vec t0 = vec(minmax[0] - rayOrigin).MulPerElem (rayInvDirection);
			vec t1 = vec(minmax[1] - rayOrigin).MulPerElem (rayInvDirection);
			vec tMin = t0.MinPerElem (t1);
			vec tMax = t0.MaxPerElem (t1);
			ffd = tMin.MaxElem(); // front face distance (behind origin if inside box) 
			bfd = tMax.MinElem(); // back face distance	
		}

		bool IntersectRay (float& t, const vec& rayOrigin, const vec& rayInvDirection, float rayLength)
		{
			float ffd, bfd;
			DistanceRayFrontAndBackface (ffd, bfd, rayOrigin, rayInvDirection);
			t = (ffd > 0) ? ffd : bfd; // always the first intersection with a face
			return (ffd <= bfd) & (bfd >= 0.0f) & (ffd <= rayLength);
		}
}

That's an optimization utilizing the fact our planes always match the coordinate system directions.
So no dot products, but the division is still there:
vec rayInvDirection = vec (1.0 / ray.x, 1.0 / ray.y, 1.0 / ray.z);

The math here is pretty basic so i wonder you ask.
Be sure to understand how it works if you can use it.
Should become second nature and you should also end with a simpler way than what i've shown here ;)




A more interesting question would be:
How can i do that sphere <-> cube mapping in a way, that all cube texels have similar area.
Currently there is more detail near the cube corners, and you don't want this.
I plan to work on this soon, in case i can't find a solution somewhere...

Share this post


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

  • Advertisement
×

Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!