So I want to put a height map on a sphere.
Here are some of the ways I have seen people do it.
1: Something to do with 6-sided plane cubes and scripting to make it look like a sphere, I don’t know how it works, I don’t know how to apply a height map to it and I don’t know how to texture it.
2: I saw somewhere you could do it with one plane? I don’t know if you can though
3: Do it in blender. I have no idea how to use blender and following that one creating planets in blender and wilbur tutorial is outdated. I got a heightmap on the sphere but it’s all distorted, Blender would be my least preferred method.
Also a game made in unity, Kerbal Space Program does this. How does it do it there?
Thanks for any help in advance!
“Which method is best?” - any method that works for you
Any of the solutions you’ve mentioned might work just fine but without knowing how you want to use it there’s no choice for a best method. Is it a static model or something that needs to procedurally change or change with different textures/height maps? Do you want to paint or generate the textures/height maps externally or would using some scripted noise functions in the editor or in-game be ok? What sort of limits do you have with regards to mesh size, texture size, etc?
If you’d prefer not to model assets externally there are lots of sites around that cover generating spheres with primitives and then texturing or applying noise to them. In our game (http://elementgame.com) we have a generator in the editor and in the game to dynamically generate small, low resolution planets offline and in realtime using a bunch of basic parameters to apply various amounts of subdivision, scale, noise, etc. to primitives like icosahedrons. Experimenting a bit with things like this should help you decide how to approach building the assets you need - externally, internally, offline, at runtime, various resolutions, using textures/height maps and/or using scripted noise functions, applying textures and/or using custom shaders to add more detail, etc.
@greg-harding
I’ve crossed of method 3. Have no Idea.
Looks like I’m going with either method 1 or 2.
Although I don’t understand how to do any of them…
Can someone explain?
bump
You can check here :
You can also generate an heightmap texture with LibNoise or WorldMachine.
using UnityEngine;
public class SphereMath
{
public static Vector3 CoordinatesToVector3(Vector2 coordinates, float radius = 1f)
{
return CoordinatesToVector3(coordinates.x, coordinates.y, radius);
}
public static Vector3 CoordinatesToVector3(float longitude, float latitude, float radius = 1f)
{
longitude *= Mathf.Deg2Rad;
latitude *= Mathf.Deg2Rad;
float r_e = Mathf.Cos(latitude);
float y_e = Mathf.Sin(latitude);
float x_s = r_e * Mathf.Sin(longitude) * -1;
float z_s = r_e * Mathf.Cos(longitude);
return new Vector3(x_s, y_e, z_s).normalized * radius;
}
public static Vector2 Vector3ToCoordinates(Vector3 position)
{
position = Vector3.Normalize(position);
float x_s = position.x;
float y_e = position.y;
float z_s = position.z;
float latitude = Mathf.Asin(y_e);
float r_e = Mathf.Cos(latitude);
float longitude = Mathf.Acos(x_s / r_e);
Vector2 coordinates = new Vector2(longitude, latitude) * Mathf.Rad2Deg;
if (z_s <= 0)
{
if (x_s <= 0)
{
coordinates.x = 180 - (coordinates.x - 90);
}
else
{
coordinates.x = -90 - coordinates.x;
}
}
else
{
coordinates.x -= 90;
}
return coordinates;
}
public static float ArcDistance(Vector3 positionA, Vector3 positionB, float radius)
{
if (Vector3.SqrMagnitude(positionA - positionB) == 0) return 0f;
return (Mathf.Acos(Vector3.Dot(positionA.normalized, positionB.normalized)) * Mathf.Rad2Deg * Mathf.PI * radius) / 180f;
}
public static int SegmentIntersections(Vector3 start, Vector3 end, Vector3 center, float radius, out Vector3 intersection1, out Vector3 intersection2)
{
Vector4 data = ComputeSegmentIntersection(start, end, center, radius);
intersection1 = Vector3.zero;
intersection2 = Vector3.zero;
if (data.w < 0)
{
return 0;
}
float mu;
if (data.w == 0)
{
mu = -data.y / (2 * data.x);
intersection1 = start + mu * (end - start);
return 1;
}
if (data.w > 0)
{
Vector3 pa = Vector3.zero;
Vector3 pb = Vector3.zero;
mu = (-data.y + Mathf.Sqrt(Mathf.Pow(data.y, 2) - 4 * data.x * data.z)) / (2 * data.x);
pa = start + mu * (end - start);
mu = (-data.y - Mathf.Sqrt(Mathf.Pow(data.y, 2) - 4 * data.x * data.z)) / (2 * data.x);
pb = start + mu * (end - start);
float da = Vector3.Distance(start, pa);
float db = Vector3.Distance(start, pb);
if (da < db)
{
intersection1 = pa;
intersection2 = pb;
}
else
{
intersection1 = pb;
intersection2 = pa;
}
return 2;
}
return 0;
}
private static Vector4 ComputeSegmentIntersection(Vector3 start, Vector3 end, Vector3 center, float radius)
{
Vector3 segment = end - start;
float a = segment.sqrMagnitude;
Vector3 offset = start - center;
float b = 2 * (segment.x * offset.x + segment.y * offset.y + segment.z * offset.z);
float c = Mathf.Pow(center.x, 2) + Mathf.Pow(center.y, 2) + Mathf.Pow(center.z, 2) + Mathf.Pow(start.x, 2) + Mathf.Pow(start.y, 2) + Mathf.Pow(start.z, 2) - 2 * (center.x * start.x + center.y * start.y + center.z * start.z) - Mathf.Pow(radius, 2);
float i = b * b - 4 * a * c;
return new Vector4(a, b, c, i);
}
// from http://mathproofs.blogspot.fr/2005/07/mapping-cube-to-sphere.html
public static Vector3 CubeToSphere(Vector3 position, float radius = 0.5f)
{
Vector3 result = Vector3.zero;
float x2 = position.x * position.x;
float y2 = position.y * position.y;
float z2 = position.z * position.z;
result.x = position.x * Mathf.Sqrt(1 - y2 * 0.5f - z2 * 0.5f + (y2 * z2) / 3f);
result.y = position.y * Mathf.Sqrt(1 - z2 * 0.5f - x2 * 0.5f + (z2 * x2) / 3f);
result.z = position.z * Mathf.Sqrt(1 - x2 * 0.5f - y2 * 0.5f + (x2 * y2) / 3f);
return result * radius;
}
// thanks to Boby, the god of Maths
public static Vector3 SphereToCube(Vector3 position, float size = 0.5f)
{
int i0, i1, i2;
position = position.normalized;
float xs = position.x;
float ys = position.y;
float zs = position.z;
float sx = Mathf.Sign(xs);
float sy = Mathf.Sign(ys);
float sz = Mathf.Sign(zs);
float[] e = new float[3];
xs = Mathf.Abs(xs);
ys = Mathf.Abs(ys);
zs = Mathf.Abs(zs);
float x = xs;
float y = ys;
float z = zs;
float t;
if (y >= x && y >= z)
{
i0 = 0; i1 = 2; i2 = 1;
x = xs; y = zs; z = ys;
e[i2] = sy;
t = sy;
sy = sz;
sz = t;
}
else if (z >= x)
{
i0 = 0; i1 = 1; i2 = 2;
x = xs; y = ys; z = zs;
e[i2] = sz;
}
else
{
i0 = 2; i1 = 1; i2 = 0;
x = zs; y = ys; z = xs;
e[i2] = sx;
t = sx;
sx = sz;
sz = t;
}
if (x < 0.0001f)
{
e[i0] = 0f;
e[i1] = sy * Mathf.Sqrt(2f - 2f * z * z);
position.x = e[0];
position.y = e[1];
position.z = e[2];
return position * size;
}
else if (y < 0.0001f)
{
e[i1] = 0f;
e[i0] = sx * Mathf.Sqrt(2f - 2f * z * z);
position.x = e[0];
position.y = e[1];
position.z = e[2];
return position * size;
}
float x2 = x * x;
float y2 = y * y;
e[i1] = Mathf.Sqrt(1.5f - x2 + y2 - Mathf.Sqrt(x2 * x2 + y2 * y2 - 3f * (x2 + y2) - 2f * x2 * y2 + 2.25f));
e[i0] = x / Mathf.Sqrt(0.5f - e[i1] * e[i1] * 0.5f + e[i1] * e[i1] / 3f);
e[i0] = Mathf.Abs(e[i0]) * sx;
e[i1] = Mathf.Abs(e[i1]) * sy;
position.x = e[0];
position.y = e[1];
position.z = e[2];
return position * size;
}
}
LibNoise
///<summary>
/// Returns the value of the mathematical constant PI.
///</summary>
public static readonly double PI = 3.1415926535897932385;
///<summary>
/// Returns the square root of 2.
///</summary>
public static readonly double Sqrt2 = 1.4142135623730950488;
///<summary>
/// Returns the square root of 3.
///</summary>
public static readonly double Sqrt3 = 1.7320508075688772935;
///<summary>
/// Returns PI/180.0, used for converting degrees to radians.
///</summary>
public static readonly double DEG_TO_RAD = PI / 180.0;
///<summary>
/// Returns noise mapped to the given location in the sphere.
///</summary>
public double GetValue(double latitude, double longitude)
{
if (SourceModule == null)
throw new NullReferenceException("A source module must be provided.");
double x=0, y=0, z=0;
LatLonToXYZ(latitude, longitude, ref x, ref y, ref z);
return SourceModule.GetValue(x, y, z);
}
protected void LatLonToXYZ(double lat, double lon, ref double x, ref double y, ref double z)
{
double r = System.Math.Cos (DEG_TO_RAD * lat);
x = r * System.Math.Cos(DEG_TO_RAD * lon);
y = System.Math.Sin(DEG_TO_RAD * lat);
z = r * System.Math.Sin(DEG_TO_RAD * lon);
}
Sorry, I don’t understand this that much, (I’m in 7’nth grade)
What do I do with this and once I generated my heightmap how do I place it on the planet??
bump
Post your heightmap texture, i will create an example script for you.
If you plan to create a planet, you will need more advanced systems like LOD and Multi-threading.
@dyox
Here,
Thanks for the examples…
How do I add LOD to this???
Do I add more verts near the character and less away?
EDIT:
I know it isn’t a heightmap that aligns but I can change it if you can give me the base examples
@dyox
Are you still there?
@dyox ?
Bump!
Yes, no time for the moment, i will upload something asap.
But it’s very simple, take a cube, size 1,1,1. Create each face (Vertices/Indices), and move them around origin (0,0,0) using formula on SphereMath i posted above. (Move each vertex on array)
@dyox
Can you show your example?
@dyox
You still there?
It’s the max i can do for you :
-Dx11 shader with heightmap. (you can move vertices directly inside code if you want, but it’s useless at this scale without a correct LOD system)
I can not help you to create a planet system like kerbal. Here it’s just a simple sphere generator.
Link : Dropbox - File Deleted - Simplify your life
wow thank you @dyox
So this only works with dx11?
nice
@dyox I know this is old, but do you still have this? I would love to have a play around with it.
@dyox Could you share the rar file again?
I’m having some trouble going from a 256x256 heightmap to a cube sphere
Especially with the upper and lower faces
Thanks!






