From 8a9c2fe3d6383eb202ce1f6b2a0fe498f60bb345 Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Tue, 26 Apr 2022 19:25:05 +0800 Subject: [PATCH 01/13] Various features added 1. A "DepthNormals" Pass (For forward renderer) 2. Adding specular scattering from "maajor"'s https://github.com/maajor/Marschner-Hair-Unity, licensed under MIT. 3. Controlling the length of fur using a texture (R channel). 4. Fixed issues when using Depth Priming on URP 12. (Depth Priming avoids rendering pixels that are occluded [probably] which improves performance) --- Assets/Fur/Shaders/Shell/Depth.hlsl | 17 +- Assets/Fur/Shaders/Shell/DepthNormals.hlsl | 95 ++++++++++ .../Fur/Shaders/Shell/DepthNormals.hlsl.meta | 7 + Assets/Fur/Shaders/Shell/FurSpecular.hlsl | 177 ++++++++++++++++++ .../Fur/Shaders/Shell/FurSpecular.hlsl.meta | 7 + Assets/Fur/Shaders/Shell/Lit.hlsl | 41 +++- Assets/Fur/Shaders/Shell/Lit.shader | 57 +++++- Assets/Fur/Shaders/Shell/Param.hlsl | 9 + Assets/Fur/Shaders/Shell/Shadow.hlsl | 5 +- 9 files changed, 396 insertions(+), 19 deletions(-) create mode 100644 Assets/Fur/Shaders/Shell/DepthNormals.hlsl create mode 100644 Assets/Fur/Shaders/Shell/DepthNormals.hlsl.meta create mode 100644 Assets/Fur/Shaders/Shell/FurSpecular.hlsl create mode 100644 Assets/Fur/Shaders/Shell/FurSpecular.hlsl.meta diff --git a/Assets/Fur/Shaders/Shell/Depth.hlsl b/Assets/Fur/Shaders/Shell/Depth.hlsl index d1d1118..750b4d9 100644 --- a/Assets/Fur/Shaders/Shell/Depth.hlsl +++ b/Assets/Fur/Shaders/Shell/Depth.hlsl @@ -39,7 +39,8 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 move = moveFactor * _BaseMove.xyz; float3 shellDir = normalize(normalInput.normalWS + move + windMove); - float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index); + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy * _FurScale, 0).x; + float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); float4 posCS = TransformWorldToHClip(posWS); output.vertex = posCS; @@ -63,16 +64,16 @@ void geom(triangle Attributes input[3], inout TriangleStream stream) } } -void frag( - Varyings input, - out float4 outColor : SV_Target, - out float outDepth : SV_Depth) +// Previous frag() causes Depth Priming error (black pixels), +// when enabling "Depth Priming + MSAA" in URP 12.1. +float frag(Varyings input) : SV_TARGET { - float4 furColor = SAMPLE_TEXTURE2D(_FurMap, sampler_FurMap, input.uv * _FurScale); + float4 furColor = SAMPLE_TEXTURE2D(_FurMap, sampler_FurMap, input.uv / _BaseMap_ST.xy * _FurScale); float alpha = furColor.r * (1.0 - input.layer); if (input.layer > 0.0 && alpha < _AlphaCutout) discard; - outColor = outDepth = input.vertex.z / input.vertex.w; + // Divided by w of PositionCS gets wrong depth when enabling depth priming (Depth Prepass) on URP 12.1. + return input.vertex.z; + //outColor = outDepth = input.vertex.z / input.vertex.w; } - #endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/DepthNormals.hlsl b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl new file mode 100644 index 0000000..c372928 --- /dev/null +++ b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl @@ -0,0 +1,95 @@ +#ifndef FUR_SHELL_DEPTH_NORMALS_HLSL +#define FUR_SHELL_DEPTH_NORMALS_HLSL + +#include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" +#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl" +#include "./Param.hlsl" + +struct Attributes +{ + half4 positionOS : POSITION; + half3 normalOS : NORMAL; + half4 tangentOS : TANGENT; + float2 uv : TEXCOORD0; +}; + +struct Varyings +{ + float4 vertex : SV_POSITION; + float2 uv : TEXCOORD0; + //float fogCoord : TEXCOORD1; + float layer : TEXCOORD1; + float3 normalWS : TEXCOORD2; + float3 tangentWS : TEXCOORD3; + float3 posWS : TEXCOORD4; +}; + +Attributes vert(Attributes input) +{ + return input; +} + +void AppendShellVertex(inout TriangleStream stream, Attributes input, int index) +{ + Varyings output = (Varyings)0; + + VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); + VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); + + float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); + float3 posOS = input.positionOS.xyz; + float3 windAngle = _Time.w * _WindFreq.xyz; + float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); + float3 move = moveFactor * _BaseMove.xyz; + + float3 shellDir = SafeNormalize(normalInput.normalWS + move + windMove); + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy * _FurScale, 0).x; + float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); + float4 posCS = TransformWorldToHClip(posWS); + + output.vertex = posCS; + output.posWS = posWS; + output.uv = TRANSFORM_TEX(input.uv, _BaseMap); + output.layer = (float)index / _ShellAmount; + + output.normalWS = normalInput.normalWS; + output.tangentWS = normalInput.tangentWS; + + + stream.Append(output); +} + +[maxvertexcount(51)] +void geom(triangle Attributes input[3], inout TriangleStream stream) +{ + [loop] for (float i = 0; i < _ShellAmount; ++i) + { + [unroll] for (float j = 0; j < 3; ++j) + { + AppendShellVertex(stream, input[j], i); + } + stream.RestartStrip(); + } +} + +float4 frag(Varyings input) : SV_Target +{ + float4 furColor = SAMPLE_TEXTURE2D(_FurMap, sampler_FurMap, input.uv / _BaseMap_ST.xy * _FurScale); + float alpha = furColor.r * (1.0 - input.layer); + if (input.layer > 0.0 && alpha < _AlphaCutout) discard; + + float3 viewDirWS = SafeNormalize(GetCameraPositionWS() - input.posWS); + half3 normalTS = UnpackNormalScale( + SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, input.uv / _BaseMap_ST.xy * _FurScale), + _NormalScale); + float3 bitangent = SafeNormalize(viewDirWS.y * cross(input.normalWS, input.tangentWS)); + float3 normalWS = SafeNormalize(TransformTangentToWorld( + normalTS, + float3x3(input.tangentWS, bitangent, input.normalWS))); + + // Stores World Space Normal to "_CameraNormalsTexture", no depth needed currently. + return float4(NormalizeNormalPerPixel(normalWS), 0.0); + +} + +#endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/DepthNormals.hlsl.meta b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl.meta new file mode 100644 index 0000000..98b85b0 --- /dev/null +++ b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9cb306cee9064a94ab6fd8359189c7b4 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fur/Shaders/Shell/FurSpecular.hlsl b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl new file mode 100644 index 0000000..e96aebd --- /dev/null +++ b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl @@ -0,0 +1,177 @@ +#ifndef FUR_SPECULAR_HLSL +#define FUR_SPECULAR_HLSL + +//------------------------------------------------------------------------------------------------- +// Fur shading from "maajor"'s https://github.com/maajor/Marschner-Hair-Unity, licensed under MIT. +//------------------------------------------------------------------------------------------------- + +struct SurfaceOutputFur +// Upgrade NOTE: excluded shader from DX11, OpenGL ES 2.0 because it uses unsized arrays +//#pragma exclude_renderers d3d11 gles +{ + half3 Albedo; + half MedulaScatter; + half MedulaAbsorb; + half3 Normal;//Tangent actually + half3 VNormal;//vertext normal + half3 Emission; + half Alpha; + half Roughness; + half Specular; + half Layer; + half Kappa; +}; + +inline float square(float x) { + return x * x; +} + +float acosFast(float inX) +{ + float x = abs(inX); + float res = -0.156583f * x + (0.5 * PI); + res *= sqrt(1.0f - x); + return (inX >= 0) ? res : PI - res; +} + +#define SQRT2PI 2.50663 + +//Gaussian Distribution for M term +inline float Hair_G(float B, float Theta) +{ + return exp(-0.5 * square(Theta) / (B*B)) / (SQRT2PI * B); +} + + +inline float3 SpecularFresnel(float3 F0, float vDotH) { + return F0 + (1.0f - F0) * pow(1 - vDotH, 5); +} + +inline float3 SpecularFresnelLayer(float3 F0, float vDotH, float layer) { + float3 fresnel = SpecularFresnel(F0, vDotH); + return (fresnel * layer) / (1 + (layer-1) * fresnel); +} + +// Yan, Ling-Qi, etc, "An efficient and practical near and far field fur reflectance model." +float3 FurBSDFYan(SurfaceOutputFur s, float3 L, float3 V, float3 N, float Shadow, float Backlit, float Area) +{ + float3 S = 0; + + const float VoL = dot(V, L); + const float SinThetaL = dot(N, L); + const float SinThetaV = dot(N, V); + float cosThetaL = sqrt(max(0, 1 - SinThetaL * SinThetaL)); + float cosThetaV = sqrt(max(0, 1 - SinThetaV * SinThetaV)); + float CosThetaD = sqrt((1 + cosThetaL * cosThetaV + SinThetaV * SinThetaL) / 2.0); + + const float3 Lp = L - SinThetaL * N; + const float3 Vp = V - SinThetaV * N; + const float CosPhi = dot(Lp, Vp) * rsqrt(dot(Lp, Lp) * dot(Vp, Vp) + 1e-4); + const float CosHalfPhi = sqrt(saturate(0.5 + 0.5 * CosPhi)); + + float n_prime = 1.19 / CosThetaD + 0.36 * CosThetaD; + + float Shift = 0.0499f; + float Alpha[] = + { + -0.0998,//-Shift * 2, + 0.0499f,// Shift, + 0.1996 // Shift * 4 + }; + float B[] = + { + Area + square(s.Roughness), + Area + square(s.Roughness) / 2, + Area + square(s.Roughness) * 2 + }; + + //float F0 = square((1 - 1.55f) / (1 + 1.55f)); + float F0 = 0.04652;//eta=1.55f + + float3 Tp; + float Mp, Np, Fp, a, h, f; + float ThetaH = SinThetaL + SinThetaV; + // R + Mp = Hair_G(B[0], ThetaH - Alpha[0]); + Np = 0.25 * CosHalfPhi; + Fp = SpecularFresnelLayer(F0, sqrt(saturate(0.5 + 0.5 * VoL)), s.Layer).x; + S += (Mp * Np) * (Fp * lerp(1, Backlit, saturate(-VoL))); + + // TT + Mp = Hair_G(B[1], ThetaH - Alpha[1]); + a = rcp(n_prime); + h = CosHalfPhi * (1 + a * (0.6 - 0.8 * CosPhi)); + f = SpecularFresnelLayer(F0, CosThetaD * sqrt(saturate(1 - h * h)), s.Layer).x; + Fp = square(1 - f); + float sinGammaTSqr = square((h * a)); + float sm = sqrt(saturate(square(s.Kappa)-sinGammaTSqr)); + float sc = sqrt(1 - sinGammaTSqr) - sm; + Tp = pow(s.Albedo, 0.5 * sc / CosThetaD) * pow(s.MedulaAbsorb*s.MedulaScatter, 0.5 * sm / CosThetaD); + Np = exp(-3.65 * CosPhi - 3.98); + S += (Mp * Np) * (Fp * Tp) * Backlit; + + // TRT + Mp = Hair_G(B[2], ThetaH - Alpha[2]); + f = SpecularFresnelLayer(F0, CosThetaD * 0.5f, s.Layer).x; + Fp = square(1 - f) * f; + // assume h = sqrt(3)/2, calculate sm and sc + sm = sqrt(saturate(square(s.Kappa)-0.75f)); + sc = 0.5f - sm; + Tp = pow(s.Albedo, sc / CosThetaD) * pow(s.MedulaAbsorb*s.MedulaScatter, sm / CosThetaD); + Np = exp((6.3f*CosThetaD+0.7f)*CosPhi-(5*CosThetaD+2)); + + S += (Mp * Np) * (Fp * Tp); + + // TTs + // hacking approximate Cm + Mp = abs(cosThetaL)*0.5f; + // still assume h = sqrt(3)/2 + Tp = pow(s.Albedo, (sc+1-s.Kappa)/(4*CosThetaD)) * pow(s.MedulaAbsorb, s.Kappa / (4*CosThetaD)); + // hacking approximate pre-integrated Dtts based on Cn + Np = 0.05*(2*CosPhi*CosPhi - 1) + 0.16f;//0.05*std::cos(2*Phi) + 0.16f; + + S += (Mp * Np) * (f * Tp); + + //TRTs + float phi = acosFast(CosPhi); + // hacking approximate pre-integrated Dtrts based on Cn + Np = 0.05f * cos(1.5*phi+1.7) + 0.18f; + // still assume h = sqrt(3)/2 + Tp = pow(s.Albedo, (3*sc+1-s.Kappa)/(4*CosThetaD)) * pow(s.MedulaAbsorb, (2*sm+s.Kappa) / (4*CosThetaD)) * pow(s.MedulaScatter, sm/(8*CosThetaD)); + Fp = f * (1-f); + + S += (Mp * Np) * (Fp * Tp); + + return S; +} + +float3 FurDiffuseKajiya(SurfaceOutputFur s, float3 L, float3 V, float3 N, half Shadow, float Backlit, float Area) { + float3 S = 0; + float KajiyaDiffuse = 1 - abs(dot(N, L)); + + float3 FakeNormal = SafeNormalize(V - N * dot(V, N)); + N = FakeNormal; + + // Hack approximation for multiple scattering. + float Wrap = 1; + float NoL = saturate((dot(N, L) + Wrap) / square(1 + Wrap)); + float DiffuseScatter = (1 / PI) * lerp(NoL, KajiyaDiffuse, 0.33);// *s.Metallic; + float Luma = Luminance(s.Albedo); + float3 ScatterTint = pow(s.Albedo / Luma, 1 - Shadow); + S = sqrt(s.Albedo) * DiffuseScatter * ScatterTint; + return S; +} + +float3 FurBxDF(SurfaceOutputFur s, float3 N, half3 V, half3 L, float Shadow, float Backlit, float Area) +{ + float3 S = float3(0, 0, 0); + + S = FurBSDFYan(s, L, V, N, Shadow, Backlit, Area); + S += FurDiffuseKajiya(s, L, V, N, Shadow, Backlit, Area); + + S = -min(-S, 0.0); + + return S; +} + +#endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/FurSpecular.hlsl.meta b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl.meta new file mode 100644 index 0000000..740e419 --- /dev/null +++ b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4a9c4eb5427894546b064ec7b5e51258 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Fur/Shaders/Shell/Lit.hlsl b/Assets/Fur/Shaders/Shell/Lit.hlsl index 5a988c0..54dc59f 100644 --- a/Assets/Fur/Shaders/Shell/Lit.hlsl +++ b/Assets/Fur/Shaders/Shell/Lit.hlsl @@ -5,6 +5,9 @@ #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceInput.hlsl" #include "./Param.hlsl" #include "../Common/Common.hlsl" +#if defined(_FUR_SPECULAR) +#include "./FurSpecular.hlsl" +#endif struct Attributes { @@ -47,8 +50,9 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 move = moveFactor * _BaseMove.xyz; float3 shellDir = SafeNormalize(normalInput.normalWS + move + windMove); float3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS; + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.texcoord / _BaseMap_ST.xy * _FurScale, 0).x; - output.positionWS = vertexInput.positionWS + shellDir * (_ShellStep * index); + output.positionWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); output.positionCS = TransformWorldToHClip(output.positionWS); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); output.normalWS = normalInput.normalWS; @@ -108,7 +112,7 @@ float4 frag(Varyings input) : SV_Target inputData.positionWS = input.positionWS; inputData.normalWS = normalWS; inputData.viewDirectionWS = viewDirWS; -#if defined(_MAIN_LIGHT_SHADOWS) && !defined(_RECEIVE_SHADOWS_OFF) +#if defined(_MAIN_LIGHT_SHADOWS) || defined(_MAIN_LIGHT_SHADOWS_CASCADE) || defined(_MAIN_LIGHT_SHADOWS_SCREEN) && !defined(_RECEIVE_SHADOWS_OFF) inputData.shadowCoord = TransformWorldToShadowCoord(input.positionWS); #else inputData.shadowCoord = float4(0, 0, 0, 0); @@ -119,6 +123,39 @@ float4 frag(Varyings input) : SV_Target float4 color = UniversalFragmentPBR(inputData, surfaceData); +#if defined(_FUR_SPECULAR) + // Use abs(f) to avoid warning messages that f should not be negative in pow(f, e). + SurfaceOutputFur s = (SurfaceOutputFur)0; + s.Albedo = abs(SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, furUv).rgb * _BaseColor.rgb); + s.MedulaScatter = abs(_MedulaScatter); + s.MedulaAbsorb = abs(_MedulaAbsorb); + s.Normal = input.tangentWS; + s.VNormal = normalWS; + s.Alpha = 1.0; + // Convert smoothness to roughness, (1 - smoothness) is perceptual roughness. + s.Roughness = (1.0 - _Smoothness) * (1.0 - _Smoothness); + s.Emission = half3(0.0, 0.0, 0.0); + s.Specular = 0.1; + s.Layer = input.layer; + s.Kappa = (1.0 - _Kappa / 2.0); + + color.rgb += (GetMainLight().color.rgb * FurBSDFYan(s, GetMainLight().direction, viewDirWS, normalWS, 1.0, _Backlit, _Area)); + + // Too slow to calculate for all additional lights, you can enable it if needed. + /* + #ifdef _ADDITIONAL_LIGHTS + int additionalLightsCount = GetAdditionalLightsCount(); + for (int i = 0; i < additionalLightsCount; ++i) + { + int index = GetPerObjectLightIndex(i); + Light light = GetAdditionalPerObjectLight(index, input.positionWS); + color.rgb += (light.color.rgb * FurBSDFYan(s, light.direction, viewDirWS, normalWS, 1.0, _Backlit, _Area)); + } + #endif + */ + +#endif + ApplyRimLight(color.rgb, input.positionWS, viewDirWS, normalWS); color.rgb += _AmbientColor; color.rgb = MixFog(color.rgb, inputData.fogCoord); diff --git a/Assets/Fur/Shaders/Shell/Lit.shader b/Assets/Fur/Shaders/Shell/Lit.shader index 5411b5b..3886f33 100644 --- a/Assets/Fur/Shaders/Shell/Lit.shader +++ b/Assets/Fur/Shaders/Shell/Lit.shader @@ -9,24 +9,39 @@ Properties _BaseMap("Albedo", 2D) = "white" {} [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.5 _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 + [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 0.0 [Header(Fur)][Space] _FurMap("Fur", 2D) = "white" {} [Normal] _NormalMap("Normal", 2D) = "bump" {} _NormalScale("Normal Scale", Range(0.0, 2.0)) = 1.0 [IntRange] _ShellAmount("Shell Amount", Range(1, 14)) = 14 - _ShellStep("Shell Step", Range(0.0, 0.01)) = 0.001 + _ShellStep("Shell Step", Range(0.0, 0.02)) = 0.001 _AlphaCutout("Alpha Cutout", Range(0.0, 1.0)) = 0.2 _FurScale("Fur Scale", Range(0.0, 10.0)) = 1.0 _Occlusion("Occlusion", Range(0.0, 1.0)) = 0.5 + [NoScaleOffset] _FurLengthMap("Fur Length Map", 2D) = "white" {} + _FurLengthIntensity("Fur Length Intensity", Range(0.0, 5.0)) = 1.0 _BaseMove("Base Move", Vector) = (0.0, -0.0, 0.0, 3.0) _WindFreq("Wind Freq", Vector) = (0.5, 0.7, 0.9, 1.0) _WindMove("Wind Move", Vector) = (0.2, 0.3, 0.2, 1.0) - [Header(Lighting)][Space] + [Header(Lighting)] + [Header(Rim Light)][Space] _RimLightPower("Rim Light Power", Range(1.0, 20.0)) = 6.0 _RimLightIntensity("Rim Light Intensity", Range(0.0, 1.0)) = 0.5 + + [Header(Marschner Specular)][Space] + [Toggle(_FUR_SPECULAR)] _FurSpecular("Enable", Float) = 0 + _Backlit("Backlit", Range(0.0, 1.0)) = 0.5 + _Area("Lit Area", Range(0.01, 1.0)) = 0.1 + _MedulaScatter("Fur Scatter", Range(0.01, 1.0)) = 1.0 + _MedulaAbsorb("Fur Absorb", Range(0.01, 1.0)) = 0.1 + _Kappa("Kappa", Range(0.0, 2.0)) = 1.0 + + [Header(Shadow)][Space] _ShadowExtraBias("Shadow Extra Bias", Range(-1.0, 1.0)) = 0.0 + } SubShader @@ -42,23 +57,32 @@ SubShader LOD 100 ZWrite On - Cull Back + ZTest LEqual + Cull Off Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForward" } + ZWrite On + HLSLPROGRAM - // URP のキーワード + // URP 、ホ・ュゥ`・ゥ`・ノ #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE + #pragma multi_compile_fragment _ _LIGHT_LAYERS + //#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION + #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF + #pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF + + #pragma multi_compile_fragment _ _FUR_SPECULAR - // Unity のキーワード + // Unity 、ホ・ュゥ`・ゥ`・ノ #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog @@ -83,7 +107,7 @@ SubShader ColorMask 0 HLSLPROGRAM - #pragma exclude_renderers gles gles3 glcore + #pragma exclude_renderers gles #pragma vertex vert #pragma require geometry #pragma geometry geom @@ -92,6 +116,23 @@ SubShader ENDHLSL } + Pass + { + Name "DepthNormals" + Tags { "LightMode" = "DepthNormals" } + + ZWrite On + + HLSLPROGRAM + #pragma exclude_renderers gles + #pragma vertex vert + #pragma require geometry + #pragma geometry geom + #pragma fragment frag + #include "./DepthNormals.hlsl" + ENDHLSL + } + Pass { Name "ShadowCaster" @@ -102,7 +143,7 @@ SubShader ColorMask 0 HLSLPROGRAM - #pragma exclude_renderers gles gles3 glcore + #pragma exclude_renderers gles #pragma vertex vert #pragma require geometry #pragma geometry geom @@ -111,5 +152,5 @@ SubShader ENDHLSL } } - + FallBack "Hidden/Universal Render Pipeline/FallbackError" } diff --git a/Assets/Fur/Shaders/Shell/Param.hlsl b/Assets/Fur/Shaders/Shell/Param.hlsl index 00284d1..7f788dd 100644 --- a/Assets/Fur/Shaders/Shell/Param.hlsl +++ b/Assets/Fur/Shaders/Shell/Param.hlsl @@ -21,4 +21,13 @@ SAMPLER(sampler_NormalMap); float4 _NormalMap_ST; float _NormalScale; +TEXTURE2D(_FurLengthMap); +SAMPLER(sampler_FurLengthMap); +float _FurLengthIntensity; + +float _Backlit; +float _Area; +float _MedulaScatter; +float _MedulaAbsorb; +float _Kappa; #endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/Shadow.hlsl b/Assets/Fur/Shaders/Shell/Shadow.hlsl index 91acc41..96d6789 100644 --- a/Assets/Fur/Shaders/Shell/Shadow.hlsl +++ b/Assets/Fur/Shaders/Shell/Shadow.hlsl @@ -3,6 +3,8 @@ #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" +// Declare "_BaseMap_ST" for line 46. +#include "Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl" #include "./Param.hlsl" #include "../Common/Common.hlsl" @@ -41,7 +43,8 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 move = moveFactor * _BaseMove.xyz; float3 shellDir = normalize(normalInput.normalWS + move + windMove); - float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index); + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy * _FurScale, 0).x; + float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); //float4 posCS = TransformWorldToHClip(posWS); float4 posCS = GetShadowPositionHClip(posWS, normalInput.normalWS); From 43bfaf6f53e793bc469cac5566cec075f65c97d3 Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Tue, 26 Apr 2022 21:22:38 +0800 Subject: [PATCH 02/13] Change "Cull Off" to "Cull Back" (Default) --- Assets/Fur/Shaders/Shell/Lit.shader | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/Lit.shader b/Assets/Fur/Shaders/Shell/Lit.shader index 3886f33..5428743 100644 --- a/Assets/Fur/Shaders/Shell/Lit.shader +++ b/Assets/Fur/Shaders/Shell/Lit.shader @@ -58,7 +58,7 @@ SubShader ZWrite On ZTest LEqual - Cull Off + Cull Back Pass { @@ -68,7 +68,7 @@ SubShader ZWrite On HLSLPROGRAM - // URP 、ホ・ュゥ`・ゥ`・ノ + // URP 縺ョ繧ュ繝シ繝ッ繝シ繝 #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS @@ -82,7 +82,7 @@ SubShader #pragma multi_compile_fragment _ _FUR_SPECULAR - // Unity 、ホ・ュゥ`・ゥ`・ノ + // Unity 縺ョ繧ュ繝シ繝ッ繝シ繝 #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog From 6e4f60354c83e2592876e24002779ac1ed2a8807 Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Tue, 26 Apr 2022 22:31:27 +0800 Subject: [PATCH 03/13] Add MIT License for "maajor"'s code --- Assets/Fur/Shaders/Shell/FurSpecular.hlsl | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Assets/Fur/Shaders/Shell/FurSpecular.hlsl b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl index e96aebd..fcefe58 100644 --- a/Assets/Fur/Shaders/Shell/FurSpecular.hlsl +++ b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl @@ -4,6 +4,29 @@ //------------------------------------------------------------------------------------------------- // Fur shading from "maajor"'s https://github.com/maajor/Marschner-Hair-Unity, licensed under MIT. //------------------------------------------------------------------------------------------------- +//------------------------------------------------------------------------------------------------- +/*MIT License + +Copyright (c) 2019 maajor + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.*/ +//------------------------------------------------------------------------------------------------- struct SurfaceOutputFur // Upgrade NOTE: excluded shader from DX11, OpenGL ES 2.0 because it uses unsized arrays @@ -174,4 +197,4 @@ float3 FurBxDF(SurfaceOutputFur s, float3 N, half3 V, half3 L, float Shadow, flo return S; } -#endif \ No newline at end of file +#endif From dd197fe40226ae8b2ccbcc0b491576668b58e30c Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Tue, 26 Apr 2022 22:52:36 +0800 Subject: [PATCH 04/13] Correcting FurLength Calculation (Lit.hlsl) --- Assets/Fur/Shaders/Shell/Lit.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/Lit.hlsl b/Assets/Fur/Shaders/Shell/Lit.hlsl index 54dc59f..421f300 100644 --- a/Assets/Fur/Shaders/Shell/Lit.hlsl +++ b/Assets/Fur/Shaders/Shell/Lit.hlsl @@ -50,7 +50,7 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 move = moveFactor * _BaseMove.xyz; float3 shellDir = SafeNormalize(normalInput.normalWS + move + windMove); float3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS; - float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.texcoord / _BaseMap_ST.xy * _FurScale, 0).x; + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.texcoord / _BaseMap_ST.xy, 0).x; output.positionWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); output.positionCS = TransformWorldToHClip(output.positionWS); @@ -163,4 +163,4 @@ float4 frag(Varyings input) : SV_Target return color; } -#endif \ No newline at end of file +#endif From 82e93f4b12e6c1f695039024be0b31b80a85b89a Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Tue, 26 Apr 2022 22:53:17 +0800 Subject: [PATCH 05/13] Correcting FurLength Calculation (Depth.hlsl) --- Assets/Fur/Shaders/Shell/Depth.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/Depth.hlsl b/Assets/Fur/Shaders/Shell/Depth.hlsl index 750b4d9..539dca5 100644 --- a/Assets/Fur/Shaders/Shell/Depth.hlsl +++ b/Assets/Fur/Shaders/Shell/Depth.hlsl @@ -39,7 +39,7 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 move = moveFactor * _BaseMove.xyz; float3 shellDir = normalize(normalInput.normalWS + move + windMove); - float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy * _FurScale, 0).x; + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy, 0).x; float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); float4 posCS = TransformWorldToHClip(posWS); @@ -76,4 +76,4 @@ float frag(Varyings input) : SV_TARGET return input.vertex.z; //outColor = outDepth = input.vertex.z / input.vertex.w; } -#endif \ No newline at end of file +#endif From 5ae7d8256898b93f1f66f8c7a1f6c1d6a63e3898 Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Tue, 26 Apr 2022 22:54:36 +0800 Subject: [PATCH 06/13] Correcting ... (DepthNormals.hlsl) --- Assets/Fur/Shaders/Shell/DepthNormals.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/DepthNormals.hlsl b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl index c372928..d33ee4c 100644 --- a/Assets/Fur/Shaders/Shell/DepthNormals.hlsl +++ b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl @@ -43,7 +43,7 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 move = moveFactor * _BaseMove.xyz; float3 shellDir = SafeNormalize(normalInput.normalWS + move + windMove); - float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy * _FurScale, 0).x; + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy, 0).x; float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); float4 posCS = TransformWorldToHClip(posWS); @@ -92,4 +92,4 @@ float4 frag(Varyings input) : SV_Target } -#endif \ No newline at end of file +#endif From 9e69f52fe9c3b112a66cf4e1166c63e1c8b3802a Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Tue, 26 Apr 2022 22:55:14 +0800 Subject: [PATCH 07/13] Correcting ... (Shadow.hlsl) --- Assets/Fur/Shaders/Shell/Shadow.hlsl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/Shadow.hlsl b/Assets/Fur/Shaders/Shell/Shadow.hlsl index 96d6789..67b7280 100644 --- a/Assets/Fur/Shaders/Shell/Shadow.hlsl +++ b/Assets/Fur/Shaders/Shell/Shadow.hlsl @@ -43,7 +43,7 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 move = moveFactor * _BaseMove.xyz; float3 shellDir = normalize(normalInput.normalWS + move + windMove); - float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy * _FurScale, 0).x; + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy, 0).x; float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); //float4 posCS = TransformWorldToHClip(posWS); float4 posCS = GetShadowPositionHClip(posWS, normalInput.normalWS); @@ -81,4 +81,4 @@ void frag( outColor = outDepth = input.vertex.z / input.vertex.w; } -#endif \ No newline at end of file +#endif From 58910e79561034b0e88bd40e3244d3ccf4221e4d Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Wed, 27 Apr 2022 13:58:44 +0800 Subject: [PATCH 08/13] Add intros for some params --- Assets/Fur/Shaders/Shell/Lit.shader | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/Lit.shader b/Assets/Fur/Shaders/Shell/Lit.shader index 5428743..6c51a2c 100644 --- a/Assets/Fur/Shaders/Shell/Lit.shader +++ b/Assets/Fur/Shaders/Shell/Lit.shader @@ -9,6 +9,8 @@ Properties _BaseMap("Albedo", 2D) = "white" {} [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.5 _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 + + [Header(Reduce Flickering)][Space] [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 0.0 [Header(Fur)][Space] @@ -31,9 +33,9 @@ Properties _RimLightPower("Rim Light Power", Range(1.0, 20.0)) = 6.0 _RimLightIntensity("Rim Light Intensity", Range(0.0, 1.0)) = 0.5 - [Header(Marschner Specular)][Space] + [Header(Marschner Scatter)][Space] [Toggle(_FUR_SPECULAR)] _FurSpecular("Enable", Float) = 0 - _Backlit("Backlit", Range(0.0, 1.0)) = 0.5 + _Backlit("Back Lit", Range(0.0, 1.0)) = 0.5 _Area("Lit Area", Range(0.01, 1.0)) = 0.1 _MedulaScatter("Fur Scatter", Range(0.01, 1.0)) = 1.0 _MedulaAbsorb("Fur Absorb", Range(0.01, 1.0)) = 0.1 @@ -78,7 +80,6 @@ SubShader #pragma multi_compile_fragment _ _LIGHT_LAYERS //#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF - #pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF #pragma multi_compile_fragment _ _FUR_SPECULAR From edcff20e3baa7deb492da252687bb87686d4a6a3 Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Wed, 27 Apr 2022 15:00:22 +0800 Subject: [PATCH 09/13] Turn SSAO Keyword on Don't know why I disabled it. Did not mention "Light Layer" on UPR12 because it does not support Specular Scattering, will add support (later...). --- Assets/Fur/Shaders/Shell/Lit.shader | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Fur/Shaders/Shell/Lit.shader b/Assets/Fur/Shaders/Shell/Lit.shader index 6c51a2c..3c36c46 100644 --- a/Assets/Fur/Shaders/Shell/Lit.shader +++ b/Assets/Fur/Shaders/Shell/Lit.shader @@ -78,7 +78,7 @@ SubShader #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE #pragma multi_compile_fragment _ _LIGHT_LAYERS - //#pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION + #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF #pragma multi_compile_fragment _ _FUR_SPECULAR From 252b8e4cafa55ded2bbc8c42a67bffffa1cd36ae Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Thu, 28 Apr 2022 01:33:55 +0800 Subject: [PATCH 10/13] Fix wrong Marschner Scatter with BaseMap Scale I used a wrong uv to sample the BaseMap. Just realized it because scaling the BaseMap is not common (except testing scene) --- Assets/Fur/Shaders/Shell/Lit.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Fur/Shaders/Shell/Lit.hlsl b/Assets/Fur/Shaders/Shell/Lit.hlsl index 421f300..a3c5667 100644 --- a/Assets/Fur/Shaders/Shell/Lit.hlsl +++ b/Assets/Fur/Shaders/Shell/Lit.hlsl @@ -126,7 +126,7 @@ float4 frag(Varyings input) : SV_Target #if defined(_FUR_SPECULAR) // Use abs(f) to avoid warning messages that f should not be negative in pow(f, e). SurfaceOutputFur s = (SurfaceOutputFur)0; - s.Albedo = abs(SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, furUv).rgb * _BaseColor.rgb); + s.Albedo = abs(SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).rgb * _BaseColor.rgb); s.MedulaScatter = abs(_MedulaScatter); s.MedulaAbsorb = abs(_MedulaAbsorb); s.Normal = input.tangentWS; From c9b50413a7bdeab05deb6aa48d7cc9223e5dc453 Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Fri, 29 Apr 2022 04:15:49 +0800 Subject: [PATCH 11/13] Various features added (Part2) 1. Add XR single pass instance support for both Shell Lit and Shell Unlit. 2. Increase maximum shell amount. (requires "#pragma target 4.6", or will fall back to 13 shells.) 3. Add option to disable fur shadow (show original mesh shadow only). --- Assets/Fur/Shaders/Shell/Depth.hlsl | 118 ++++++++++++++-- Assets/Fur/Shaders/Shell/DepthNormals.hlsl | 120 ++++++++++++++-- Assets/Fur/Shaders/Shell/FurSpecular.hlsl | 25 +--- Assets/Fur/Shaders/Shell/Lit.hlsl | 146 +++++++++++++++++-- Assets/Fur/Shaders/Shell/Lit.shader | 155 +++++++++++++++++++-- Assets/Fur/Shaders/Shell/Param.hlsl | 2 + Assets/Fur/Shaders/Shell/Shadow.hlsl | 131 +++++++++++++++-- Assets/Fur/Shaders/Shell/Unlit.hlsl | 43 +++++- 8 files changed, 653 insertions(+), 87 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/Depth.hlsl b/Assets/Fur/Shaders/Shell/Depth.hlsl index 539dca5..5a99323 100644 --- a/Assets/Fur/Shaders/Shell/Depth.hlsl +++ b/Assets/Fur/Shaders/Shell/Depth.hlsl @@ -3,6 +3,8 @@ #include "Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl" #include "./Param.hlsl" +// For VR single pass instance compability: +#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { @@ -10,29 +12,63 @@ struct Attributes float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID }; -struct Varyings +struct v2g +{ + float4 positionOS : POSITION; + float3 normalOS : NORMAL; + float4 tangentOS : TANGENT; + float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID +}; + +struct g2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float fogCoord : TEXCOORD1; float layer : TEXCOORD2; + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO }; -Attributes vert(Attributes input) +v2g vert(Attributes input) { - return input; + v2g output = (v2g)0; + // setup the instanced id + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the "v2g output" to 0.0 + // This is the URP version of UNITY_INITIALIZE_OUTPUT() + ZERO_INITIALIZE(v2g, output); + // copy instance id in the "Attributes input" to the "v2g output" + UNITY_TRANSFER_INSTANCE_ID(input, output); + + output.positionOS = input.positionOS; + output.normalOS = input.normalOS; + output.tangentOS = input.tangentOS; + output.uv = input.uv; + return output; } -void AppendShellVertex(inout TriangleStream stream, Attributes input, int index) +void AppendShellVertex(inout TriangleStream stream, v2g input, int index) { - Varyings output = (Varyings)0; + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); - float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); + float clampedShellAmount = clamp(_ShellAmount, 1, 13); + _ShellStep = _TotalShellStep / clampedShellAmount; + + float moveFactor = pow(abs((float)index / clamp(_ShellAmount, 1, 13)), _BaseMove.w); float3 posOS = input.positionOS.xyz; float3 windAngle = _Time.w * _WindFreq.xyz; float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); @@ -43,6 +79,41 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); float4 posCS = TransformWorldToHClip(posWS); + output.vertex = posCS; + output.uv = TRANSFORM_TEX(input.uv, _BaseMap); + output.fogCoord = ComputeFogFactor(posCS.z); + output.layer = (float)index / clamp(_ShellAmount, 1, 13); + + stream.Append(output); +} + +// For geometry shader instancing, no clamp on _ShellAmount. +void AppendShellVertexInstancing(inout TriangleStream stream, v2g input, int index) +{ + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); + VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); + + _ShellStep = _TotalShellStep / _ShellAmount; + + float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); + float3 posOS = input.positionOS.xyz; + float3 windAngle = _Time.w * _WindFreq.xyz; + float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); + float3 move = moveFactor * _BaseMove.xyz; + + float3 shellDir = normalize(normalInput.normalWS + move + windMove); + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy, 0).x; + float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); + float4 posCS = TransformWorldToHClip(posWS); + output.vertex = posCS; output.uv = TRANSFORM_TEX(input.uv, _BaseMap); output.fogCoord = ComputeFogFactor(posCS.z); @@ -51,10 +122,33 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, stream.Append(output); } -[maxvertexcount(128)] -void geom(triangle Attributes input[3], inout TriangleStream stream) +//-----------------------------------(below) For Microsoft Shader Model > 4.1----------------------------------- +// See "Lit.hlsl" for more information. +#if defined(_GEOM_INSTANCING) +[instance(3)] +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream, uint instanceID : SV_GSInstanceID) { - [loop] for (float i = 0; i < _ShellAmount; ++i) + // 13 is calculated manually, because "maxvertexcount" is 39 in "Lit.hlsl", keep all passes to have the smallest (39 now). + // If not, DepthNormals will be incorrect and Depth Priming (DepthNormal Mode) won't work. + // "39 / 3 = 13", 3 means 3 vertices of a tirangle. + [loop] for (float i = 0 + (instanceID * 13); i < _ShellAmount; ++i) + { + [unroll] for (float j = 0; j < 3; ++j) + { + AppendShellVertexInstancing(stream, input[j], i); + } + stream.RestartStrip(); + } +} +//-----------------------------------(above) For Microsoft Shader Model > 4.1----------------------------------- + +//-----------------------------------(below) For Microsoft Shader Model < 4.1----------------------------------- +#else +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream) +{ + [loop] for (float i = 0; i < clamp(_ShellAmount, 1, 13); ++i) { [unroll] for (float j = 0; j < 3; ++j) { @@ -63,10 +157,12 @@ void geom(triangle Attributes input[3], inout TriangleStream stream) stream.RestartStrip(); } } +#endif +//-----------------------------------(above) For Microsoft Shader Model < 4.1----------------------------------- // Previous frag() causes Depth Priming error (black pixels), // when enabling "Depth Priming + MSAA" in URP 12.1. -float frag(Varyings input) : SV_TARGET +float frag(g2f input) : SV_TARGET { float4 furColor = SAMPLE_TEXTURE2D(_FurMap, sampler_FurMap, input.uv / _BaseMap_ST.xy * _FurScale); float alpha = furColor.r * (1.0 - input.layer); @@ -76,4 +172,4 @@ float frag(Varyings input) : SV_TARGET return input.vertex.z; //outColor = outDepth = input.vertex.z / input.vertex.w; } -#endif +#endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/DepthNormals.hlsl b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl index d33ee4c..e8199be 100644 --- a/Assets/Fur/Shaders/Shell/DepthNormals.hlsl +++ b/Assets/Fur/Shaders/Shell/DepthNormals.hlsl @@ -4,6 +4,8 @@ #include "Packages/com.unity.render-pipelines.universal/Shaders/LitInput.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderVariablesFunctions.hlsl" #include "./Param.hlsl" +// For VR single pass instance compability: +#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { @@ -11,9 +13,19 @@ struct Attributes half3 normalOS : NORMAL; half4 tangentOS : TANGENT; float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID }; -struct Varyings +struct v2g +{ + half4 positionOS : POSITION; + half3 normalOS : NORMAL; + half4 tangentOS : TANGENT; + float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID +}; + +struct g2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; @@ -22,20 +34,83 @@ struct Varyings float3 normalWS : TEXCOORD2; float3 tangentWS : TEXCOORD3; float3 posWS : TEXCOORD4; + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO }; -Attributes vert(Attributes input) +v2g vert(Attributes input) +{ + v2g output = (v2g)0; + // setup the instanced id + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the "v2g output" to 0.0 + // This is the URP version of UNITY_INITIALIZE_OUTPUT() + ZERO_INITIALIZE(v2g, output); + // copy instance id in the "Attributes input" to the "v2g output" + UNITY_TRANSFER_INSTANCE_ID(input, output); + + output.positionOS = input.positionOS; + output.normalOS = input.normalOS; + output.tangentOS = input.tangentOS; + output.uv = input.uv; + return output; +} + +void AppendShellVertex(inout TriangleStream stream, v2g input, int index) { - return input; + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); + VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); + + float clampedShellAmount = clamp(_ShellAmount, 1, 13); + _ShellStep = _TotalShellStep / clampedShellAmount; + + float moveFactor = pow(abs((float)index / clamp(_ShellAmount, 1, 13)), _BaseMove.w); + float3 posOS = input.positionOS.xyz; + float3 windAngle = _Time.w * _WindFreq.xyz; + float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); + float3 move = moveFactor * _BaseMove.xyz; + + float3 shellDir = SafeNormalize(normalInput.normalWS + move + windMove); + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy, 0).x; + float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); + float4 posCS = TransformWorldToHClip(posWS); + + output.vertex = posCS; + output.posWS = posWS; + output.uv = TRANSFORM_TEX(input.uv, _BaseMap); + output.layer = (float)index / clamp(_ShellAmount, 1, 13); + + output.normalWS = normalInput.normalWS; + output.tangentWS = normalInput.tangentWS; + + + stream.Append(output); } -void AppendShellVertex(inout TriangleStream stream, Attributes input, int index) +// For geometry shader instancing, no clamp on _ShellAmount. +void AppendShellVertexInstancing(inout TriangleStream stream, v2g input, int index) { - Varyings output = (Varyings)0; + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); + _ShellStep = _TotalShellStep / _ShellAmount; + float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); float3 posOS = input.positionOS.xyz; float3 windAngle = _Time.w * _WindFreq.xyz; @@ -59,10 +134,33 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, stream.Append(output); } -[maxvertexcount(51)] -void geom(triangle Attributes input[3], inout TriangleStream stream) +//-----------------------------------(below) For Microsoft Shader Model > 4.1----------------------------------- +// See "Lit.hlsl" for more information. +#if defined(_GEOM_INSTANCING) +[instance(3)] +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream, uint instanceID : SV_GSInstanceID) +{ + // 13 is calculated manually, because "maxvertexcount" is 39 in "Lit.hlsl", keep all passes to have the smallest (39 now). + // If not, DepthNormals will be incorrect and Depth Priming (DepthNormal Mode) won't work. + // "39 / 3 = 13", 3 means 3 vertices of a tirangle. + [loop] for (float i = 0 + (instanceID * 13); i < _ShellAmount; ++i) + { + [unroll] for (float j = 0; j < 3; ++j) + { + AppendShellVertexInstancing(stream, input[j], i); + } + stream.RestartStrip(); + } +} +//-----------------------------------(above) For Microsoft Shader Model > 4.1----------------------------------- + +//-----------------------------------(below) For Microsoft Shader Model < 4.1----------------------------------- +#else +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream) { - [loop] for (float i = 0; i < _ShellAmount; ++i) + [loop] for (float i = 0; i < clamp(_ShellAmount, 1, 13); ++i) { [unroll] for (float j = 0; j < 3; ++j) { @@ -71,8 +169,10 @@ void geom(triangle Attributes input[3], inout TriangleStream stream) stream.RestartStrip(); } } +#endif +//-----------------------------------(above) For Microsoft Shader Model < 4.1----------------------------------- -float4 frag(Varyings input) : SV_Target +float4 frag(g2f input) : SV_Target { float4 furColor = SAMPLE_TEXTURE2D(_FurMap, sampler_FurMap, input.uv / _BaseMap_ST.xy * _FurScale); float alpha = furColor.r * (1.0 - input.layer); @@ -92,4 +192,4 @@ float4 frag(Varyings input) : SV_Target } -#endif +#endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/FurSpecular.hlsl b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl index fcefe58..e96aebd 100644 --- a/Assets/Fur/Shaders/Shell/FurSpecular.hlsl +++ b/Assets/Fur/Shaders/Shell/FurSpecular.hlsl @@ -4,29 +4,6 @@ //------------------------------------------------------------------------------------------------- // Fur shading from "maajor"'s https://github.com/maajor/Marschner-Hair-Unity, licensed under MIT. //------------------------------------------------------------------------------------------------- -//------------------------------------------------------------------------------------------------- -/*MIT License - -Copyright (c) 2019 maajor - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE.*/ -//------------------------------------------------------------------------------------------------- struct SurfaceOutputFur // Upgrade NOTE: excluded shader from DX11, OpenGL ES 2.0 because it uses unsized arrays @@ -197,4 +174,4 @@ float3 FurBxDF(SurfaceOutputFur s, float3 N, half3 V, half3 L, float Shadow, flo return S; } -#endif +#endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/Lit.hlsl b/Assets/Fur/Shaders/Shell/Lit.hlsl index a3c5667..779b46a 100644 --- a/Assets/Fur/Shaders/Shell/Lit.hlsl +++ b/Assets/Fur/Shaders/Shell/Lit.hlsl @@ -8,6 +8,8 @@ #if defined(_FUR_SPECULAR) #include "./FurSpecular.hlsl" #endif +// VR single pass instance compability: +#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { @@ -19,7 +21,17 @@ struct Attributes UNITY_VERTEX_INPUT_INSTANCE_ID }; -struct Varyings +struct v2g +{ + float4 positionOS : POSITION; + float3 normalOS : NORMAL; + float4 tangentOS : TANGENT; + float2 texcoord : TEXCOORD0; + float2 lightmapUV : TEXCOORD1; + UNITY_VERTEX_INPUT_INSTANCE_ID +}; + +struct g2f { float4 positionCS : SV_POSITION; float3 positionWS : TEXCOORD0; @@ -29,21 +41,46 @@ struct Varyings DECLARE_LIGHTMAP_OR_SH(lightmapUV, vertexSH, 5); float4 fogFactorAndVertexLight : TEXCOORD6; // x: fogFactor, yzw: vertex light float layer : TEXCOORD7; + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO }; -Attributes vert(Attributes input) +v2g vert(Attributes input) { - return input; + v2g output = (v2g)0; + // setup the instanced id + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the "v2g output" to 0.0 + // This is the URP version of UNITY_INITIALIZE_OUTPUT() + ZERO_INITIALIZE(v2g, output); + // copy instance id in the "Attributes input" to the "v2g output" + UNITY_TRANSFER_INSTANCE_ID(input, output); + + output.positionOS = input.positionOS; + output.normalOS = input.normalOS; + output.tangentOS = input.tangentOS; + output.lightmapUV = input.lightmapUV; + output.texcoord = input.texcoord; + return output; } -void AppendShellVertex(inout TriangleStream stream, Attributes input, int index) +void AppendShellVertex(inout TriangleStream stream, v2g input, int index) { - Varyings output = (Varyings)0; + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); - float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); + float clampedShellAmount = clamp(_ShellAmount, 1, 13); + _ShellStep = _TotalShellStep / clampedShellAmount; + + float moveFactor = pow(abs((float)index / clampedShellAmount), _BaseMove.w); float3 posOS = input.positionOS.xyz; float3 windAngle = _Time.w * _WindFreq.xyz; float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); @@ -52,6 +89,49 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, float3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS; float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.texcoord / _BaseMap_ST.xy, 0).x; + output.positionWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); + output.positionCS = TransformWorldToHClip(output.positionWS); + output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); + output.normalWS = normalInput.normalWS; + output.tangentWS = normalInput.tangentWS; + output.layer = (float)index / clampedShellAmount; + + float3 vertexLight = VertexLighting(vertexInput.positionWS, normalInput.normalWS); + float fogFactor = ComputeFogFactor(vertexInput.positionCS.z); + output.fogFactorAndVertexLight = float4(fogFactor, vertexLight); + + OUTPUT_LIGHTMAP_UV(input.lightmapUV, unity_LightmapST, output.lightmapUV); + OUTPUT_SH(output.normalWS.xyz, output.vertexSH); + + + stream.Append(output); +} + +// For geometry shader instancing, no clamp on _ShellAmount. +void AppendShellVertexInstancing(inout TriangleStream stream, v2g input, int index) +{ + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); + VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); + + _ShellStep = _TotalShellStep / _ShellAmount; + + float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); + float3 posOS = input.positionOS.xyz; + float3 windAngle = _Time.w * _WindFreq.xyz; + float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); + float3 move = moveFactor * _BaseMove.xyz; + float3 shellDir = SafeNormalize(normalInput.normalWS + move + windMove); + float3 viewDirWS = GetCameraPositionWS() - vertexInput.positionWS; + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.texcoord / _BaseMap_ST.xy, 0).x; + output.positionWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); output.positionCS = TransformWorldToHClip(output.positionWS); output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap); @@ -66,13 +146,52 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, OUTPUT_LIGHTMAP_UV(input.lightmapUV, unity_LightmapST, output.lightmapUV); OUTPUT_SH(output.normalWS.xyz, output.vertexSH); + stream.Append(output); } -[maxvertexcount(42)] -void geom(triangle Attributes input[3], inout TriangleStream stream) +//-----------------------------------(below) For Microsoft Shader Model > 4.1----------------------------------- +// "[instance(3)]" = 3+1 geometry shader instances, so we can have at most 13x4 = 52 shells +// +// If you need 200 shells (too much for game): +// "200 / 13 = 15, remains 5" +// +// You will need "16" instances, "15" for 195 shells, "1" for 5 remaining shells. +// +// IMPORTANT: if you set [instance(30)] for 200 shells, you will waste performance because +// "stream.RestartStrip()" will run on 14 istances (with empty output). +// +// Please keep "n" in [instance(n)] the same for all "passes.hlsl" (Lit, Depth, DepthNormals, Shadow,...) +// Or something will break! (post-processing in most cases) +// +// LIMIT: You can only have up to 32 instances, so (32+1)x13 = 429 shells at most. +#if defined(_GEOM_INSTANCING) +[instance(3)] +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream, uint instanceID : SV_GSInstanceID) { - [loop] for (float i = 0; i < _ShellAmount; ++i) + // 13 is calculated manually, because "maxvertexcount" is 39 in "Lit.hlsl", keep all passes to have the smallest (39 now). + // If not, DepthNormals will be incorrect and Depth Priming (DepthNormal Mode) won't work. + // "39 / 3 = 13", 3 means 3 vertices of a tirangle. + [loop] for (float i = 0 + (instanceID * 13); i < _ShellAmount; ++i) + { + [unroll] for (float j = 0; j < 3; ++j) + { + AppendShellVertexInstancing(stream, input[j], i); + } + stream.RestartStrip(); + } +} +//-----------------------------------(above) For Microsoft Shader Model > 4.1----------------------------------- + +//-----------------------------------(below) For Microsoft Shader Model < 4.1----------------------------------- +// For device that does not support geometry shader instancing. +// Available since Microsoft Shader Model 4.1, it is "target 4.6" in Unity. +#else +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream) +{ + [loop] for (float i = 0; i < clamp(_ShellAmount, 1, 13); ++i) { [unroll] for (float j = 0; j < 3; ++j) { @@ -81,14 +200,17 @@ void geom(triangle Attributes input[3], inout TriangleStream stream) stream.RestartStrip(); } } +#endif +//-----------------------------------(above) For Microsoft Shader Model < 4.1----------------------------------- inline float3 TransformHClipToWorld(float4 positionCS) { return mul(UNITY_MATRIX_I_VP, positionCS).xyz; } -float4 frag(Varyings input) : SV_Target +float4 frag(g2f input) : SV_Target { + float2 furUv = input.uv / _BaseMap_ST.xy * _FurScale; float4 furColor = SAMPLE_TEXTURE2D(_FurMap, sampler_FurMap, furUv); float alpha = furColor.r * (1.0 - input.layer); @@ -158,9 +280,11 @@ float4 frag(Varyings input) : SV_Target ApplyRimLight(color.rgb, input.positionWS, viewDirWS, normalWS); color.rgb += _AmbientColor; + // Disable "Specular Highlights" instead of clamping, + // to avoid reducing Bloom and Scatter strength. color.rgb = MixFog(color.rgb, inputData.fogCoord); return color; } -#endif +#endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/Lit.shader b/Assets/Fur/Shaders/Shell/Lit.shader index 3c36c46..43d4699 100644 --- a/Assets/Fur/Shaders/Shell/Lit.shader +++ b/Assets/Fur/Shaders/Shell/Lit.shader @@ -9,16 +9,19 @@ Properties _BaseMap("Albedo", 2D) = "white" {} [Gamma] _Metallic("Metallic", Range(0.0, 1.0)) = 0.5 _Smoothness("Smoothness", Range(0.0, 1.0)) = 0.5 - + [Header(Reduce Flickering)][Space] [ToggleOff] _SpecularHighlights("Specular Highlights", Float) = 0.0 [Header(Fur)][Space] - _FurMap("Fur", 2D) = "white" {} - [Normal] _NormalMap("Normal", 2D) = "bump" {} + [NoScaleOffset]_FurMap("Fur", 2D) = "white" {} + [NoScaleOffset][Normal] _NormalMap("Normal", 2D) = "bump" {} _NormalScale("Normal Scale", Range(0.0, 2.0)) = 1.0 - [IntRange] _ShellAmount("Shell Amount", Range(1, 14)) = 14 - _ShellStep("Shell Step", Range(0.0, 0.02)) = 0.001 + [IntRange] _ShellAmount("Shell Amount", Range(1, 52)) = 13 + [Header(More Shell Amount)][Space] + [Toggle(_GEOM_INSTANCING)] _GeomInstancing("Enable", Float) = 0 + [HideInInspector] _ShellStep("Shell Step", Range(0.0, 0.02)) = 0.001 + [Space][Space] _TotalShellStep("Total Shell Step", Range(0.0, 0.25)) = 0.026 _AlphaCutout("Alpha Cutout", Range(0.0, 1.0)) = 0.2 _FurScale("Fur Scale", Range(0.0, 10.0)) = 1.0 _Occlusion("Occlusion", Range(0.0, 1.0)) = 0.5 @@ -35,7 +38,7 @@ Properties [Header(Marschner Scatter)][Space] [Toggle(_FUR_SPECULAR)] _FurSpecular("Enable", Float) = 0 - _Backlit("Back Lit", Range(0.0, 1.0)) = 0.5 + _Backlit("Backlit", Range(0.0, 1.0)) = 0.5 _Area("Lit Area", Range(0.01, 1.0)) = 0.1 _MedulaScatter("Fur Scatter", Range(0.01, 1.0)) = 1.0 _MedulaAbsorb("Fur Absorb", Range(0.01, 1.0)) = 0.1 @@ -43,6 +46,7 @@ Properties [Header(Shadow)][Space] _ShadowExtraBias("Shadow Extra Bias", Range(-1.0, 1.0)) = 0.0 + [Toggle(_NO_FUR_SHADOW)] _NoFurShadow("Mesh Shadow Only", Float) = 0 } @@ -70,30 +74,149 @@ SubShader ZWrite On HLSLPROGRAM - // URP 縺ョ繧ュ繝シ繝ッ繝シ繝 + // URP 、ホ・ュゥ`・ゥ`・ノ +#if (UNITY_VERSION >= 202111) + #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN + #pragma multi_compile_fragment _ _LIGHT_LAYERS +#else #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE +#endif #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE + #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION + #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF + //#pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF + + #pragma multi_compile_fragment _ _FUR_SPECULAR + #pragma multi_compile _ _GEOM_INSTANCING + + // Unity 、ホ・ュゥ`・ゥ`・ノ + #pragma multi_compile _ DIRLIGHTMAP_COMBINED + #pragma multi_compile _ LIGHTMAP_ON + #pragma multi_compile_fog + #pragma multi_compile_instancing + #pragma multi_compile _ DOTS_INSTANCING_ON + + #pragma prefer_hlslcc gles + #pragma exclude_renderers d3d11_9x + // if "_GEOM_INSTANCING", then Microsoft ShaderModel 4.1 (geometry shader instancing support) + // It is "target 4.6" in Unity. (Tested on OpenGL 4.1, instancing not supported on OpenGL 4.0) + #pragma target 4.6 _GEOM_INSTANCING + #pragma vertex vert + #pragma require geometry + #pragma geometry geom + #pragma fragment frag + #include "./Lit.hlsl" + ENDHLSL + } + + Pass + { + Name "DepthOnly" + Tags { "LightMode" = "DepthOnly" } + + ZWrite On + ColorMask 0 + + HLSLPROGRAM + #pragma multi_compile _ _GEOM_INSTANCING + + #pragma exclude_renderers gles + #pragma vertex vert + #pragma require geometry + #pragma geometry geom + #pragma fragment frag + #pragma target 4.6 _GEOM_INSTANCING + #include "./Depth.hlsl" + ENDHLSL + } + + Pass + { + Name "DepthNormals" + Tags { "LightMode" = "DepthNormals" } + + ZWrite On + + HLSLPROGRAM + #pragma multi_compile _ _GEOM_INSTANCING + + #pragma exclude_renderers gles + #pragma vertex vert + #pragma require geometry + #pragma geometry geom + #pragma fragment frag + #pragma target 4.6 _GEOM_INSTANCING + #include "./DepthNormals.hlsl" + ENDHLSL + } + + Pass + { + Name "ShadowCaster" + Tags { "LightMode" = "ShadowCaster" } + + ZWrite On + ZTest LEqual + ColorMask 0 + + HLSLPROGRAM + #pragma multi_compile _ _GEOM_INSTANCING + #pragma multi_compile _ _NO_FUR_SHADOW + + #pragma exclude_renderers gles + #pragma vertex vert + #pragma require geometry + #pragma geometry geom + #pragma fragment frag + #pragma target 4.6 _GEOM_INSTANCING + #include "./Shadow.hlsl" + ENDHLSL + } + +//---------------------------For Microsoft Shader Model < 4.1--------------------------------------------- +//-----------------------Geometry Shader Instancing not supported.---------------------------------------- + Pass + { + Name "ForwardLit" + Tags { "LightMode" = "UniversalForward" } + + ZWrite On + + HLSLPROGRAM + // URP 、ホ・ュゥ`・ゥ`・ノ +#if (UNITY_VERSION >= 202111) + #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN #pragma multi_compile_fragment _ _LIGHT_LAYERS +#else + #pragma multi_compile _ _MAIN_LIGHT_SHADOWS + #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE +#endif + #pragma multi_compile _ _ADDITIONAL_LIGHTS_VERTEX _ADDITIONAL_LIGHTS + #pragma multi_compile _ _ADDITIONAL_LIGHT_SHADOWS + #pragma multi_compile _ _SHADOWS_SOFT + #pragma multi_compile _ _MIXED_LIGHTING_SUBTRACTIVE #pragma multi_compile_fragment _ _SCREEN_SPACE_OCCLUSION #pragma shader_feature _ _SPECULARHIGHLIGHTS_OFF + //#pragma shader_feature_local_fragment _ENVIRONMENTREFLECTIONS_OFF #pragma multi_compile_fragment _ _FUR_SPECULAR - // Unity 縺ョ繧ュ繝シ繝ッ繝シ繝 + // Unity 、ホ・ュゥ`・ゥ`・ノ #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog + #pragma multi_compile_instancing + #pragma multi_compile _ DOTS_INSTANCING_ON #pragma prefer_hlslcc gles #pragma exclude_renderers d3d11_9x - #pragma target 2.0 #pragma vertex vert #pragma require geometry - #pragma geometry geom + #pragma geometry geom #pragma fragment frag #include "./Lit.hlsl" ENDHLSL @@ -108,10 +231,12 @@ SubShader ColorMask 0 HLSLPROGRAM + #pragma multi_compile _ _GEOM_INSTANCING + #pragma exclude_renderers gles #pragma vertex vert #pragma require geometry - #pragma geometry geom + #pragma geometry geom #pragma fragment frag #include "./Depth.hlsl" ENDHLSL @@ -125,10 +250,12 @@ SubShader ZWrite On HLSLPROGRAM + #pragma multi_compile _ _GEOM_INSTANCING + #pragma exclude_renderers gles #pragma vertex vert #pragma require geometry - #pragma geometry geom + #pragma geometry geom #pragma fragment frag #include "./DepthNormals.hlsl" ENDHLSL @@ -144,10 +271,12 @@ SubShader ColorMask 0 HLSLPROGRAM + #pragma multi_compile _ _NO_FUR_SHADOW + #pragma exclude_renderers gles #pragma vertex vert #pragma require geometry - #pragma geometry geom + #pragma geometry geom #pragma fragment frag #include "./Shadow.hlsl" ENDHLSL diff --git a/Assets/Fur/Shaders/Shell/Param.hlsl b/Assets/Fur/Shaders/Shell/Param.hlsl index 7f788dd..d2c00ca 100644 --- a/Assets/Fur/Shaders/Shell/Param.hlsl +++ b/Assets/Fur/Shaders/Shell/Param.hlsl @@ -25,6 +25,8 @@ TEXTURE2D(_FurLengthMap); SAMPLER(sampler_FurLengthMap); float _FurLengthIntensity; +float _TotalShellStep; + float _Backlit; float _Area; float _MedulaScatter; diff --git a/Assets/Fur/Shaders/Shell/Shadow.hlsl b/Assets/Fur/Shaders/Shell/Shadow.hlsl index 67b7280..8182d56 100644 --- a/Assets/Fur/Shaders/Shell/Shadow.hlsl +++ b/Assets/Fur/Shaders/Shell/Shadow.hlsl @@ -3,10 +3,12 @@ #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" -// Declare "_BaseMap_ST" for line 46. +// Declare "_BaseMap_ST" for line 76. #include "Packages/com.unity.render-pipelines.universal/Shaders/UnlitInput.hlsl" #include "./Param.hlsl" #include "../Common/Common.hlsl" +// For VR single pass instance compability: +#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" struct Attributes { @@ -14,29 +16,63 @@ struct Attributes float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID }; -struct Varyings +struct v2g +{ + float4 positionOS : POSITION; + float3 normalOS : NORMAL; + float4 tangentOS : TANGENT; + float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID +}; + +struct g2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float fogCoord : TEXCOORD1; float layer : TEXCOORD2; + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO }; -Attributes vert(Attributes input) +v2g vert(Attributes input) { - return input; + v2g output = (v2g)0; + // setup the instanced id + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the "v2g output" to 0.0 + // This is the URP version of UNITY_INITIALIZE_OUTPUT() + ZERO_INITIALIZE(v2g, output); + // copy instance id in the "Attributes input" to the "v2g output" + UNITY_TRANSFER_INSTANCE_ID(input, output); + + output.positionOS = input.positionOS; + output.normalOS = input.normalOS; + output.tangentOS = input.tangentOS; + output.uv = input.uv; + return output; } -void AppendShellVertex(inout TriangleStream stream, Attributes input, int index) +void AppendShellVertex(inout TriangleStream stream, v2g input, int index) { - Varyings output = (Varyings)0; + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); - float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); + float clampedShellAmount = clamp(_ShellAmount, 1, 13); + _ShellStep = _TotalShellStep / clampedShellAmount; + + float moveFactor = pow(abs((float)index / clamp(_ShellAmount, 1, 13)), _BaseMove.w); float3 posOS = input.positionOS.xyz; float3 windAngle = _Time.w * _WindFreq.xyz; float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); @@ -48,6 +84,42 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, //float4 posCS = TransformWorldToHClip(posWS); float4 posCS = GetShadowPositionHClip(posWS, normalInput.normalWS); + output.vertex = posCS; + output.uv = TRANSFORM_TEX(input.uv, _FurMap); + output.fogCoord = ComputeFogFactor(posCS.z); + output.layer = (float)index / clamp(_ShellAmount, 1, 13); + + stream.Append(output); +} + +// For geometry shader instancing, no clamp on _ShellAmount. +void AppendShellVertexInstancing(inout TriangleStream stream, v2g input, int index) +{ + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); + VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); + + _ShellStep = _TotalShellStep / _ShellAmount; + + float moveFactor = pow(abs((float)index / _ShellAmount), _BaseMove.w); + float3 posOS = input.positionOS.xyz; + float3 windAngle = _Time.w * _WindFreq.xyz; + float3 windMove = moveFactor * _WindMove.xyz * sin(windAngle + posOS * _WindMove.w); + float3 move = moveFactor * _BaseMove.xyz; + + float3 shellDir = normalize(normalInput.normalWS + move + windMove); + float FurLength = SAMPLE_TEXTURE2D_LOD(_FurLengthMap, sampler_FurLengthMap, input.uv / _BaseMap_ST.xy, 0).x; + float3 posWS = vertexInput.positionWS + shellDir * (_ShellStep * index * FurLength * _FurLengthIntensity); + //float4 posCS = TransformWorldToHClip(posWS); + float4 posCS = GetShadowPositionHClip(posWS, normalInput.normalWS); + output.vertex = posCS; output.uv = TRANSFORM_TEX(input.uv, _FurMap); output.fogCoord = ComputeFogFactor(posCS.z); @@ -56,10 +128,43 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, stream.Append(output); } -[maxvertexcount(128)] -void geom(triangle Attributes input[3], inout TriangleStream stream) +//-----------------------------------(below) For Microsoft Shader Model > 4.1----------------------------------- +// See "Lit.hlsl" for more information. +#if defined(_GEOM_INSTANCING) +[instance(3)] +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream, uint instanceID : SV_GSInstanceID) { - [loop] for (float i = 0; i < _ShellAmount; ++i) +#if defined(_NO_FUR_SHADOW) + float loopTimes = 1; +#else + float loopTimes = _ShellAmount; +#endif + // 13 is calculated manually, because "maxvertexcount" is 39 in "Lit.hlsl", keep all passes to have the smallest (39 now). + // If not, DepthNormals will be incorrect and Depth Priming (DepthNormal Mode) won't work. + // "39 / 3 = 13", 3 means 3 vertices of a tirangle. + [loop] for (float i = 0 + (instanceID * 13); i < loopTimes; ++i) + { + [unroll] for (float j = 0; j < 3; ++j) + { + AppendShellVertexInstancing(stream, input[j], i); + } + stream.RestartStrip(); + } +} +//-----------------------------------(above) For Microsoft Shader Model > 4.1----------------------------------- + +//-----------------------------------(below) For Microsoft Shader Model < 4.1----------------------------------- +#else +[maxvertexcount(39)] +void geom(triangle v2g input[3], inout TriangleStream stream) +{ +#if defined(_NO_FUR_SHADOW) + float loopTimes = 1; +#else + float loopTimes = clamp(_ShellAmount, 1, 13); +#endif + [loop] for (float i = 0; i < loopTimes; ++i) { [unroll] for (float j = 0; j < 3; ++j) { @@ -68,9 +173,11 @@ void geom(triangle Attributes input[3], inout TriangleStream stream) stream.RestartStrip(); } } +#endif +//-----------------------------------(above) For Microsoft Shader Model < 4.1----------------------------------- void frag( - Varyings input, + g2f input, out float4 outColor : SV_Target, out float outDepth : SV_Depth) { @@ -81,4 +188,4 @@ void frag( outColor = outDepth = input.vertex.z / input.vertex.w; } -#endif +#endif \ No newline at end of file diff --git a/Assets/Fur/Shaders/Shell/Unlit.hlsl b/Assets/Fur/Shaders/Shell/Unlit.hlsl index b6cd108..aed5ce6 100644 --- a/Assets/Fur/Shaders/Shell/Unlit.hlsl +++ b/Assets/Fur/Shaders/Shell/Unlit.hlsl @@ -11,24 +11,55 @@ struct Attributes float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID }; -struct Varyings +struct v2g +{ + float4 positionOS : POSITION; + float3 normalOS : NORMAL; + float4 tangentOS : TANGENT; + float2 uv : TEXCOORD0; + UNITY_VERTEX_INPUT_INSTANCE_ID +}; + +struct g2f { float4 vertex : SV_POSITION; float2 uv : TEXCOORD0; float fogCoord : TEXCOORD1; float layer : TEXCOORD2; + UNITY_VERTEX_INPUT_INSTANCE_ID + UNITY_VERTEX_OUTPUT_STEREO }; Attributes vert(Attributes input) { - return input; + v2g output = (v2g)0; + // setup the instanced id + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the "v2g output" to 0.0 + // This is the URP version of UNITY_INITIALIZE_OUTPUT() + ZERO_INITIALIZE(v2g, output); + // copy instance id in the "Attributes input" to the "v2g output" + UNITY_TRANSFER_INSTANCE_ID(input, output); + + output.positionOS = input.positionOS; + output.normalOS = input.normalOS; + output.tangentOS = input.tangentOS; + output.uv = input.uv; + return output; } -void AppendShellVertex(inout TriangleStream stream, Attributes input, int index) +void AppendShellVertex(inout TriangleStream stream, v2g input, int index) { - Varyings output = (Varyings)0; + g2f output = (g2f)0; + UNITY_SETUP_INSTANCE_ID(input); + // set all values in the g2f output to 0.0 + ZERO_INITIALIZE(g2f, output); + + UNITY_TRANSFER_INSTANCE_ID(input, output); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); VertexPositionInputs vertexInput = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs normalInput = GetVertexNormalInputs(input.normalOS, input.tangentOS); @@ -59,7 +90,7 @@ void AppendShellVertex(inout TriangleStream stream, Attributes input, } [maxvertexcount(128)] -void geom(triangle Attributes input[3], inout TriangleStream stream) +void geom(triangle v2g input[3], inout TriangleStream stream) { [loop] for (float i = 0; i < _ShellAmount; ++i) { @@ -71,7 +102,7 @@ void geom(triangle Attributes input[3], inout TriangleStream stream) } } -float4 frag(Varyings input) : SV_Target +float4 frag(g2f input) : SV_Target { float4 furColor = SAMPLE_TEXTURE2D(_FurMap, sampler_FurMap, input.uv * _FurScale); float alpha = furColor.r * (1.0 - input.layer); From aa8f24c7cc8f74429e938f4363ec0456299fe717 Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Fri, 29 Apr 2022 04:57:23 +0800 Subject: [PATCH 12/13] =?UTF-8?q?Correct=20=20the=20garbled=20"=E3=81=AE?= =?UTF-8?q?=E3=82=AD=E3=83=BC=E3=83=AF=E3=83=BC=E3=83=89"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Assets/Fur/Shaders/Shell/Lit.shader | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Assets/Fur/Shaders/Shell/Lit.shader b/Assets/Fur/Shaders/Shell/Lit.shader index 43d4699..fe69d94 100644 --- a/Assets/Fur/Shaders/Shell/Lit.shader +++ b/Assets/Fur/Shaders/Shell/Lit.shader @@ -74,7 +74,7 @@ SubShader ZWrite On HLSLPROGRAM - // URP 、ホ・ュゥ`・ゥ`・ノ + // URP 縺ョ繧ュ繝シ繝ッ繝シ繝 #if (UNITY_VERSION >= 202111) #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN #pragma multi_compile_fragment _ _LIGHT_LAYERS @@ -93,7 +93,7 @@ SubShader #pragma multi_compile_fragment _ _FUR_SPECULAR #pragma multi_compile _ _GEOM_INSTANCING - // Unity 、ホ・ュゥ`・ゥ`・ノ + // Unity 縺ョ繧ュ繝シ繝ッ繝シ繝 #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog @@ -187,7 +187,7 @@ SubShader ZWrite On HLSLPROGRAM - // URP 、ホ・ュゥ`・ゥ`・ノ + // URP 縺ョ繧ュ繝シ繝ッ繝シ繝 #if (UNITY_VERSION >= 202111) #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE _MAIN_LIGHT_SHADOWS_SCREEN #pragma multi_compile_fragment _ _LIGHT_LAYERS @@ -205,7 +205,7 @@ SubShader #pragma multi_compile_fragment _ _FUR_SPECULAR - // Unity 、ホ・ュゥ`・ゥ`・ノ + // Unity 縺ョ繧ュ繝シ繝ッ繝シ繝 #pragma multi_compile _ DIRLIGHTMAP_COMBINED #pragma multi_compile _ LIGHTMAP_ON #pragma multi_compile_fog From 935a9abb2586b4519378fb07fbadc948d1474d8b Mon Sep 17 00:00:00 2001 From: jiaozi158 <62869447+jiaozi158@users.noreply.github.com> Date: Mon, 2 May 2022 15:38:26 +0800 Subject: [PATCH 13/13] Correct the comments --- Assets/Fur/Shaders/Shell/Lit.hlsl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Assets/Fur/Shaders/Shell/Lit.hlsl b/Assets/Fur/Shaders/Shell/Lit.hlsl index 779b46a..4981d1b 100644 --- a/Assets/Fur/Shaders/Shell/Lit.hlsl +++ b/Assets/Fur/Shaders/Shell/Lit.hlsl @@ -157,6 +157,7 @@ void AppendShellVertexInstancing(inout TriangleStream stream, v2g input, in // "200 / 13 = 15, remains 5" // // You will need "16" instances, "15" for 195 shells, "1" for 5 remaining shells. +// So, use [instance(15)] to execute "15+1" instances. // // IMPORTANT: if you set [instance(30)] for 200 shells, you will waste performance because // "stream.RestartStrip()" will run on 14 istances (with empty output). @@ -287,4 +288,4 @@ float4 frag(g2f input) : SV_Target return color; } -#endif \ No newline at end of file +#endif