Calculate normal of sine

Godot Version

v4.2.2.stable.official [15073afe3]

Question

I’m trying to calculate the normal from a trigonometric equation. Since the derivative of sine is cosine, I should be able calculate the normal vectors quite easy, with the caveat that i suck. It creates the correct pattern on the plane, but:

  • It doesn’t adjust to rotation.
  • Colors are wrong
  • For some reason there are no shadows at certain camera angles, and only shadows at others.
  • I get different hues for Vertex or Fragment normals.
  • Vertex shadows behaves the best, but with visual banding.

Fragment normal:

Vertex normal:

shader_type spatial;

uniform float amplitude = 0.1;
uniform float period = 2.0;
uniform float speed = 0.1;

varying float trig_data_x;
varying float trig_data_y;
void vertex() {
	trig_data_x = (UV.x - TIME * speed) * period * PI;
	trig_data_y = (UV.y - TIME * speed) * period * PI;
	VERTEX.y += sin(trig_data_x + trig_data_y) * amplitude * UV.x;
	//NORMAL = normalize(vec3(0.0, cos(trig_data_x + trig_data_y), 1.0) * amplitude * UV.x);
}
void fragment() {
	NORMAL = normalize(vec3(0.0, cos(trig_data_x + trig_data_y), 1.0) * amplitude * UV.x);
	ALBEDO = vec3(0.5, 0.0, 0.7);
}

In above code I call the same equation twice, once with sine for vertex offset, and once with cosine for normal.

I believe I solved it. Updated my derivative skills. I need to calculate both derivative of x and y (not only x). And when using NORMAL in fragment, I believe it’s viewspace? So I had to package my vector as a normal map. Visually I get the same result in vertex normal as for fragment normal_map. Though I think it looks a bit crushed. And I though fragment was per pixel and would boost shadows a bit?

The method for calculate normal I see often is finite partial derivative, where a small offset is used to calculate the normal. Which means we have to call the original function (sineMovement) three times.
By creating a new function with derivative, granted a bit larger, there is less calculations to be done, maybe half as much. At least that was the idea.

I’m gonna do an example of finite partial derivative as well and compare the result.

shader_type spatial;

uniform float speed;
uniform float period;
uniform float amplitude;

vec3 to_normalmap(vec3 n){
	n *= vec3(1.0, 1.0, -1.0);
	n = n / 2.0 + 0.5;
	n = vec3(n.x, n.z, n.y);
	return n;
}

// Function to calculate the sine movement
float sineMovement(vec2 pos) {
    float data_x = (pos.x - TIME * speed) * period * PI;
    float data_y = (pos.y - TIME * speed) * period * PI * 2.0;
    return sin(data_x + data_y) * amplitude * pos.x;
}

// Function to calculate the gradient of the sine movement for normal
vec2 sineMovementGradient(vec2 pos) {
    float data_x = (pos.x - TIME * speed) * period * PI;
    float data_y = (pos.y - TIME * speed) * period * PI * 2.0;
    float z = data_x + data_y;
    float dfdx = cos(z) * period * PI * amplitude * pos.x + sin(z) * amplitude;
    float dfdy = cos(z) * period * PI * 2.0 * amplitude * pos.x;
    return vec2(dfdx, dfdy);
}

void vertex() {
    float offset = sineMovement(UV);
    VERTEX.y += offset;
	vec2 gradient = sineMovementGradient(UV);
    //NORMAL = normalize(vec3(-gradient.x, 1.0, -gradient.y));
}

void fragment() {
    vec2 gradient = sineMovementGradient(UV);
    vec3 normal = normalize(vec3(-gradient.x, 1.0, -gradient.y));
	NORMAL_MAP = to_normalmap(normal);
	ALBEDO = vec3(0.9, 0.9, 0.05);
}

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.