



Reply From: 
Zylann 
Godot shading language is converted to GLSL but it doesn’t support the #
directives at all unfortunately. Enabling an extension would require to modify VisualServer
rasterizer_gles2.cpp
I think.
I had a quick look at the video and it would seem derivatives were an optimized way to get normals (I personally didn’t know it worked like that).
To do that manually, you can compute them in the vertex shader, using the same function you use to displace the water (same technique as heightmaps). Take the height at the vertex, then the height from neighbor positions in negative X and negative Z. From these 3 points you can compute the normal with a cross product.
You can also put your height calculation in a function to make this easier.
Wow, thanks for answering that fast !
I guess, modifying the cpp file would mean recompiling Godot right ? If so, I’ll just try to calculate them as you said.
I’m not sure how to access the VERTEX neighbors though. I see in this tutorial that it’s done through a heightmap with the following :
pos=VERTEX.xz
NORMAL = normalize(vec3(k  height(pos + vec2(0.1, 0.0), TIME), 0.1,
k  height(pos + vec2(0.0, 0.1), TIME)));
I don’t have a height map, so I replaced “height” by “apply_distorsion”:
v_step = 1/mesh_size //It's a square
vec3 vx= applyDistortion(VERTEXvec3(v_step,0,0),0.1); //x neighbor
vec3 vz= applyDistortion(VERTEXvec3(0,0,v_step),0.1); //z neighbor
VERTEX= applyDistortion(VERTEX,0.1);
I’m not sure if that was what you meant when you said x and z neighbor
Then I tried different ways of calculating the NORMAL, but I must admit I’m shooting in the dark here :
A)
NORMAL=normalize(cross((VERTEXvx),(VERTEXvz)));
B)
NORMAL=normalize(cross((VERTEXvec3(0,vx.y,0)),(VERTEXvec3(0,vz.y,0))));
It runs, but it’s giving me the wrong results. I’m sure there is something simple I’m not getting.
EDIT :##
I’ve been at it the whole night after work and I can’t seem to come close to what the derivatives do. I would eally appreciate some help.
Here’s the shader code, it’s applied to a PlaneMesh subdivided 10x10y of size 10x10
I pretty muched tried to interchange everything with everything :
vX<–>vY<–>vZ<–>(VERTEXvX)[…] with division by pt_size or not etc…
shader_type spatial;
uniform int GL_OES_standard_derivatives;
const float v_step = 10.0/1.0;
uniform vec4 out_color : hint_color =vec4(0.0,0.2,1.0,1.0);
uniform float distortion_amount : hint_range(0.2,1.5)=1.5;
uniform float distorsion_speed : hint_range(0.2,5)=1.0;
uniform float distorsion_seed : hint_range(0,1000)=1.0;
float generate_offset(float x, float z, float val1, float val2, float time){
float speed=distorsion_speed,amount=distortion_amount;
float radiansX=((mod(x + z*x*val1,amount)/amount)+(time*speed)*mod(x*0.8+z,1.5))*2.0*3.14;
float radiansZ=((mod(val2*(x*z+x*z),amount)/amount)+ (time*speed)*2.0*mod(x,2.0))*2.0*3.14;
return amount*0.5 *(sin(radiansZ)+cos(radiansX));
}
vec3 applyDistortion(vec3 vertex, float amount){
float xd = 0.0;//generate_offset(vertex.x,vertex.z,0.2,0.1,amount);
float yd = generate_offset(vertex.x,vertex.z,0.1,0.3,amount);
float zd = 0.0;//generate_offset(vertex.x,vertex.z,0.15,0.2,amount);
return vertex + vec3(xd,yd,zd);
}
varying vec3 preV;
varying vec3 vx;
varying vec3 vy;
varying vec3 vz;
varying float t;
varying vec3 normall;
varying float pt_size;
void vertex(){
//prevVertex = VERTEX;
t=TIME;
pt_size=POINT_SIZE;
preV=VERTEX;
VERTEX= applyDistortion(VERTEX,t*0.1);
vx= applyDistortion(VERTEX+vec3(POINT_SIZE,0,0),t*0.1);
vy= applyDistortion(VERTEX+vec3(0,POINT_SIZE,0),t*0.1);
vz= applyDistortion(VERTEX+vec3(0,0,POINT_SIZE),t*0.1);
}
void fragment(){
//NORMAL=normalize(cross(dFdx(VERTEX),dFdy(VERTEX)));
vec3 vX= applyDistortion(VERTEXvec3(pt_size,0,0),t*0.1);
vec3 vY= applyDistortion(VERTEXvec3(0,pt_size,0),t*0.1);
vec3 vZ= applyDistortion(VERTEXvec3(0,0,pt_size),t*0.1);
NORMAL=normalize(cross((VERTEXvX)/pt_size,(VERTEXvY)/pt_size));
METALLIC =0.0;
SPECULAR=0.0;
ROUGHNESS=0.2;
ALBEDO= out_color.xyz;
}
julliansana  20200225 03:12
I gave it a go myself to recall what it takes in details. I briefly looked at your shader but I wasn’t sure if your displacement function was actually derivable (i.e I don’t know if it’s actually as continuous as it looks, since deriving it means taking close enough samples… but how close?).
I also found the doc links to this video, which explains it: https://youtu.be/vm9Sdvhq6ho?t=265
On my own with a unitsized plane subdivided 10 times, I had this more or less working (not optimized, just fiddling result):
shader_type spatial;
uniform vec4 out_color : hint_color =vec4(0.0,0.2,1.0,1.0);
varying flat vec3 v_normal;
float get_wave(vec2 pos, float time, vec2 dir, float period, float amplitude) {
return amplitude * sin((pos.x * dir.x + pos.y * dir.y + time) / period);
}
float get_height(vec2 pos, float time) {
time *= 0.3;
return get_wave(pos, time, vec2(0.5, 0.5), 0.3, 0.1)
+ get_wave(pos, time, vec2(0.6, 0.4), 0.12, 0.1)
+ get_wave(pos, time, vec2(0.7, 0.2), 0.5, 0.06)
+ get_wave(pos, time, vec2(0.9, 0.1), 0.3, 0.03);
}
void vertex() {
float side_step = 0.01;
float h = get_height(VERTEX.xz, TIME);
float h_right = get_height(VERTEX.xz + vec2(side_step, 0.0), TIME);
float h_up = get_height(VERTEX.xz + vec2(0.0, side_step), TIME);
float dx = (h_right  h) / side_step;
float dz = (h_up  h) / side_step;
vec3 pos_right = vec3(1, dx, 0);
vec3 pos_up = vec3(0, dz, 1);
v_normal = cross(normalize(pos_right), normalize(pos_up));
NORMAL = v_normal;
VERTEX.y = h;
}
void fragment(){
NORMAL = (INV_CAMERA_MATRIX * (vec4(v_normal, 0.0))).xyz;
}
It doesn’t look “triangulish” though, I’m not sure why.
Zylann  20200225 19:41
Hey, thanks a lot,
In short :
That looks great to me.
I can’t make it work in GLSL2 though, and the game crashes on Android if I select GLSL3.
GLSL2 doesn’t crash, but it’s not flat shaded, it’s more continuous and it looks off.
Do you have any clue why ? What happens if you run this shader on GLSL2 ?
(Below is just more details about my previous mistakes)
I adapted it to my code and it didn’t work with the original function, probably because :
 mod() breaks continuity and the function
 the apply_distorsion() was changing the vertex X,Y, and Z at the same time
 the function actually not mapping, but incrementing/decrementing the vertex position “y+=f(x,z)”
But changed the distorsion to your function and it worked … until I changed to GLES2, and then it lost the flat shading.
The flat specifier in fromt of v_normal is not changing anything wheter it’s tehre r not.
There’s a lot that I was missing.
I would have never thought to put the 1s in here
vec3 pos_right = vec3(1, dx, 0);
The flat is also completely new to me, but I looked it u, it seems obvious now
varying flat vec3 v_normal;
I tried without INV_CAMERA_MATRIX to see the difference but I couldn’t see any.
NORMAL = (INV_CAMERA_MATRIX * (vec4(v_normal, 0.0))).xyz;
Thanks for your help again.
julliansana  20200226 13:51
When I try my shader in GLES2 it doesn’t crash, however the flat
keyword had zero effect. I have no idea if that’s not supported in this renderer, or if it’s a Godot bug. Looks more likely to be not supported in GLES2.
So let’s change strategy.
Don’t use PlaneMesh
. It looks smooth in GLES2 because vertices are shared, the geometry needs to be made such that each triangle is independent. Maybe you can make it in Blender? Or you could generate it from a script.
I have no idea why it crashes though. Does it crash without the flat
?
I used INV_CAMERA_MATRIX
to transform the normal because otherwise the shading was changing depending on the angle I was looking at the plane. Also I’m assigning it in the fragment shader because if I don’t, the flat
keyword would have no effect to make faces look flat. But since GLES2 doesnt supports that, you won’t even need to write a fragment part anyways.
Zylann  20200226 18:55
Yeah, I think generating is the way forward.
It’s probably going to be easier to manipulate the vertices, as I won’t be limited by shader loop logic…
I actually tried to import it from an animated blender model at first, but I have lighting problems when importing flat shaded models even with the better collada exporter.
I had partial success with .obj until I scaled it. I should crete another post for that.
 “I have no idea why it crashes though. Does it crash without the flat?”
It only crashes on android if I select GLES3, GLES2 runs fine on android (and HTML), the flat look is just not there.
julliansana  20200228 04:39