# Stepping through 3D noise to generate a cubemap for a sphere

This is somewhat related to a previous question I asked How to create a seamless cubemap noise texture?

I have managed to successfully step through a 3D noise function to create a cubemap texture which I'm then applying to an icosphere. This is done by stepping though it as suggested above.

However, I'm getting some mixed results on some of my edges:

In this picture, I'm not sure if it's clear but you can see the seam up the middle. However, this "seam" is actually perfectly smooth from a noise perspective. The problem is that both of these cube faces seem to be distorted, like they are being dragged up the sphere.

This picture shows one of the corners. Again, the noise is perfectly fine, but I think it's obvious that the way I'm stepping through my noise along a sphere surface is wrong. It's like it's going in opposite directions?

From RenderDoc I was able to retrieve the actual cubemap generated:

Which I think shows the this problem is only apparent on a few face edges, or at least, not all of them.

The code I'm using goes through all six faces individually (so that I don't have to generate the noise from inside the sphere, just the surface). The code looks like this:

...
glm::vec3 origin = glm::vec3(100,100,100); // really whatever, just some arbitrary point
int radius = 100; // the "size" of my textures

ImageObject img1;
ImageObject img2;
ImageObject img3;
ImageObject img4;
ImageObject img5;
ImageObject img6;

for(int y = radius-1; y >= 0; --y)
{
for(int z = 0; z < radius; ++z)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(0,y,z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

img1.SetPixel(y,z,0,noise);
}
}

for(int y = 0; y < radius; ++y)
{
for(int z = 0; z < radius; ++z)
{
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

}
}

for(int x = radius-1; x >= 0; --x)
{
for(int z = 0; z < radius; ++z)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(x,0,z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

img3.SetPixel(z,x,0,noise);
}
}

for(int z = 0; z < radius; ++z)
{
for(int x = 0; x < radius; ++x)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(x,0,z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

}
}

for(int y = radius-1; y >= 0; --y)
{
for(int x = 0; x < radius; ++x)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(x,0,z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

}
}

for(int y = radius-1; y >= 0; --y)
{
for(int x = 0; x < radius; ++x)
{
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

img6.SetPixel(y,x,0,noise);
}
}


I'm sure that the problem is the way that I'm stepping through each cube face. I'm stepping in different directions. I had to do this because it was the only way to get my cubemap textures to line-up; but now that they're lined up, they've got something going wrong with them.

• At first I would try to simplify this by removing the origin parameter, perhaps also try another noise function, just in case, and see what that yields. Also, it seems that here you are always setting img1 only, shouldn't you be setting a different one each iteration? Apr 7 '15 at 12:13
• Also you are mixing up where you do the coordinate correction. You should do it everywhere in the for "init" and not in the for "body". Apr 7 '15 at 12:19
• @akaltar thanks for your response. The code above isn't the complete code as it's also multithreaded; so I simplified. They each update their respective image. I'm not sure what your second comment means. Why wouldn't I adjust each coordinate? And I just tried removing the origin, no difference Apr 7 '15 at 13:35
• First, make sure that you can really map a point on the sphere to a coordinate in the cube map. From your code, it's unclear to me whether you're doing that correctly. Instead of drawing noise, try drawing a 3D grid, and make sure it ends up how you would expect. Apr 7 '15 at 16:11
• About my second comment, your code just seems hard to understand as it is currently. I would either use lookup tables to determine which coordinate is which way, or something similar. Apr 7 '15 at 16:14

Okay, I solved the problem.

As the guys commenting above pointed out, the code was weird. It wasn't really clear what was happening. This was a result of my brute forcing axis until the individual faces aligned.

However, it's what resulted in the above. So I've taken the time to draw on paper how each face should be stepped through and I found the answer.

It might not be immediately clear in the picture of the cubemap above but the whole noise is stretched. If you look at this reference:

You can see on my cubemap that the +Y, -X and +Z faces are stretched to the top left, and the other faces are stretched to the top right.

One of the things I was doing wrong was only sampling half of the noise, and then stretching it to cover the texture. This happened because where I was getting the direction from origin, was only ever in one direction along that axis.

E.g. Let's say my origin is at 20,20,20 and the radius is 10.

for(int y = radius-1; y >= 0; --y)
{
for(int z = 0; z < radius; ++z)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(0,y,z)-origin);


From the start of the loops this will be {0,9,0} - {20,20,20} which gives me {-20,-11,-20}, at the end it will be {0,0,9} - {20,20,20} which is then {-20,-20,-11}. This is the negative x axis BTW, the the direction is in both cases, negative on the x axis, so this is good.

But then on the positive X axis

for(int y = 0; y < radius; ++y)
{
for(int z = 0; z < radius; ++z)
{


I'm going to get at the start, {9,0,0} - {20,20,20} to give me result of {-11,-20,-20} and at the end of the loop: {9,9,9} - {20,20,20} and the result is {-11.-11,-11}!

Whoops! On both the positive and negative x axis (and this is the same for the other axis), I'm always sample from the negative direction on my where, but in one case I'm taking all the noise, in the other only half and stretching.

So that's why it matched up as well. It was from the same point and travelling back in the same direction. AND that's what gave my the stripe where it looked like it was being dragged up, it was in fact and mirror image, with one side of the mirror being stretched and distorted more than then other (so it wasn't immediately apparent).

A few things need to change. I needed to sample around the origin from the beginning and correct the positions for the texture later. This meant that I no longer has to screw around with which axis goes where either.

So the amended code should look like this:

...
glm::vec3 origin = glm::vec3(100,100,100); // really whatever, just some arbitrary point
int radius = 100; // the "size" of my textures

ImageObject img1;
ImageObject img2;
ImageObject img3;
ImageObject img4;
ImageObject img5;
ImageObject img6;

for(int y = origin.y-dimensions.y; y < origin.y+dimensions.y; ++y)
{
for(int z = origin.z-dimensions.z; z < origin.z+dimensions.z; ++z)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(origin.x-dimensions.x,y,z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

img1.SetPixel(y-origin.y+dimensions.y,z-origin.x+dimensions.z,0,noise);
}
}

for(int y = origin.y-dimensions.y; y < origin.y+dimensions.y; ++y)
{
for(int z = origin.z-dimensions.z; z < origin.z+dimensions.z; ++z)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(origin.x+dimensions.x,z,y)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

}
}

for(int x = origin.x-dimensions.x; x < origin.x+dimensions.x; ++x)
{
for(int z = origin.z-dimensions.z; z < origin.z+dimensions.z; ++z)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(x,origin.y+dimensions.y,z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

}
}

for(int z = origin.z-dimensions.z; z < origin.z+dimensions.z; ++z)
{
for(int x = origin.x-dimensions.x; x < origin.x+dimensions.x; ++x)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(x,origin.y-dimensions.y,z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

img4.SetPixel(z-origin.x+dimensions.z,x-origin.x+dimensions.x,0,noise);
}
}

for(int y = origin.y-dimensions.y; y < origin.y+dimensions.y; ++y)
{
for(int x = origin.x-dimensions.x; x < origin.x+dimensions.x; ++x)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(x,y,origin.z-dimensions.z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;

}
}

for(int y = origin.y-dimensions.y; y < origin.y+dimensions.y; ++y)
{
for(int x = origin.x-dimensions.x; x < origin.x+dimensions.x; ++x)
{
glm::vec3 pointDirection = glm::normalize(glm::vec3(x,y,origin.z+dimensions.z)-origin);
glm::vec3 pointOnSphere = pointDirection * dimensions;
glm::vec3 pointOnSphereAdjustedForCenter = pointOnSphere + origin;