Closed scurest closed 2 months ago
Thanks for having a proper look at what I did back then. :)
@scurest Very accurate work. The result is really good. I tested several cases where noise is used and didn't find any regressions. The noise looks pretty random, as good as with noise textures. Thanks!
Previously snoise(), snoiseRGB().r, and snoiseA() were always the same, because they sampled the noise texture at the same location. Does this property need to be maintained?
I think, no. We need a random input for each color channel, that's all.
snoiseRGB().r will now be different than the others, because it uses a different hash function.
ok.
I have not tested the snoiseRGB() or snoiseA() functions, in particular the enableHiresNoiseDithering option. I'm happy to do so if you can tell me how/where to test it.
As I remember, snoiseA() is used in SM64 with Vanish Cap (invisibility hat). snoiseRGB() is used for noise color dithering. It sometimes is used in cut-scenes. As I remember, it is used in Zelda MM intro, when Link falls into the pit, and in "remembering Zelda" black-and-white cut-scene. I checked these scenes, no problems found.
@mudl0rd
Thanks for having a proper look at what I did back then. :)
Yes, the same idea, but seems to work properly this time.
@gonetz So this broke shader compilation on GLES (#2837) because
uniform float uNoiseSeed;
needs to have a precision qualifier
uniform mediump float uNoiseSeed;
which is an easy fix.
However now that I think about precision, I'm pretty sure the hash functions require highp
for p3
; if mediump
is a float16, the noise will always be 0. This creates a problem for old GLES implementations that do not have highp
. Can you confirm if those are supported? If they are, this will need to reverted, or the hashing constant will need to be tweaked somehow.
It looks to me like GLideN64 does try to support them (by replacing highp
with mediump
)
Shaders currently get noise by sampling a 640x580 noise texture with the fragment location. Variation over time is provided by keeping a pool of 30 noise textures and binding a different one every frame.
This PR replaces this with hashing the fragment location and a frame-varying seed value, obviating the need for noise textures.
Noise seed
uNoiseSeed is updated every frame with the low byte of the frame count, ie. it's a simple counter with period 256. This is unlike the noise textures, which would cycle in a random order with long period (but never repeating on two consecutive frames). I don't think this matters, but I can easily change it to the old behavior if you like.
The seed changes automatically every frame and does not need an explicit
update()
when noise is used.Hash function
The hash functions used are Dave Hoskins's Hashing without Sine GLSL functions that take 1-4 integer-spaced float inputs and produce 1-4 float outputs in [0,1).
Noise resolution
One noise value is generated per native-res pixel, ie. as by
To match this, the hash function is passed the native-res pixel location
Note that, as pointed out in #1474, generating high-res noise would be as easy as switching to
vec2 coord = gl_FragCoord.xy
. But that is not proposed in this PR.Correlations between noise functions
Previously
snoise()
,snoiseRGB().r
, andsnoiseA()
were always the same, because they sampled the noise texture at the same location. Does this property need to be maintained?snoiseRGB().r
will now be different than the others, because it uses a different hash function.Font atlas
All noise texture code has been removed, except the
noiseFormat
etc. variables. These are also used for the font atlas, so they've been renamedfontFormat
, etc. to reflect their current use.Testing
snoise()
function works in the Kirby 64 intro.I have not tested the
snoiseRGB()
orsnoiseA()
functions, in particular theenableHiresNoiseDithering
option. I'm happy to do so if you can tell me how/where to test it.Thanks for considering.