diff options
Diffstat (limited to 'Shaders/avatar_clone/avatar_clone_lighting.cginc')
| -rw-r--r-- | Shaders/avatar_clone/avatar_clone_lighting.cginc | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/Shaders/avatar_clone/avatar_clone_lighting.cginc b/Shaders/avatar_clone/avatar_clone_lighting.cginc new file mode 100644 index 0000000..7471157 --- /dev/null +++ b/Shaders/avatar_clone/avatar_clone_lighting.cginc @@ -0,0 +1,309 @@ +#ifndef AVATAR_CLONE_LIGHTING +#define AVATAR_CLONE_LIGHTING + +#include "AutoLight.cginc" +#include "iq_sdf.cginc" +#include "math.cginc" +#include "motion.cginc" +#include "pbr.cginc" +#include "poi.cginc" +#include "shadertoy.cginc" + +sampler2D _BaseColor; +sampler2D _Emission; +float _Emission_Strength; +sampler2D _Normal; +sampler2D _Metallic; +sampler2D _Roughness; + +bool _Disable_Normal_Texture; +bool _Disable_Normal_Recalc; + +sampler2D _Height; +float _Height_LOD; +float _Height_Exponent; +float _Height_Scale; +float _Height_Speed_X; +float _Height_Speed_Y; +float _Height_AA_Sample_Scale; + +sampler2D _Height_Mask; +float _Height_Mask_Exponent; + +float _Center_Out_Speed; +float _Center_Out_Sharpness; +float _Center_Out_Min_Radius; +float _Center_Out_Max_Radius; + +float _Num_Clones; +float _Clone_dx; +float _Clone_dy; +float _Clone_dz; + +struct appdata +{ + float4 position : POSITION; + float2 uv : TEXCOORD0; + float3 normal : NORMAL; +}; + +void getVertexLightColor(inout v2f i) +{ + #if defined(VERTEXLIGHT_ON) + float3 light_pos = float3(unity_4LightPosX0.x, unity_4LightPosY0.x, + unity_4LightPosZ0.x); + float3 light_float = light_pos - i.worldPos; + float3 light_dir = normalize(light_float); + float ndotl = DotClamped(i.normal, light_dir); + // Light fills an expanding sphere with surface area 4 * pi * r^2. + // By conservation of energy, this means that at distance r, light intensity + // is proportional to 1/(r^2). + float attenuation = 1 / (1 + dot(light_float, light_float) * unity_4LightAtten0.x); + i.vertexLightColor = unity_LightColor[0].rgb * ndotl * attenuation; + + i.vertexLightColor = Shade4PointLights( + unity_4LightPosX0, unity_4LightPosY0, unity_4LightPosZ0, + unity_LightColor[0].rgb, + unity_LightColor[1].rgb, + unity_LightColor[2].rgb, + unity_LightColor[3].rgb, + unity_4LightAtten0, i.worldPos, i.normal + ); + #endif +} + +v2f vert(appdata v) +{ + v2f o; + + o.objPos = v.position; + o.clipPos = UnityObjectToClipPos(v.position); + o.worldPos = mul(unity_ObjectToWorld, v.position); + + o.normal = UnityObjectToWorldNormal(v.normal); + o.uv = v.uv; + + getVertexLightColor(o); + + return o; +} + +float getDisplacement(float2 uv) +{ + // Manipulate vertex in world space. + float height = 0; + + 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); + + const float duv = _Height_AA_Sample_Scale; + + float z0 = tex2Dlod(_Height, float4(traveling_uv.x, traveling_uv.y, _Height_LOD, 0)); + // Trivial optimization. No need to keep going if no displacement is desired. + if (z0 == 0) { + return 0; + } + #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 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 HEIGHT_AA_LEVEL == 0 + height += z0; + #elif HEIGHT_AA_LEVEL == 1 + height += (z0 + z1 + z2 + z3 + z4) / 5.0; + #elif HEIGHT_AA_LEVEL == 2 + height += (z0 + z1 + z2 + z3 + z4 + z5 + z6 + z7 + z8) / 9.0; + #endif + + height = pow(height, _Height_Exponent); + height *= _Height_Scale; + + { + 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 = uv * 2.0 - 1.0; + + float center_dist2 = length2(middle_out_uv); + float ring_radius = fmod(_Time[1] * _Center_Out_Speed, + _Center_Out_Max_Radius - _Center_Out_Min_Radius) + + _Center_Out_Min_Radius; + + // How far am I from the desired ring? + float ring_dist = dabs(center_dist2 - ring_radius, _Center_Out_Sharpness); + float ring_scale = exp(-1.0 * ring_dist); + + float middle_out_height = ring_scale; + 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(15)] +void geom(triangle v2f tri_in[3], + uint pid: SV_PrimitiveID, + inout TriangleStream<v2f> tri_out) +{ + float dx = 0.5; + + 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 (uint 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]; + + if (!_Disable_Normal_Recalc) { + 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; + } + } + } + + tri_out.Append(t0); + tri_out.Append(t1); + tri_out.Append(t2); + tri_out.RestartStrip(); + + const int num_clones = max((int) floor(_Num_Clones), 0); + for (int i = 2; i < num_clones + 2; i++) { + v2f t0p = t0; + v2f t1p = t1; + v2f t2p = t2; + + t0p.worldPos.x += _Clone_dx * (i / 2) * (i % 2 == 0 ? 1.0 : -1.0); + t0p.worldPos.y += _Clone_dy * (i / 2); + t0p.worldPos.z += _Clone_dz * (i / 2); + + t1p.worldPos.x += _Clone_dx * (i / 2) * (i % 2 == 0 ? 1.0 : -1.0); + t1p.worldPos.y += _Clone_dy * (i / 2); + t1p.worldPos.z += _Clone_dz * (i / 2); + + t2p.worldPos.x += _Clone_dx * (i / 2) * (i % 2 == 0 ? 1.0 : -1.0); + t2p.worldPos.y += _Clone_dy * (i / 2); + t2p.worldPos.z += _Clone_dz * (i / 2); + + t0p.objPos = mul(unity_WorldToObject, float4(t0p.worldPos, 1.0)); + t0p.clipPos = UnityObjectToClipPos(t0p.objPos); + + t1p.objPos = mul(unity_WorldToObject, float4(t1p.worldPos, 1.0)); + t1p.clipPos = UnityObjectToClipPos(t1p.objPos); + + t2p.objPos = mul(unity_WorldToObject, float4(t2p.worldPos, 1.0)); + t2p.clipPos = UnityObjectToClipPos(t2p.objPos); + + tri_out.Append(t0p); + tri_out.Append(t1p); + tri_out.Append(t2p); + tri_out.RestartStrip(); + } +} + +float getWorldSpaceDepth(in const float3 worldPos) +{ + float4 clip_pos = mul(UNITY_MATRIX_VP, float4(worldPos, 1.0)); + return clip_pos.z / clip_pos.w; +} + +float4 effect(inout v2f i, out float depth) +{ + depth = -1000.0; + + float4 albedo = tex2D(_BaseColor, i.uv); + float3 emission = tex2D(_Emission, i.uv); + float3 normal = _Disable_Normal_Texture ? i.normal : tex2D(_Normal, i.uv); + float metallic = tex2D(_Metallic, i.uv); + float roughness = tex2D(_Roughness, i.uv); + if (albedo.a > 0) { + depth = getWorldSpaceDepth(i.worldPos); + } + + float4 lit_color = getLitColor(i, albedo, i.worldPos, normal, metallic, + 1.0 - roughness, /*custom_cubemap=*/true); + + lit_color.rgb += emission * _Emission_Strength; + + return lit_color; +} + +fixed4 frag(v2f i, out float depth : SV_DepthLessEqual) : SV_Target +{ + return effect(i, depth); +} + +#endif // AVATAR_CLONE_LIGHTING + |
