# spherical terrain

dudeabot

24-03-2009 00:18:26

i dunno if its posisble, but im trying to map the terrain to a sphere, using this equations:

Vector3 Tile::mapCubeToUnitSphere(const Vector3 &cubeCoord)
{
Real x = cubeCoord.x;
Real y = cubeCoord.y;
Real z = cubeCoord.z;

assert(x >= -1 && x <= 1 && y >= -1 && y <= 1 && z >= -1 && z <= 1);

Vector3 sphereCoord;
const Real div3 = 1.0f / 3.0f;
sphereCoord.x = x * Math::Sqrt(1.0f - y * y * 0.5f - z * z * 0.5f + y * y * z * z * div3);
sphereCoord.y = y * Math::Sqrt(1.0f - z * z * 0.5f - x * x * 0.5f + z * z * x * x * div3);
sphereCoord.z = z * Math::Sqrt(1.0f - x * x * 0.5f - y * y * 0.5f + x * x * y * y * div3);

return sphereCoord;
}

i have modified createVertexData to this(tile.cpp from 2.31 ETM):

for (size_t j = startz; j < endz; ++j)
{
for (size_t i = startx; i < endx; ++i)
{
float* pPos, * pTex0;//, * pTex1;
posElem->baseVertexPointerToElement(pBase, &pPos);
texElem0->baseVertexPointerToElement(pBase, &pTex0);

Real height = mInfo.getOffset().y + mInfo.at(i, j) * mInfo.getScaling().y;
Vector3 face1Normalised(i,mInfo.at(i, j),j);
face1Normalised.normalise();
Vector3 finalVector=mapCubeToUnitSphere(face1Normalised);

*pPos++ = mInfo.getOffset().x + mInfo.getScaling().x * finalVector.x;
*pPos++ = mInfo.getOffset().y + mInfo.getScaling().y * finalVector.y;
*pPos++ = mInfo.getOffset().z + mInfo.getScaling().z * finalVector.z;

*pTex0++ = float(i) / (mInfo.getWidth() - 1);
*pTex0++ = float(j) / (mInfo.getHeight() - 1);

if (height < minHeight)
minHeight = height;
if (height > maxHeight)
maxHeight = height;

pBase += mMainBuffer->getVertexSize();
}
}

it would map just one of the 6 cube faces, but i just see a rather strange cone.

i am missing something?

CABAListic

24-03-2009 12:44:56

Do you want a complete (closed) sphere, or just a part of it? I doubt that you can get the former to look right; mapping a rectangular heightmap to a full sphere is not without problems.

In any case, I haven't tried it, but I would probably try to interpret the heightmap positions as spherical coordinates and translate them accordingly to new cartesian coordinates. I'm not exactly sure what your current transformation is doing or where it comes from.

dudeabot

24-03-2009 16:49:34

ok sorry

i got the equation from johnj, which seems ogt from another place:

http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html and http://www.infinity-universe.com/opengl/CubeSphereMapping.txt

Do you want a complete (closed) sphere, or just a part of it?

complete

im trying with just one side of the cube right now (just one face) but i could use the same heightmap just for testing

the coordinates from the equation should be normalised and one of the extremes should be (-1,1). Is it possible to change the vertexdata after its built(normalise the values, map to sphere, then scale it back)? and if it would work after changed because:

1) i didnt understand how the height is stored
2) if the LOD would get screwed up.

EDIT i did some testings, and the values i get is far from benig correct, negatives ones, what i see i think its like graphical garbage (if theres such a thing)

CABAListic

24-03-2009 17:30:31

Ah ok, but you do regard the heightmap as just one side of the cube, right? Because if you're actually regarding the heightmap as the cube itself, this won't quite give the results you want.

dudeabot

24-03-2009 18:10:48

yes i do, still not sure where to change the vertexdata though

CABAListic

24-03-2009 19:06:55

Well, the best way would be in ETL v3, by creating a new class SphericalTerrain, modelled after FlatTerrain, but I can't currently recommend using ETL (if you do want to try, be sure to check out revision 50, because the more recent ones are broken right now)

In principle, the place you picked should be correct, but this will only alter the visual representation. You will not get any useful info out of the TerrainInfo object, as that one's just not made to deal with spherical terrain. For now I assume that your calculation is not quite correct, but I didn't take a closer look, so this is just guessing on my part. Specifically the normalisation of your input vector sounds bogus to me.

dudeabot

06-04-2009 04:07:57

im trying this again

Well, the best way would be in ETL v3, by creating a new class SphericalTerrain, modelled after FlatTerrain, but I can't currently recommend using ETL (if you do want to try, be sure to check out revision 50, because the more recent ones are broken right now)

that looks nice, but my editor is entirely based on 2.3 unfortunately

Specifically the normalisation of your input vector sounds bogus to me.

me too, but what could it be? can i use i,mInfo.at(i, j),j for the vector? i was taking a look there is a special method for retrivieng the height value

i get negative values if i used the code posted up, so its really bogus, im guessing it has to do with the normalisation part too

thanks!

CABAListic

06-04-2009 10:33:01

Ok, well, let's do this methodically, then I haven't studied the link you gave any further, so I'm going to ignore it here. To me, the "simplest" way to map a rectangle to a sphere seems to be to interpret its cartesian coordinates as spherical coordinates.

Let's assume our sphere is centered at the origin, then we need a base radius R to describe it. This gives us a base sphere on top of which we construct the terrain. Any point on the sphere can be described by the two angles theta and phi, so we are going to map our rectangle to theta and phi. We need minimum and maximum values for phi and theta. These might work well:
phi_min = 0° = 0
phi_max = 90° = PI/2
theta_min = 45° = PI/4
theta_max = 135° = 3*PI/4

That said, we have as input i, j and mInfo.at(i, j). i goes from 0 to mInfo.getWidth()-1. Let's map i to the angle phi:
phi = phi_min + (phi_max - phi_min) * float(i) / (mInfo.getWidth()-1);
Same goes for j to theta:
theta = theta_min + (theta_max - theta_min) * float(j) / (mInfo.getHeight()-1);
And finally, we need the third spherical coordinate, r. We have already defined a minimum radius R for our sphere. We are going to add to R the corresponding height value with the scaling value.
r = R + mInfo.at(i, j) * mInfo.getScaling().z

Ok, I didn't test any of that, but if I haven't made a mistake we should now have a mapping to get any point from our heightmap to a spherical coordinate (r, theta, phi). Finally, we need to get the cartesian coordinates from the spherical coordinates to give to Ogre:

x = r * sin(theta) * sin(phi);
y = r * sin(theta) * cos(phi);
z = r * cos(theta);

Now, to be fair, it's very possible that, even if this works, the terrain might not be quite where you want it, and the mapping to spherical coordinates is actually not ideal. It should work with the angle restrictions I gave, but other angles may very well fail. The mapping in the link is probably more advanced, but maybe this here can get you started.

dudeabot

08-04-2009 02:45:02

thanks for your time cabalistic! im getting this tested this weekend, you know exams