#calculate normals for sine wave vertex displacement

41 messages · Page 1 of 1 (latest)

opal sierra
#
uniform vec3 albedo : source_color;

vec4 wavetest(float x, float z, float time) {
    float height = sin(x) + cos(z);
    vec3 tangent = vec3(1.0, 0.0, cos(x));
    vec3 binormal = vec3(0.0, 1.0, cos(z));
    vec3 normal = cross(binormal, tangent);
    return vec4(normal, height);
}

void vertex() {
    vec4 i = wavetest(VERTEX.x, VERTEX.z, TIME);
    VERTEX.y = i.a;
    NORMAL = i.rgb;
}

void fragment() {
    ALBEDO = albedo;
    METALLIC = 0.0;
    ROUGHNESS = 1.0;
}
half spruce
#

I actually did this as well a few weeks ago, so I can help if you have any questions. Though I only barely understand the math :)

What helped me was looking at the source code and the sources he used as a reference. For normal calculation, you want to look at equations 6b and 7 and/or code at around line 98 (though it's a bit hard to follow and you need to convert it to gdshader from HLSL as well).
https://github.com/GarrettGunnell/Water/blob/main/Assets/Shaders/Water.shader
https://developer.nvidia.com/gpugems/gpugems/part-i-natural-effects/chapter-1-effective-water-simulation-physical-models

I didn't even think about storing the height in an alpha channel, I just made different functions to calculate height and normals.

opal sierra
#

ive been tryingthe gpugems article, trying to copy the formulas they showed in there, but i keep being close but still wrong

half spruce
#

The thing that confused me for ages was mistaking the " ⋅ " symbol as multiplication instead of the dot product... felt like an idiot once I realised it. xD

Btw feel free to ping me if you need help.

opal sierra
#

oh wow thats a game changer

#

i didnt konw that at all

#

i thought it was multiplication

#

thanks man

opal sierra
#

so this is what i got now:

#
shader_type spatial;
uniform vec3 albedo : source_color;

uniform float heightMulti = 1.0;
uniform float speedMulti = 1.0;

const float wavelength = 4.0;
const float waveheight = 0.7;
const float wavespeed = 1.0;
const vec2 direction = vec2(1.0, 5.0);


vec4 wavestuff(float x, float z, float time) {
    float height = 0.0;
    float binormal_value = 0.0;
    float tangent_value = 0.0;
    
    for(int i = 0; i < 1; i++) { // for loop so i can add more sine waves into it later
        float freq = 2.0 / wavelength;
        float ampl = waveheight;
        float speed = wavespeed;
        vec2 dir = normalize(direction);
        
        height += ampl * sin(dot(dir, vec2(x, z)) * freq + (time * speed * speedMulti * freq));
        
        float value = freq*ampl*cos(dot(dir, vec2(x, z))*freq + (time*speed*speedMulti*freq));
        binormal_value += dir.x * value;
        tangent_value += dir.y * value;
    }
    vec3 normal = vec3(-1.0 * binormal_value, -1.0 * tangent_value, 1.0);
    height = height / 2.0 * heightMulti;
    return vec4(normal, height);
}

void vertex() {
    VERTEX.y = wavestuff(VERTEX.x, VERTEX.z, TIME).a;
    NORMAL = wavestuff(VERTEX.x, VERTEX.z, TIME).rgb;
}

void fragment() {
    ALBEDO = albedo;
    METALLIC = 0.0;
    ROUGHNESS = 1.0;
}
#

this this creates this effect:

#

it works well, but only if the light is pointed 45 degrees down, but if i rotate the light it creates these weird thingies

#

@half spruce sorry to bother you, do you have any idea why this might be?

half spruce
# opal sierra

No clue to be honest, but the only relevant difference I can find is that I do this at the end.

NORMAL = normalize(vec3(-sine_normal.x, 1.0, -sine_normal.y));

sine normal would be wavestuff.rgb (ignore the minuses, you did that in wavestuff already)

opal sierra
#

oh wow copying that fixed most my problems

#

thats interesting

#

i wonder why now

half spruce
#

atm your guess is as good as mine xD

#

maybe I took it from acerola's code

opal sierra
#

hmmm maybe

#

ima try and experiment a bit with it just to actually understand it

#

its almost perfect

#

thanks a lot man

half spruce
#

I guess it ensures that the normal always faces up?

#

and yeah, line 336

i.normal = normalize(UnityObjectToWorldNormal(normalize(float3(-n.x, 1.0f, -n.y))));
opal sierra
#

i like made it make stack multiple sine waves

#

and it worked just as good as it did with one

#

but when i changed the roughness&metallic thingies it started showing these funny blobs

#

they disappear if i make the metallic 0 and roughness 1

#

and they are only visible if i look at them at certain angles

#

if i look at it from the top they rarely show

#

very suspicious

opal sierra
#

but that doesnt matter much

#

the initial problem was solved

#

as far as i know

#

thanks man