- Home /
Adjusting strange Vector3.Normalize behaviour
I'm trying to create 6 planes and normalize the vertices to map it to a sphere, however I'm getting some strange behaviour making my results more like an egg than sphere.
int resolution = 32;
int height = 32;
int width = 32;
for(int y=0;y < height;y++){
for (int x=0; x < width; x++){
Vector3 vertex = new Vector3(x,0,y);
vertex += new Vector3(-resolution * 0.5f,resolution * 0.25f,-resolution * 0.5f);
vertex = Vector3.Normalize(vertex);
}
}
Anyone know how I can solve this issue?
Cheers, C.
Your picture isn't showing for me. And we'll probably need some code to look at.
@Dave updated the question with some example code, it's probably all in the picture though, I'll try add again.
Answer by Dave-Carlile · Dec 21, 2012 at 04:26 PM
I'm not completely sure what the issue is with your code. Is there a reason you're adding resolution * 0.25 for the y coordinate, but using 0.5 for the x and z?
Try this:
Vector3 vertex = new Vector3(x, 0, y);
// normalize it, move out 10 units from the "center"
vertex = vertex.normalized * 10.0f;
It should be more spherical that way, but you won't end up with uniform spacing.
What you need is a better function for mapping the coordinates. The code below is what I used for my procedural planet experiments using XNA (just released the full C# source code a couple of days ago). It should mostly work as is, but you'll need to change the Sqrt function call to Unity's version.
The local coordinates of each cube face must be in the range -1 to 1. In other words, the full cube is centered at <0, 0, 0>. Once you get the result (the coordinate mapped to a unit sphere) you can multiply it by the desired sphere radius.
/// Given coordinates in the [-1,1] range, maps the vector as if it were
/// a cube deformed into a sphere. The output vector is on the surface of
/// the unit sphere.
/// URL: http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
public static Vector3 CubeToSphereMapping(float x, float y, float z)
{
float x2 = x * x;
float y2 = y * y;
float z2 = z * z;
float x2Half = x2 * 0.5f;
float y2Half = y2 * 0.5f;
float z2Half = z2 * 0.5f;
return new Vector3(x * (float)Math.Sqrt(1.0f - y2Half - z2Half + y2 * z2 / 3.0f),
y * (float)Math.Sqrt(1.0f - z2Half - x2Half + z2 * x2 / 3.0f),
z * (float)Math.Sqrt(1.0f - x2Half - y2Half + x2 * y2 / 3.0f));
}
Thank you for the source! I've been wanting something to use as reference for this, done a lot of the hard work but I need to tidy it up with better methods. thats amazing thank you. :D
Answer by Owen-Reynolds · Dec 21, 2012 at 04:25 PM
That snippet makes a single, 32x32 vert plane. Since you fill in slots x and z, it looks like a "floor" section, which goes right and away from (0,0,0). Then the code sort of moves it to be the top face.
The resolution line pulls X and Z 16 left and 16 towards you, which is almost centered on you. Almost, since your loops go from 0 to 31. Makes 32 verts across, but only 31 faces, for a total width of 31 (typical fencepost math.) So should be using 15.5 to center. Or maybe you want 32 faces across, so want to use <=
for the loops. Then 16 would be correct.
The middle value +resolution*0.25f
lifts it by 8, making it the roof. Should be 16 (or maybe 15.5, again.) Think about the pre-normalized cube. Each side is 32x32 -- 16 up and 16 down, so this needs to be 16 up to meet them. To error check, if the side verts are 16 over and 16 up, that makes 45 degrees (so the top face bends to cover a correct 90 degrees of sky.)