Skip to content

Instantly share code, notes, and snippets.

@dzil123
Last active October 27, 2022 17:10
Show Gist options
  • Save dzil123/27b1a7a3fa6ab1f38b1b8bfd4b412b11 to your computer and use it in GitHub Desktop.
Save dzil123/27b1a7a3fa6ab1f38b1b8bfd4b412b11 to your computer and use it in GitHub Desktop.
Planet ocean effect depth fix
diff --git a/shader.glsl b/shader.glsl
index ec7854a..3825944 100644
--- a/shader.glsl
+++ b/shader.glsl
@@ -140,31 +140,34 @@ void fragment() {
depth = exp(-depth);*/
// Normalized Device Coordinates needs to be -1 to 1 in Godot
- vec3 ndc = vec3(SCREEN_UV, depth) * 2.0 - 1.0;
+ vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);
// Convert between NDC and view space to get distance to camera
vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
view.xyz /= view.w;
- float linear_depth = view.z;
+ float linear_depth = -view.z;
float scaled_depth = (ZFar * ZNear) / (ZFar + (linear_depth * (ZNear - ZFar)));
// Distance from fragment point to camera?
float viewLength = length(viewVector);
-
+ linear_depth *= viewLength;
vec3 rayPos = CAMERA_POSITION_WORLD;
vec3 rayDir = viewVector / viewLength;
//vec2 hit = raySphere(rayPos, rayDir, OceanCentre, OceanRadius);
vec2 hit = raySphere(rayPos, rayDir, OceanRadius);
float dstToOcean = hit.x;
- float dstThroughOcean = dstToOcean + OceanRadius/2.0;
+ float dstThroughOcean = hit.y - hit.x;
+ if (hit.y <= 0.0) {
+ dstThroughOcean = -1.0;
+ }
//float dstToOcean = sphereIntersect(rayPos, rayDir, OceanCentre, OceanRadius);
vec3 rayOceanIntersectPos = rayPos + rayDir * dstToOcean - OceanCentre;
// dst that view ray travels through ocean (before hitting terrain / exiting ocean)
//float oceanViewDepth = sceneDepth + dstToOcean;
- float oceanViewDepth = min(dstThroughOcean, scaled_depth + dstToOcean);
+ float oceanViewDepth = min(dstThroughOcean, linear_depth - dstToOcean);
vec4 finalCol = originalCol;
float alpha = 1.0;
shader_type spatial;
render_mode unshaded, depth_draw_never, depth_prepass_alpha;
uniform float ZNear = 0.05;
uniform float ZFar = 4000.0;
uniform vec4 ColA : source_color;
uniform vec4 ColB : source_color;
uniform vec4 SpecularCol : source_color;
uniform float DepthMultiplier = 0.5;
uniform float AlphaMultiplier = 3;
uniform float Smoothness = 0.92;
uniform sampler2D WaveNormalA;
uniform sampler2D WaveNormalB;
uniform float WaveStrength = 0.15;
uniform float WaveNormalScale = 15.0;
uniform float WaveSpeed = 0.5;
uniform float PlanetScale = 200.0;
uniform vec3 OceanCentre = vec3(0.0);
uniform float OceanRadius = 190.0;
uniform vec3 DirToSun = vec3(0.0, 1.0, 0.0);
varying vec2 uv;
varying vec3 viewVector;
vec2 raySphere(vec3 o, vec3 d, float r) {
float a = dot(d,d);
float b = 2.0 * dot(o,d);
float c = dot(o,o) - r * r;
float q = b * b - 4.0 * a * c;
if (q < 0.0){
return vec2(-1.0, -1.0);
}
float sq = sqrt(q);
float t1 = (-b - sq) / (2.0*a);
float t2 = (-b + sq) / (2.0*a);
if (t1 > t2){
float a = t2;
t2 = t1;
t1 = a;
}
return vec2(t1,t2);
}
float saturate(float value) {
return min(max(value, 0.0), 1.0);
}
vec3 saturate3(vec3 value) {
return min(max(value, 0.0), 1.0);
}
vec3 unpackNormal(vec4 packednormal)
{
vec3 normal;
normal.xy = packednormal.wy * 2.0 - 1.0;
normal.z = sqrt(1.0 - normal.x * normal.x - normal.y * normal.y);
return normal;
}
// Reoriented Normal Mapping
// http://blog.selfshadow.com/publications/blending-in-detail/
// Altered to take normals (-1 to 1 ranges) rather than unsigned normal maps (0 to 1 ranges)
vec3 blend_rnm(vec3 n1, vec3 n2)
{
n1.z += 1.0;
n2.xy = -n2.xy;
return n1 * dot(n1, n2) / n1.z - n2;
}
// Sample normal map with triplanar coordinates
// Returned normal will be in obj/world space (depending whether pos/normal are given in obj or world space)
// Based on: medium.com/@bgolus/normal-mapping-for-a-triplanar-shader-10bf39dca05a
vec3 triplanarNormal(vec3 vertPos, vec3 normal, float scale, vec2 offset, sampler2D normalMap) {
vec3 absNormal = abs(normal);
// Calculate triplanar blend
vec3 blendWeight = saturate3(pow(normal, 4.0 * vec3(1.0, 1.0, 1.0)));
// Divide blend weight by the sum of its components. This will make x + y + z = 1
blendWeight /= dot(blendWeight, vec3(1.0, 1.0, 1.0));
// Calculate triplanar coordinates
vec2 uvX = vertPos.zy * scale + offset;
vec2 uvY = vertPos.xz * scale + offset;
vec2 uvZ = vertPos.xy * scale + offset;
// Sample tangent space normal maps
// unpackNormal puts values in range [-1, 1] (and accounts for DXT5nm compression)
vec3 tangentNormalX = unpackNormal(texture(normalMap, uvX));
vec3 tangentNormalY = unpackNormal(texture(normalMap, uvY));
vec3 tangentNormalZ = unpackNormal(texture(normalMap, uvZ));
// Swizzle normals to match tangent space and apply reoriented normal mapping blend
tangentNormalX = blend_rnm(vec3(normal.zy, absNormal.x), tangentNormalX);
tangentNormalY = blend_rnm(vec3(normal.xz, absNormal.y), tangentNormalY);
tangentNormalZ = blend_rnm(vec3(normal.xy, absNormal.z), tangentNormalZ);
// Apply input normal sign to tangent space Z
vec3 axisSign = sign(normal);
tangentNormalX.z *= axisSign.x;
tangentNormalY.z *= axisSign.y;
tangentNormalZ.z *= axisSign.z;
// Swizzle tangent normals to match input normal and blend together
vec3 outputNormal = normalize(
tangentNormalX.zyx * blendWeight.x +
tangentNormalY.xzy * blendWeight.y +
tangentNormalZ.xyz * blendWeight.z
);
return outputNormal;
}
const vec2 vertices[3] = {vec2(-1,-1), vec2(3,-1), vec2(-1, 3)};
void vertex() {
// Generate triangle in clip space
POSITION = vec4(vertices[VERTEX_ID],0.0,1.0);
uv = 0.5 * POSITION.xy + vec2(0.5, 0.5);
UV = uv;
// View vector in world space
viewVector = (INV_PROJECTION_MATRIX * vec4(uv * 2.0 - 1.0, 0.0, 1.0)).xyz;
viewVector = (INV_VIEW_MATRIX * vec4(viewVector, 0.0)).xyz;
}
void fragment() {
vec4 originalCol = texture(SCREEN_TEXTURE, SCREEN_UV);
// Get depth value from DEPTH_TEXTURE
float depth = texture(DEPTH_TEXTURE, SCREEN_UV).r;
/*depth = depth * 2.0 - 1.0;
depth = PROJECTION_MATRIX[3][2] / (depth + PROJECTION_MATRIX[2][2]);
depth = depth + VERTEX.z;
depth = exp(-depth);*/
// Normalized Device Coordinates needs to be -1 to 1 in Godot
vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);
// Convert between NDC and view space to get distance to camera
vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
view.xyz /= view.w;
float linear_depth = -view.z;
float scaled_depth = (ZFar * ZNear) / (ZFar + (linear_depth * (ZNear - ZFar)));
// Distance from fragment point to camera?
float viewLength = length(viewVector);
linear_depth *= viewLength;
vec3 rayPos = CAMERA_POSITION_WORLD;
vec3 rayDir = viewVector / viewLength;
//vec2 hit = raySphere(rayPos, rayDir, OceanCentre, OceanRadius);
vec2 hit = raySphere(rayPos, rayDir, OceanRadius);
float dstToOcean = hit.x;
float dstThroughOcean = hit.y - hit.x;
if (hit.y <= 0.0) {
dstThroughOcean = -1.0;
}
//float dstToOcean = sphereIntersect(rayPos, rayDir, OceanCentre, OceanRadius);
vec3 rayOceanIntersectPos = rayPos + rayDir * dstToOcean - OceanCentre;
// dst that view ray travels through ocean (before hitting terrain / exiting ocean)
//float oceanViewDepth = sceneDepth + dstToOcean;
float oceanViewDepth = min(dstThroughOcean, linear_depth - dstToOcean);
vec4 finalCol = originalCol;
float alpha = 1.0;
if (oceanViewDepth > 0.0) {
vec3 clipPlanePos = rayPos + viewVector * ZNear;
float dstAboveWater = length(clipPlanePos - OceanCentre) - OceanRadius;
float t = 1.0 - exp(-oceanViewDepth / PlanetScale * DepthMultiplier);
alpha = 1.0 - exp(-oceanViewDepth / PlanetScale * AlphaMultiplier);
vec4 oceanCol = mix(ColA, ColB, t);
vec3 oceanSphereNormal = normalize(rayOceanIntersectPos);
finalCol = oceanCol;
}
//ALBEDO = vec3(normalize(hit), 0.0);
//ALBEDO = normalize(rayOceanIntersectPos) * 0.5 + 0.5;
//ALBEDO = vec3(dstThroughOcean, dstToOcean, 0.0);
ALBEDO = finalCol.rgb;
ALPHA = alpha;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment