2
\$\begingroup\$

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:

enter image description here

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.

enter image description here

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:

enter image description here

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

glm::vec3 dimensions = glm::vec3(radius,radius,radius);

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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

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

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

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        img2.SetPixel(z,radius-1-y,0,noise);
    }
}

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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        img4.SetPixel(radius-1-z,x,0,noise);
    }
}

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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        img5.SetPixel(y,radius-1-x,0,noise);
    }
}

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

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        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.

\$\endgroup\$
  • \$\begingroup\$ 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? \$\endgroup\$ – akaltar Apr 7 '15 at 12:13
  • \$\begingroup\$ 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". \$\endgroup\$ – akaltar Apr 7 '15 at 12:19
  • \$\begingroup\$ @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 \$\endgroup\$ – NeomerArcana Apr 7 '15 at 13:35
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ – mklingen Apr 7 '15 at 16:11
  • \$\begingroup\$ 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. \$\endgroup\$ – akaltar Apr 7 '15 at 16:14
2
\$\begingroup\$

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:

enter image description here

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)
    {
        glm::vec3 pointDirection = glm::normalize(glm::vec3(radius-1,z,y)-origin);

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

glm::vec3 dimensions = glm::vec3(radius/2,radius/2,radius/2);

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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

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

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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        img3.SetPixel(radius-1-(z-origin.x+dimensions.z),x-origin.x+dimensions.x,0,noise);
    }
}

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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

        img5.SetPixel(y-origin.y+dimensions.y,radius-1-(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;

        float noise = noise_function(pointOnSphereAdjustedForCenter.x,    pointOnSphereAdjustedForCenter.y,pointOnSphereAdjustedForCenter.z);

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

Finally:

enter image description here

enter image description here

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.