godotengine / godot

Godot Engine – Multi-platform 2D and 3D game engine
https://godotengine.org
MIT License
90.63k stars 21.1k forks source link

NoiseTexture has always the same value for top left corner #47040

Open atngames opened 3 years ago

atngames commented 3 years ago

Godot version: v3.2.3.stable.official

OS/device including version: Linux Ubuntu 20.10 - NVIDIA Corporation TU117M / GeForce GTX 1650/PCIe/SSE2

Issue description: When creating a NoiseTexture without seamless, the top left of the texture is always the same value.

Steps to reproduce: Create a TextureRect Add a new NoiseTexture (to test it is easier with the following settings but they are not mandatory) Change the flags to remove FILTER Use a low period (0.1) Zoom on the top left pixel of the texture Change the seed multiple times, the top left pixel stays the same

Minimal reproduction project: test.zip

Calinou commented 3 years ago

@Zylann Is this a bug or expected behavior for OpenSimplex noise?

Zylann commented 3 years ago

If you change the seed I don't see why it would have the same pixel. We may check OpenSimplexNoise to see if it's a particularity of the old algorithm Godot is using, when given the (0,0) coordinate.

Note: period of 0.1 is extremely small, like 10 times smaller than a pixel, not sure if it makes sense here

Edit: Testing (0, 0) with OpenSimplexNoise and 3 different seeds, using default period, I indeed get 0 three times. I also tested OpenSimplex2 from FastNoiseLite, same result. Then Perlin from the same library... same result. So it might actually be expected, but I'm going to ask the author for more information.

KdotJPG commented 3 years ago

This is a side-effect of the noise grid, yes. Noise is comprised of a grid of points, each of which has a gradient vector. (0, 0) falls on one of those grid points, and the value of the gradient vector's extrapolation at its grid point is zero. Simplex/OpenSimplex use a triangular-type grid so you don't get the same squareness problems as Perlin, but it is still a grid originating from (0, 0). There are actually many of these points which evaluate at zero, they just blend in with the noise pattern as a whole.

If you can oversize the noise texture and sample from an offset starting point, you can mitigate this issue. But you may have thought of this already.

One thing that could conceal this issue for a single octave, and prevent it entirely for multiple octaves, would be to offset each octave individually, so that when multiple frequencies are combined the grid points never line up. This would need to be done inside the noise code, though. Perhaps if the OpenSimplexNoise module is ever upgraded in a way that changes its output, a new mode in it is added, or a new module is created -- particularly one that implements OpenSimplex2, then this approach should be used.

atngames commented 3 years ago

Thank you for those insights.

I actually ended up creating a (very easy lazy) WhiteNoise class module for my purpose.

I am currently changing the Noise module to allow for FastNoise's different Fractal types, add my WhiteNoise and allow to offset the texture creation.

The offset per octave is smart, I like it. I might add it too, someday (the modified module currently exceed my needs so I am a bit reluctant to spend some time improving it) .

I am not sure if an OpenSimplex2 implementation is needed, but I might add that too if anybody is interested. (But who else uses noises outside of shaders nowadays ?)

Thanks a lot for your comment @KdotJPG , it is an honor talking to you ;)

Zylann commented 3 years ago

I am not sure if an OpenSimplex2 implementation is needed, but I might add that too if anybody is interested. (But who else uses noises outside of shaders nowadays ?)

I do, for voxel generation. And I stopped using Godot's OpenSimplexNoise, it's slower than the new one in FastNoiseLite, and yet FastNoise2 is an order of magnitude faster. I never had to care about the origin being zero though^^