Seams on noise WGSL shader, porting gdshader to wgsl (bevy)

137 views Asked by At

wgsl gdshader

left is wgsl, right is gdshader

Bevy MRE here

I am trying to port a water shader written in gdshader to WGSL (in Bevy). However I noticed that there is some seaming going on. After some time I figured out it's that the blur of the noise isn't transitionless.

This strucks me as extremely weird as it works seamless in godot, but creates these ugly edges in WGSL (Bevy). The code I use in the .wgsl shader. Also in this MRE repo.

fn rand(uv: vec2<f32>) -> f32 {
    return (fract(sin(dot(uv.xy, vec2(23.53, 44.0))) * 42350.45));
}

fn noise(uv: vec2<f32>) -> f32 {
    let i: vec2<f32> = floor(uv);
    let j: vec2<f32> = fract(uv);
    let blur: vec2<f32> = smoothstep(vec2<f32>(0.0, 0.0), vec2<f32>(1.0, 1.0), j);

    let a: f32 = rand(i);
    let b: f32 = rand(i + vec2<f32>(1.0, 0.0));

    return mix(a, b, blur.x);
}

@fragment
fn fragment(in: VertexOutput) -> @location(0) vec4<f32> {
    let UV = in.uv * 10.0;
    return vec4<f32>(vec3<f32>(1.0) * noise(UV), 1.0);
}

The .gdshader is as far as I can tell exactly the same, so I assume it's either WGSL or Bevy that is doing some magic here. Or I am just incredibly blind.

float rand(vec2 input){
    return fract(sin(dot(input,vec2(23.53,44.0)))*42350.45);
}

float noise(vec2 input){
    vec2 i = floor(input);
    vec2 j = fract(input);
    vec2 blur = smoothstep(0.0, 1.0, j);

    float a = rand(i);
    float b = rand(i + vec2(1.0, 0.0));

    return mix(a, b, blur.x);
}

void fragment(){
    COLOR = vec4(vec3(1.0) * noise(UV * 10.0), 1.0);
}

How can I get rid of the transition issues? I know that using pre backed noise textures is much better for performance and all, but that is not my concern right now. I don't understand why the behaviour differs here.

On a side note, I tried debugging the UV and fract, and it looked like godot and WGSL (bevy) differed here. Not sure if that was an optical illusion or not though. But it would explain the difference in behaviour. Also note that the colors in the images are different even though we practically have the same values. This further suggests to me that there are differences in either UV itself or fract.


Okay so I figured out that the color difference stems from this fact, the color space is different. So you have to convert to linear color space, i.e.

fn srgb2lin(color: vec3<f32>) -> vec3<f32> {
    let in_c_lo: vec3<f32> = color / 12.92;
    let in_c_hi: vec3<f32> = pow((color + 0.055) / 1.055, vec3<f32>(2.4));
    let in_s: vec3<f32> = step(vec3<f32>(0.04045), color);
    
    return mix(in_c_lo, in_c_hi, in_s);
}

Still no clue why I get seams though. Any help or guidance is greatly appreciated.

0

There are 0 answers