summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2023-04-14 03:45:44 -0700
committeryum <yum.food.vr@gmail.com>2023-04-14 04:14:06 -0700
commit6a14a2dd1dd5208c7cb1ea04c49d759484121ce7 (patch)
tree69e9f9f0f102ebbbc8a1ec5c2998d9c6ef415e42
parent7fffb7c8ec8101020972bc811459d8d481bfae6e (diff)
Fix normal calculation in displacement shader
Recompute normals after generating the deformed mesh. Unfortunately, significant anti-aliasing is required to get the generated normals to look smooth in motion. * Enable backface culling.
-rw-r--r--Demos/displacement_demo.gifbin4717920 -> 4899631 bytes
-rw-r--r--Shaders/displacement/displacement.shader12
-rw-r--r--Shaders/displacement/displacement_lighting.cginc100
-rw-r--r--Shaders/displacement/pbr.cginc1
4 files changed, 86 insertions, 27 deletions
diff --git a/Demos/displacement_demo.gif b/Demos/displacement_demo.gif
index 90ba0d0..951b01f 100644
--- a/Demos/displacement_demo.gif
+++ b/Demos/displacement_demo.gif
Binary files differ
diff --git a/Shaders/displacement/displacement.shader b/Shaders/displacement/displacement.shader
index 6a47853..5c0b517 100644
--- a/Shaders/displacement/displacement.shader
+++ b/Shaders/displacement/displacement.shader
@@ -4,8 +4,8 @@ Shader "yum_food/displacement"
{
_BaseColor("Base color", 2D) = "white" {}
_Normal("Normal", 2D) = "bump" {}
- _Disable_Normal_Texture("Disable normal texture", float) = 0.0
- _Metallic("Metallic", 2D) = "black" {}
+ _Disable_Normal_Texture("Disable normal texture", float) = 1.0
+ _Metallic("Metallic", 2D) = "white" {}
_Roughness("Roughness", 2D) = "black" {}
_Cubemap("Cubemap", Cube) = "" {}
@@ -36,7 +36,7 @@ Shader "yum_food/displacement"
Blend SrcAlpha OneMinusSrcAlpha
ZWrite On
ZTest LEqual
- Cull Off
+ Cull Back
CGPROGRAM
#pragma target 5.0
@@ -53,7 +53,7 @@ Shader "yum_food/displacement"
// 0: no anti-aliasing
// 1: sample 4 neighbors (diagonals)
// 2: sample 8 neighbors (diagonals + cartesian)
- #define OFFSET_AA_LEVEL 2
+ #define HEIGHT_AA_LEVEL 2
#include "displacement_lighting.cginc"
ENDCG
@@ -67,7 +67,7 @@ Shader "yum_food/displacement"
Blend One One
ZWrite On
ZTest LEqual
- Cull Off
+ Cull Back
CGPROGRAM
#pragma target 5.0
@@ -78,7 +78,7 @@ Shader "yum_food/displacement"
#pragma geometry geom
#pragma fragment frag
- #define OFFSET_AA_LEVEL 2
+ #define HEIGHT_AA_LEVEL 2
#include "displacement_lighting.cginc"
ENDCG
diff --git a/Shaders/displacement/displacement_lighting.cginc b/Shaders/displacement/displacement_lighting.cginc
index d0abdb9..3a5e04b 100644
--- a/Shaders/displacement/displacement_lighting.cginc
+++ b/Shaders/displacement/displacement_lighting.cginc
@@ -80,12 +80,12 @@ v2f vert(appdata v)
return o;
}
-void displace(inout v2f vert)
+float getDisplacement(float2 uv)
{
// Manipulate vertex in world space.
float height = 0;
- float2 traveling_uv = vert.uv;
+ float2 traveling_uv = uv;
traveling_uv.x += _Time[0] * _Height_Speed_X;
traveling_uv.y += _Time[0] * _Height_Speed_Y;
traveling_uv = glsl_mod(traveling_uv, 1.0);
@@ -93,24 +93,24 @@ void displace(inout v2f vert)
const float duv = _Height_AA_Sample_Scale;
float z0 = tex2Dlod(_Height, float4(traveling_uv.x, traveling_uv.y, _Height_LOD, 0));
- #if OFFSET_AA_LEVEL >= 1
+ #if HEIGHT_AA_LEVEL >= 1
float z1 = tex2Dlod(_Height, float4(traveling_uv.x + duv, traveling_uv.y + duv, _Height_LOD, 0));
float z2 = tex2Dlod(_Height, float4(traveling_uv.x + duv, traveling_uv.y - duv, _Height_LOD, 0));
float z3 = tex2Dlod(_Height, float4(traveling_uv.x - duv, traveling_uv.y - duv, _Height_LOD, 0));
float z4 = tex2Dlod(_Height, float4(traveling_uv.x - duv, traveling_uv.y + duv, _Height_LOD, 0));
#endif
- #if OFFSET_AA_LEVEL >= 2
+ #if HEIGHT_AA_LEVEL >= 2
float z5 = tex2Dlod(_Height, float4(traveling_uv.x + duv, traveling_uv.y, _Height_LOD, 0));
float z6 = tex2Dlod(_Height, float4(traveling_uv.x - duv, traveling_uv.y, _Height_LOD, 0));
float z7 = tex2Dlod(_Height, float4(traveling_uv.x, traveling_uv.y + duv, _Height_LOD, 0));
float z8 = tex2Dlod(_Height, float4(traveling_uv.x, traveling_uv.y - duv, _Height_LOD, 0));
#endif
- #if OFFSET_AA_LEVEL == 0
+ #if HEIGHT_AA_LEVEL == 0
height += z0;
- #elif OFFSET_AA_LEVEL == 1
+ #elif HEIGHT_AA_LEVEL == 1
height += (z0 + z1 + z2 + z3 + z4) / 5.0;
- #elif OFFSET_AA_LEVEL == 2
+ #elif HEIGHT_AA_LEVEL == 2
height += (z0 + z1 + z2 + z3 + z4 + z5 + z6 + z7 + z8) / 9.0;
#endif
@@ -118,14 +118,14 @@ void displace(inout v2f vert)
height *= _Height_Scale;
{
- float mask = tex2Dlod(_Height_Mask, float4(vert.uv, _Height_LOD, 0));
+ float mask = tex2Dlod(_Height_Mask, float4(uv, _Height_LOD, 0));
mask = pow(mask, _Height_Mask_Exponent);
height *= mask;
}
// 0 at middle, 1 or -1 at edges
if (_Center_Out_Speed > 0.0) {
- float2 middle_out_uv = vert.uv * 2.0 - 1.0;
+ float2 middle_out_uv = uv * 2.0 - 1.0;
float center_dist2 = length2(middle_out_uv);
float ring_radius = fmod(_Time[1] * _Center_Out_Speed,
@@ -140,11 +140,46 @@ void displace(inout v2f vert)
height *= middle_out_height;
}
+ return height;
+}
+
+void displace(inout v2f vert)
+{
+ float height = getDisplacement(vert.uv);
+
vert.worldPos += height * vert.normal;
vert.objPos = mul(unity_WorldToObject, float4(vert.worldPos, 1.0));
vert.clipPos = UnityObjectToClipPos(vert.objPos);
}
+float3 getNormal(
+ v2f v0,
+ v2f v1,
+ v2f v2,
+ float duv_scale) {
+ float2 duv_v0v1 = v1.uv - v0.uv;
+ float2 duv_v0v2 = v2.uv - v0.uv;
+
+ float h0 = getDisplacement(v0.uv);
+ float h1 = getDisplacement(v0.uv + duv_v0v1 * duv_scale);
+ float h2 = getDisplacement(v0.uv + duv_v0v2 * duv_scale);
+
+ float dh_v0v1 = h1 - h0;
+ float dh_v0v2 = h2 - h0;
+
+ float3 dpos_v0v1 = v1.worldPos - v0.worldPos;
+ float3 dpos_v0v2 = v2.worldPos - v0.worldPos;
+
+ float3 p0 = v0.worldPos + h0 * v0.normal;
+ float3 p1 = v0.worldPos + dpos_v0v1 * duv_scale + lerp(h0, h1, duv_scale) * v1.normal;
+ float3 p2 = v0.worldPos + dpos_v0v2 * duv_scale + lerp(h0, h2, duv_scale) * v2.normal;
+
+ float3 tangent = normalize(p1 - p0);
+ float3 bitangent = normalize(p2 - p0);
+ float3 new_normal = normalize(cross(tangent, bitangent));
+ return new_normal;
+}
+
// maxvertexcount == the number of vertices we create
[maxvertexcount(3)]
void geom(triangle v2f tri_in[3],
@@ -153,17 +188,41 @@ void geom(triangle v2f tri_in[3],
{
float dx = 0.5;
- v2f cur = tri_in[0];
- displace(cur);
- tri_out.Append(cur);
-
- cur = tri_in[1];
- displace(cur);
- tri_out.Append(cur);
+ v2f t0 = tri_in[0];
+ v2f t1 = tri_in[1];
+ v2f t2 = tri_in[2];
+
+ displace(t0);
+ displace(t1);
+ displace(t2);
+
+ // Math from here:
+ // http://tonfilm.blogspot.com/2007/01/calculate-normals-in-shader.html
+ for (int i = 0; i < 3; i++) {
+ v2f v0 = tri_in[(i + 0) % 3];
+ v2f v1 = tri_in[(i + 1) % 3];
+ v2f v2 = tri_in[(i + 2) % 3];
+
+ float3 aa_normal = 0;
+ aa_normal += getNormal(v0, v1, v2, 0.3);
+ aa_normal += getNormal(v0, v1, v2, 0.4);
+ aa_normal += getNormal(v0, v1, v2, 0.5);
+ aa_normal += getNormal(v0, v1, v2, 0.6);
+ aa_normal += getNormal(v0, v1, v2, 0.7);
+ aa_normal = normalize(aa_normal);
+
+ if (i == 0) {
+ t0.normal = aa_normal;
+ } else if (i == 1) {
+ t1.normal = aa_normal;
+ } else if (i == 2) {
+ t2.normal = aa_normal;
+ }
+ }
- cur = tri_in[2];
- displace(cur);
- tri_out.Append(cur);
+ tri_out.Append(t0);
+ tri_out.Append(t1);
+ tri_out.Append(t2);
tri_out.RestartStrip();
}
@@ -185,10 +244,9 @@ float4 effect(inout v2f i, out float depth)
if (albedo.a > 0) {
depth = getWorldSpaceDepth(i.worldPos);
}
+
return getLitColor(i, albedo, i.worldPos, normal, metallic, 1.0 - roughness,
/*custom_cubemap=*/true);
-
- return 1;
}
fixed4 frag(v2f i, out float depth : SV_DepthLessEqual) : SV_Target
diff --git a/Shaders/displacement/pbr.cginc b/Shaders/displacement/pbr.cginc
index e552bcc..690f547 100644
--- a/Shaders/displacement/pbr.cginc
+++ b/Shaders/displacement/pbr.cginc
@@ -12,6 +12,7 @@ struct v2f
float2 uv : TEXCOORD0;
float3 normal : TEXCOORD1;
float3 worldPos : TEXCOORD2;
+
float3 objPos : TEXCOORD3;
#if defined(VERTEXLIGHT_ON)