5
\$\begingroup\$

I am using a standard heightmapped procedural terrain in my project. However, I want the terrain to appear spherical when the user zooms out. This is an attempt to simulate the appearance of a spherical planet. Here is my current algorithm:

        //get the direction from the "planet" center to this vert
        Vector3 sphereCentertoVertPosition = vert.Position - SphereCenter;
        sphereCentertoVertPosition.Normalize();

        //our rotation axis is the cross between the direction from this vert to the planet center and the root (center of the terrain) to the planet center
        RotationAxis = Vector3.Cross(sphereCentertoVertPosition, sphereCenterToRootPosition);

        //the amount we rotate is based on the distance of this vert from the center of the terrain
        Vector3 fromCenter = vert.Position - Root.Position;
        float amount = (fromCenter.Length() / ((myTextureWidth / Scale) / 2)) * (float)Math.PI;

        Quaternion rot = Quaternion.CreateFromAxisAngle(RotationAxis, amount);

        Vector3.Transform(ref vert.Position, ref rot, out vert.Position);

My main concern is that the rotation axis is not correct. Theoretically, should it be the cross between the vert-to-planet-center and the terrain-center-to-planet-center?

\$\endgroup\$
3
  • \$\begingroup\$ What kind of result is this producing? \$\endgroup\$
    – House
    Commented Dec 18, 2011 at 6:54
  • 1
    \$\begingroup\$ In case anyone googles this, there were three problems. First, the rotation axis should be Vector3.Cross(vert.Position - Root.Position, Vector3.Up); And second, Vector3.Transform will rotate around the origin. To rotate around the heightmap center, you need to subtract Root.Position, transform, and add Root.Position back. Third, you should only rotate PI/4 radians at the farthest points. \$\endgroup\$
    – khayman218
    Commented Dec 19, 2011 at 17:40

1 Answer 1

5
\$\begingroup\$

Hmm, I'm not so sure about rotating the vertices. Perhaps this is not the answer you're looking for, but I can suggest an alternate method.

I've done something similar with maps in my game. I wrote a shader to wrap terrain into a sphere, but it can easily be done outside the graphics card too. It's as simple as mapping the Cartesian coordinates to spherical coordinates. The code would look something like:

public static Vector3f MapToSphere(Vector3f coords, WorldMap MAP) {
    float pi = 3.14159265f;
    float thetaDelta = ((2 * pi) / (MAP.XSize - 1));
    float phiDelta = ((pi) / (MAP.ZSize - .5f));
    float RadiusBase = ((MAP.XSize) / pi / 2f);
    float theta = (coords.z * thetaDelta);
    float phi = (coords.x * phiDelta);

    //Limit the map to half a sphere
    if(theta > pi) {theta = theta - (pi);}

    if(theta < 0.0)    {theta = theta + (pi);}

    if (phi > 2*pi) {phi = phi - (2*pi);}

    if (phi < 0.0) {phi = phi + (2*pi);}

    Vector3f coords2 = new Vector3f();
    coords2.x = (float) (((RadiusBase) * Math.sin(theta) * Math.cos(phi)) + MAP.XSize / 2f);
    coords2.y = (float) ((RadiusBase) * Math.sin(theta) * Math.sin(phi));
    coords2.z = (float) (((RadiusBase) * Math.cos(theta)) + MAP.ZSize / 2f);
    return coords2;
}

This maybe "too spherical" for you. If so, you can try padding the edges of your map so that the portion turned into a sphere only represents a portion of the surface of the sphere.

Below is an example of the spherical mapping results.

A "flat" map:

enter image description here

And a spherical world, created by wrapping the vertices into a sphere:

enter image description here

Note that there will be a large amount of distortion at the poles if you don't follow the suggestion above to limit the surface area of the sphere this map is stretched over.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .