(February 2026) Monthly WIP Screenshot Thread
jMonkeyEngine Hub
February 22, 2026
uniform vec4 m_MainColor;
uniform vec4 m_NoiseColor;
uniform float m_NoiseSize;
uniform float m_NoiseAmount;
uniform float m_NoiseOscillationChance;
uniform float m_NoiseOscillationForce;
uniform float m_Progress;
in vec3 mPosition;
float hash(vec2 p) {
p = fract(p * vec2(123.34, 456.21));
p += dot(p, p + 45.32);
return fract(p.x * p.y);
}
float rand(vec2 co, float probability, float seed) {
float gridSize = 10.0;
vec2 gridPos = floor(co * gridSize);
return step(1.0 - probability, hash(gridPos + seed));
}
vec4 generateWave(
float phase,
float frequency,
float width,
float opacity
) {
vec4 waveColor = m_MainColor;
float waveProgress = pow(abs(sin((phase + m_Progress * frequency) + (mPosition.y))), 1.0 / width);
waveColor.a *= waveProgress;
waveColor.a *= opacity;
waveColor.rgb *= smoothstep(0.0, 0.8, waveColor.a);
return waveColor;
}
void main(){
vec4 wavesColor =
generateWave(0.0, 0.05, 0.1000, 0.4) +
generateWave(0.3, 0.02, 0.0750, 0.4) +
generateWave(0.7, 0.08, 0.2000, 0.4) +
generateWave(0.0, 0.10, 0.0100, 0.6) +
generateWave(0.0, 0.20, 0.0001, 1.0);
float noiseAmount = m_NoiseAmount;
float noiseOscillation = rand(vec2(0.0), m_NoiseOscillationChance, m_Progress) * m_NoiseOscillationForce;
noiseAmount += noiseOscillation;
float randomValue = rand(mPosition.xy / m_NoiseSize, noiseAmount, m_Progress);
float noiseInfluence = max(randomValue - wavesColor.a, 0.0);
vec4 noiseColor = m_NoiseColor * noiseInfluence;
gl_FragColor = wavesColor + noiseColor;
}
This is the fragment shader I am using. The most notable difference with respect to the pseudo-random functions I have found on the web was the usage of hashing + step threshold rather than sinusoidal functions. Using sin, the wavy artifacts are evident at low resolutions, while I needed my randomness to look like a random grid of binary 0-1 values.
Discussion in the ATmosphere