5
\$\begingroup\$

I have, so far, been able to create the vertices and UV coords etc for a sphere that would be textured with a cube map. I have also successfully loaded a cube texture from file and applied it to my sphere and it looks awesome.

So now, I want to randomly create a noise cube texture map to apply to my sphere.

I have a class which can create 1d, 2d, 3d and 4d noise. My problem is I don't know the math needed to sample a sphere map out of the cube, and then how to translate this to the 6 textures that make up with my cubemap.

I guess first I need to know how to first sample the points of a sphere in 3d; and then how to translate these to x,y,z coordinates for the 6 sides. I can probably work it out from there.

I would have thought this would be simple enough to Google, but I'm not finding what I need.

SOLUTION

For whomever comes along next, here's the answer. @Jason has the right idea below. Here's how I solved it:

  1. March through each of the faces of the cube and each UV coord for that face
  2. Normalize each position vector
  3. Multiply by the radius of your sphere. You now have the coordinates of the sphere edge
  4. These coordinates can be used to sample from your 3D noise function

You'll end up with each faces UV coordinates being filled with the noise that is at the spherical equivalents position in the noise.

(I hope that was in english). I will try to remember to update this later with full code once I've cleaned it up.

\$\endgroup\$
1
  • \$\begingroup\$ How did you texture a sphere with a cubemap? Could you share a code? \$\endgroup\$
    – Nolesh
    Apr 30, 2019 at 15:41

5 Answers 5

3
\$\begingroup\$

To generate noise which is isotropic, you need to sample from 3D space but from the surface of as sphere:

Projection points onto sphere

Here the black point is the location in space of the pixel in the image you want to generate the color for. Project it onto the unit sphere (the green point) by normalizing the vector from the origin (red), and then sample from your noise function (scale it up by a constant to get finer noise, or down to get softer noise). You will need functions to compute the x,y,z coordinates of a cube map pixel given the image dimensions, pixel x,y, and which face the pixel is on.

Note that classic Perlin noise has some serious artifacts when taking a 2D slice of 3D noise, so you should use another function, or add a bunch of randomly rotated copies of classic noise (which kinda hides the artifacts).

This noise will look distorted when you look at the raw images, but when rendered as a skybox it will appear uniform in every direction.

\$\endgroup\$
2
  • \$\begingroup\$ Thanks your comment sounds like exactly what I'm trying to do. But I'm still not sure how to do it. For example, how do I normalize the vector from the origin? \$\endgroup\$ Apr 1, 2015 at 6:57
  • \$\begingroup\$ Normalizing a vector just means dividing each component by the length. Any game focused vector library would have it. In formula v_norm = vector(v.x/v.length(), v.y/v.length(), v.z/v.length). Normalizing produces a vector of length 1 in the same direction as the original. This constant length is what makes the noise isotropic. \$\endgroup\$
    – user41442
    Apr 4, 2015 at 21:37
0
\$\begingroup\$

I have also successfully loaded a cube texture from file and applied it to my sphere and it looks awesome.

This implies that you've already calculated the UV's on the CPU and stored them in the vertices. Those same UV's should work for any cube textures that are similarly oriented since they all range from 0:1.

A diagram follows, in case it helps, but I think you're already doing this.

The gray sphere represents your skysphere.
The purple cube is just a cube with the same "radius" as the skysphere.
The green cube is a unit cube.

Given some arbitrary "forward" direction that corresponds to the cube map, and the normalized direction from each pixel world-coordinate to sphere-center, a few dot products will tell you which face to sample and how to convert the angle into a UV.

For example, when you are working with the top face, the normalized pixel world X and Z will become the UV. On the face shown below, Y and Z change but X is constant. The dot products range from -1:1 and UV's are 0:1 so you'll also need a linear scaling and translation i.e. (XZ + 1) / 2

sphere map diagram

The same, from above:
enter image description here

Any point within the face has an angle away from "face-forward" of -45:45. This corresponds to the dot range -1:1. Again, scaling to 0:1 range is trivial. This diagram occurs twice for each point; the face determines which of the 3 axis' go into the UV.

\$\endgroup\$
1
  • \$\begingroup\$ Thanks for your response. So, with the UV coordinates of my sphere, I know these are mapping directly to a texture. The "face" that they're on will give me the direction to project. That's all good, but the issue is that I need to first generate the textures from my noise function. Which means, I need to sample x,y,z coords from my noise. What these x,y,z coords are, how to calculate them given the size of a texture I want to generate, is what I'm stuck on. I imagine that these two things are related, but I can't work out how. \$\endgroup\$ Mar 31, 2015 at 9:28
0
\$\begingroup\$

Please confirm that my other answer is not-at-all or, less-, applicable, so I can delete it.

This is one way to "unwrap" a cube, (neglecting the bottom face (assuming there is a terrain of some kind)).

(right-handed)
For face 1:
U+ corresponds to Y+
V+ corresponds to Z+

For face 4:
U+ corresponds to X+
V+ corresponds to Y-

and so on..

unwrapped cube

\$\endgroup\$
10
  • \$\begingroup\$ I would leave it, only that it has good info in it. I think may not be explaining what I need very well... It's not warping the flat cube textures to a cube that I'm trying to do, it's the opposite. I'm trying to first work out how to get the 2D texture values from a 3D texture and project them onto a flat 2D texture; AND, how to do this math with a sphere. \$\endgroup\$ Mar 31, 2015 at 10:11
  • \$\begingroup\$ Please explain, on a higher level, what you are trying to do. You have sampled a cube-map onto the sphere. Are you, now, wanting to sample your sphere back into a (cube)texture? \$\endgroup\$
    – Jon
    Mar 31, 2015 at 10:19
  • \$\begingroup\$ Yes, so sampling a cube map onto a sphere. I've done this just to prove that I can do it when using a pre-made texture. Now I want to generate that texture using 3d noise. \$\endgroup\$ Mar 31, 2015 at 10:22
  • \$\begingroup\$ Ok, so you are wanting to generate a cube-mapped noise texture. Please post some details about the noise-generation code. What is it's input/output specifically. You can treat each face as it's own mini-texture, as shown by the smaller, green, UV coordinates. \$\endgroup\$
    – Jon
    Mar 31, 2015 at 10:24
  • \$\begingroup\$ The noise generation code isn't important. It works; but is limited to selecting noise from either x, x+y, x+y+z or x+y+z+w coordinates. It's output is just a float, just noise. What I need to know, is how to loop through x,y coordinates for each face of my cube, so that the noise is circular. Selecting the noise on the faces of the cube is easy enough, I've done that, but once it's projected back onto a sphere, the seams appear because the original selection wasn't circular along the surface of the sphere. \$\endgroup\$ Mar 31, 2015 at 10:29
0
\$\begingroup\$

As I done in my project Seamles Noise Generator

I suggest to apply a 3d noise (i.e. 3d perlin noise) on the cube surface and unwrap it like already suggested

And use a cube sphere aproach enter image description here

\$\endgroup\$
2
  • \$\begingroup\$ Thanks, I have a cube sphere already, so it's UV coords are mapped to the faces of a cube. Your suggestion to apply the noise to a cube surface, and then just apply it to my sphere... I've done this already, and it produced visible seams. Have I simply done this wrong? My thought was that my noise was generated from the x,y,z coords of the UV coords of a cubes surface, which would mean those right angles would produce visible seams. \$\endgroup\$ Mar 31, 2015 at 11:05
  • \$\begingroup\$ the quality detail of your 3d noise can make the difference. High detail is better. Or your UV mappin is not accurate? \$\endgroup\$ Mar 31, 2015 at 11:16
0
\$\begingroup\$

Your question is similar to what I'm doing , but I'm using libnoise , doing most of the work for me .Can generate 4 faces of a icoespher using libnoise(they fit perfectly in a icoesphere) and saving as bmp, but unfortunately , there must be some wrong in libnoise , which causes distortion in the top faces and down , looked at the code utils::NoiseMapBuilderSphere, which takes two latitudes and two longitudes and turns in an image and everything seems ok , the code looks like the first answer from user41442.

/*snipt from libnoise utils::NoiseMapBuilderSphere.*/
model::Sphere sphereModel;
sphereModel.SetModule (*m_pSourceModule);

double lonExtent = m_eastLonBound  - m_westLonBound ;
double latExtent = m_northLatBound - m_southLatBound;
double xDelta = lonExtent / (double)m_destWidth ;
double yDelta = latExtent / (double)m_destHeight;
double curLon = m_westLonBound ;
double curLat = m_southLatBound;

// Fill every point in the noise map with the output values from the model.
for (int y = 0; y < m_destHeight; y++) 
{
    float* pDest = m_pDestNoiseMap->GetSlabPtr(y);//get pointer to fill one slice of sphere, one at a time
    curLon = m_westLonBound;
    for (int x = 0; x < m_destWidth; x++) 
    {
        float curValue = (float)sphereModel.GetValue (curLat, curLon);
        *pDest++ = curValue;
        curLon += xDelta;
    }
    curLat += yDelta;
}

my code for gen faces Z+ Z- X+ X-:

for each face i change that :

heightMapBuilder.SetBounds (-45.0, 45.0, -45.0, 45.0); //Z+  front
heightMapBuilder.SetBounds (-45.0, 45.0,    45.0, 135.0);//X+ right
heightMapBuilder.SetBounds (-45.0, 45.0,   -225.0, -135.0);//Z- back
heightMapBuilder.SetBounds (-45.0, 45.0,  -135,-45 );//X-     left

just do not understand why it does not work with latitudes 45,90 and longitudes -180,180 for generating face top.

\$\endgroup\$
1
  • \$\begingroup\$ If it's using latitude and longitude it may be getting distorted at the poles. This is why I was using a cubemap projection to begin with. Basically, it's sampling at a different rate toward the poles, and when that's projected to texture, you get a distortion \$\endgroup\$ Nov 24, 2015 at 10:56

You must log in to answer this question.

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