dilevin / computer-graphics-shader-pipeline

Computer Graphics Assignment about the Shader Pipeline
2 stars 5 forks source link

Perlin Noise scaling issues #39

Open ginkxo opened 4 years ago

ginkxo commented 4 years ago

I'm trying to find a way to scale the Perlin noise "grid cell size" in order to get "smaller blobs" where possible. This is what my normal Perlin noise looks like at scale = 1 aka (x0, y0, z0) = (0,0,0) and (x1, y1) = (1,1,1) for an example unit cube.

perlin01

I've figured out a scaling technique that creates smaller-scaled grid cells around a particular input point. So the example below is scale = 4 where (x0, y0, z0) = (0,0,0) and (x1, y1, z1) = (0.25, 0.25, 0.25). It seems to be reducing the cell "regions" but it has this blocky characteristic:

perlin02

Would this be an issue of the calculation of the gradients, or would it be an issue of the linear interpolation? I'm under the impression it might be the latter (since the gradient variances seem to be working okay). If it is a linear interpolation issue, is there something I might have missed with this scaling in performing the linear interpolation just with these values (e.g. since the cells are not unit cells anymore, is this causing an issue with the interpolation?)

Thanks for any help.

abhimadan commented 4 years ago

Yes, these issues are typically caused by the interpolation. Make sure that you're only providing values in the range [0,1] to the interpolation function, since it's only designed to produce smooth results in that domain.

ginkxo commented 4 years ago

Thanks. I realized that I was calculating the "raw weights" (before putting them in the smooth step function) as just, e.g. raw_wx = st.x - x0 . So while this worked fine for determining the correct weighted path distance for a unit cube of size 1, e.g. raw_wx = 3.75 - 3.00 = 0.75, I realized this was an issue for unit cubes of different sizes, e.g. raw_wx = 3.75 - 3.50 = 0.25, but 3.75 is in fact 0.5 of the path between 3.50 and 4.00 since the box is size 0.5.

I tried to correct this as follows: raw_wx = (st.x - x0) / (1. / scaling_factor). So for a scaling factor of size 4, and a point with x coordinate x = 3.875, we have (0.875 - 0.75) / (1. / 4) = 0.5, which is appropriate since for a grid cell of sizes (1/4), the x coordinate 0.875 would be halfway or 0.5 between 0.75 and 1.

However, all this has done is make the gradient values steeper? Intuitively this makes me feel like this technique is somehow "narrowing" the smooth step curve, but I'm not certain how to interpret this

perlin03

abhimadan commented 4 years ago

You shouldn't do this scaling in the Perlin noise function. It's designed so that it will interpolate smoothly within cubes of an integer grid, and be continuous between cubes. Since your interpolation inputs don't reach 0 or 1 for each cube, the noise function won't be smooth.

Do the scaling outside the function, so that you can change the frequency of the noise for different uses.

ginkxo commented 4 years ago

Thank you. Changing the frequency through adjustment of the Perlin Noise input coordinate produces more of the subdivisions above but has the same kind of "blocky" / "nonsmooth" output (basically identical to the last image posted above). I feel like I might be conceptually missing something here.

My smoothstep function appropriately returns 0 and 1 for the respective f <= 0 and f >= 1 (have also tried fiddling with these bounds, no luck), and the appropriate function as per the original paper for the "easing" / "smoothness". So as far as I am aware this smoothstep function should be fine (putting aside the improvement polynomial for the other file). The frequency scaling occurring at the external level outside the Perlin noise function itself (as a change to input) means that in theory this shouldn't be diminishing smoothness as all values are between [0,1] still, but this does not appear to be the case. As far as I am aware the linear interpolation technique is a simple path linear interpolation and so relies on these interpolant weights and should not need any changes. (sorry to keep pressing this! I'm truly stumped as to why none of this scaling is working properly)

abhimadan commented 4 years ago

What I was trying to say before is that your cubes should be 1x1x1, and you only change the number of cubes to determine the frequency. Since you're dealing with a unit sphere (in model space), this means shifting and scaling the input so that you tile the space with more cubes, not scaling within the Perlin noise function.

If your cubes have a smaller side length (which is what your scaling inside Perlin noise is doing), then your interpolation will not be smooth, since the interpolation weight won't reach 1 even when you reach the cube face it's associated with, but when you cross over to the next cube, its weight will suddenly be 1.

The increased sharpness you noticed is because this is a value discontinuity which creates jumps in the texture, while before you only had a derivative discontinuity, which produces cusps in the texture.

ginkxo commented 4 years ago

at the moment, my Perlin noise function has removed all its scaling and works on unit cubes around the input. When I scale the input components by some factor e.g. 4.0 and then send this as an input to the Perlin noise function, the discontinuities return despite this being a scaling of the input rather than any internal scaling of the Perlin noise components.

For reference my input vector is sphere_fs_in aka the point on the unit sphere. I guess what is happening here is the scaling itself is changing the coordinates away from unit sphere coordinates and this is causing the discontinuity issues. I think I'm confused about how changing the scale of the input point would necessarily create more cells and specifically how do we interpret a "3D seed" to the Perlin noise. (I've also tried pos_fs_in and even view_pos_fs_in with the same issues).

abhimadan commented 4 years ago

The 3D seed is determined by the position of the unit cube in space. For example, if your cube was [0,1]x[0,1]x[0,1], then you could represent that with its corner (0,0,0), and pass that as the seed to random_direction. So if your input values cover a larger range, you get more cells because there are more integer points covered in 3D space.

I unfortunately don't think I can help you further without debugging your code for you, so here are some tips when debugging this part that may help: