diff --git a/Assets/Shaders/DecalsCommon.cginc b/Assets/Shaders/DecalsCommon.cginc index 81656e5..af39193 100644 --- a/Assets/Shaders/DecalsCommon.cginc +++ b/Assets/Shaders/DecalsCommon.cginc @@ -1,4 +1,6 @@ #ifndef DECALS_COMMON_INCLUDED +// Upgrade NOTE: excluded shader from DX11; has structs without semantics (struct v2f members screenUV) +#pragma exclude_renderers d3d11 #define DECALS_COMMON_INCLUDED #include "AutoLight.cginc" @@ -47,6 +49,12 @@ float4 _Decal_ST; fixed4 _Emissive_Color; #endif //DECAL_EMISSIVE +#ifdef UNITY_PASS_DEFERRED + sampler2D _CameraGBufferTexture0; + sampler2D _CameraGBufferTexture1; + sampler2D _CameraGBufferTexture2; +#endif + // KSP EFFECTS // opacity and color float _Opacity; @@ -104,7 +112,7 @@ struct appdata_decal struct v2f { - UNITY_POSITION(pos); + // UNITY_POSITION(pos); float3 normal : NORMAL; float4 uv_decal : TEXCOORD0; @@ -124,6 +132,10 @@ struct v2f #ifdef UNITY_PASS_FORWARDADD UNITY_LIGHTING_COORDS(5,6) #endif //UNITY_PASS_FORWARDADD + + #ifdef UNITY_PASS_DEFERRED + float4 screenUV : TEXCOORD5; + #endif }; diff --git a/Assets/Shaders/DecalsLighting.cginc b/Assets/Shaders/DecalsLighting.cginc index 38f766e..3d5bcae 100644 --- a/Assets/Shaders/DecalsLighting.cginc +++ b/Assets/Shaders/DecalsLighting.cginc @@ -1,8 +1,11 @@ #ifndef DECALS_LIGHTING_INCLUDED #define DECALS_LIGHTING_INCLUDED +#include "UnityPBSLighting.cginc" +#include "LegacyToStandard.cginc" + // modifed version of the KSP BlinnPhong because it does some weird things -inline fixed4 LightingBlinnPhongDecal(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten) +inline fixed4 LightingBlinnPhongDecal(SurfaceOutputStandardSpecular s, fixed3 lightDir, half3 viewDir, fixed atten) { s.Normal = normalize(s.Normal); half3 h = normalize(lightDir + viewDir); @@ -10,7 +13,7 @@ inline fixed4 LightingBlinnPhongDecal(SurfaceOutput s, fixed3 lightDir, half3 vi fixed diff = max(0, dot(s.Normal, lightDir)); float nh = max(0, dot(s.Normal, h)); - float spec = pow(nh, s.Specular*128.0) * s.Gloss; + float spec = pow(nh, s.Smoothness*128.0) * s.Specular; // specular and smoothness inverted from usual KSP lighting function fixed4 c = 0; c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * _SpecColor.rgb * spec) * (atten); @@ -30,4 +33,39 @@ float4 UnderwaterFog(float3 worldPos, float3 color) return float4(lerp(color, _UnderwaterFogColor.rgb, albedoLerpValue), alphaFactor); } + +inline half4 KSPLightingStandardSpecular_Deferred (SurfaceOutputStandardSpecular s, out half4 outGBuffer0, out half4 outGBuffer1, out half4 outGBuffer2, out half4 outEmission) +{ + GetStandardSpecularPropertiesFromLegacy(s.Smoothness, s.Specular, _SpecColor, s.Smoothness, s.Specular); + + // energy conservation + half oneMinusReflectivity; + s.Albedo = EnergyConservationBetweenDiffuseAndSpecular (s.Albedo, s.Specular, oneMinusReflectivity); + + UnityStandardData data; + data.diffuseColor = s.Albedo; + data.occlusion = s.Occlusion; + data.specularColor = s.Specular; + data.smoothness = s.Smoothness; + data.normalWorld = s.Normal; + + // RT0: diffuse color (rgb), occlusion (a) - sRGB rendertarget + outGBuffer0 = half4(data.diffuseColor, data.occlusion); + + // RT1: spec color (rgb), smoothness (a) - sRGB rendertarget + outGBuffer1 = half4(data.specularColor, data.smoothness); + + // RT2: normal (rgb), --unused, very low precision-- (a) + outGBuffer2 = half4(data.normalWorld * 0.5f + 0.5f, 1.0f); + + outEmission = half4(s.Emission, s.Alpha); + + #ifndef UNITY_HDR_ON + outEmission.rgb = exp2(-outEmission.rgb); + #endif + + return outEmission; +} + + #endif diff --git a/Assets/Shaders/DecalsSurface.cginc b/Assets/Shaders/DecalsSurface.cginc index f1b5c06..30caa66 100644 --- a/Assets/Shaders/DecalsSurface.cginc +++ b/Assets/Shaders/DecalsSurface.cginc @@ -6,14 +6,14 @@ // declare surf function, // this must be defined in any shader using this cginc -void surf (DecalSurfaceInput IN, inout SurfaceOutput o); +void surf (DecalSurfaceInput IN, inout SurfaceOutputStandardSpecular o); -v2f vert_forward(appdata_decal v) +v2f vert(appdata_decal v, out float4 outpos : SV_POSITION) { v2f o; UNITY_INITIALIZE_OUTPUT(v2f,o); - o.pos = UnityObjectToClipPos(v.vertex); + outpos = UnityObjectToClipPos(v.vertex); o.normal = v.normal; #ifdef DECAL_PREVIEW @@ -63,6 +63,14 @@ v2f vert_forward(appdata_decal v) unity_4LightAtten0, worldPosition, worldNormal ); #endif // VERTEXLIGHT_ON #endif // UNITY_PASS_FORWARDBASE + + #ifdef UNITY_PASS_DEFERRED + o.screenUV = v.vertex; + + // Correct flip when rendering with a flipped projection matrix. + // (I've observed this differing between the Unity scene & game views) + o.screenUV.y *= _ProjectionParams.x; + #endif // pass shadow and, possibly, light cookie coordinates to pixel shader UNITY_TRANSFER_LIGHTING(o, 0.0); @@ -70,8 +78,7 @@ v2f vert_forward(appdata_decal v) return o; } -fixed4 frag_forward(v2f IN) : SV_Target -{ +void frag_common(v2f IN, float3 worldPosition, float3 viewDir, out SurfaceOutputStandardSpecular o) { #ifdef DECAL_PREVIEW fixed4 uv_projected = IN.uv_decal; #else @@ -84,22 +91,6 @@ fixed4 frag_forward(v2f IN) : SV_Target // declare data DecalSurfaceInput i; - SurfaceOutput o; - - // setup world-space TBN vectors - UNITY_EXTRACT_TBN(IN); - - float3 worldPosition = float3(IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w); - float3 worldTangent = float3(IN.tSpace0.x, IN.tSpace1.x, IN.tSpace2.x); - - // setup world-space light and view direction vectors - #ifndef USING_DIRECTIONAL_LIGHT - fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPosition)); - #else - fixed3 lightDir = _WorldSpaceLightPos0.xyz; - #endif - float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPosition)); - float3 viewDir = _unity_tbn_0 * worldViewDir.x + _unity_tbn_1 * worldViewDir.y + _unity_tbn_2 * worldViewDir.z; // initialize surface input UNITY_INITIALIZE_OUTPUT(DecalSurfaceInput, i) @@ -135,7 +126,7 @@ fixed4 frag_forward(v2f IN) : SV_Target o.Emission = 0.0; o.Specular = 0.0; o.Alpha = 0.0; - o.Gloss = 0.0; + o.Smoothness = 0.0; o.Normal = fixed3(0,0,1); // call surface function @@ -150,9 +141,30 @@ fixed4 frag_forward(v2f IN) : SV_Target o.Emission = lerp(0, o.Emission, o.Alpha); o.Alpha = _Opacity; #endif //DECAL_PREVIEW +} + +fixed4 frag_forward(v2f IN) : SV_Target +{ + // setup world-space TBN vectors + UNITY_EXTRACT_TBN(IN); + + SurfaceOutputStandardSpecular o; + float3 worldPosition = float3(IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w); + float3 worldTangent = float3(IN.tSpace0.x, IN.tSpace1.x, IN.tSpace2.x); + float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPosition)); + float3 viewDir = _unity_tbn_0 * worldViewDir.x + _unity_tbn_1 * worldViewDir.y + _unity_tbn_2 * worldViewDir.z; + frag_common(IN, worldPosition, viewDir, o); + // compute lighting & shadowing factor UNITY_LIGHT_ATTENUATION(atten, IN, worldPosition) + + // setup world-space light and view direction vectors + #ifndef USING_DIRECTIONAL_LIGHT + fixed3 lightDir = normalize(UnityWorldSpaceLightDir(worldPosition)); + #else + fixed3 lightDir = _WorldSpaceLightPos0.xyz; + #endif // compute world normal float3 WorldNormal; @@ -180,4 +192,48 @@ fixed4 frag_forward(v2f IN) : SV_Target return c; } + +#ifdef UNITY_PASS_DEFERRED +void frag_deferred (v2f IN, + UNITY_VPOS_TYPE uv : VPOS, + out half4 outGBuffer0 : SV_Target0, + out half4 outGBuffer1 : SV_Target1, + out half4 outGBuffer2 : SV_Target2, + out half4 outEmission : SV_Target3 +#if defined(SHADOWS_SHADOWMASK) && (UNITY_ALLOWED_MRT_COUNT > 4) + , out half4 outShadowMask : SV_Target4 +#endif + ) +{ + + // float2 uv = (IN.screenUV.xy / IN.screenUV.w) * 0.5f + 0.5f; + half4 inGBuffer0 = tex2D (_CameraGBufferTexture0, uv); // Diffuse RGB, Occlusion A + half4 inGBuffer1 = tex2D (_CameraGBufferTexture1, uv); // Specular RGB, Smoothness A + half4 inGBuffer2 = tex2D (_CameraGBufferTexture2, uv); // Normal RGB + + // setup world-space TBN vectors + UNITY_EXTRACT_TBN(IN); + + SurfaceOutputStandardSpecular o; + float3 worldPosition = float3(IN.tSpace0.w, IN.tSpace1.w, IN.tSpace2.w); + float3 worldTangent = float3(IN.tSpace0.x, IN.tSpace1.x, IN.tSpace2.x); + float3 worldViewDir = normalize(UnityWorldSpaceViewDir(worldPosition)); + float3 viewDir = _unity_tbn_0 * worldViewDir.x + _unity_tbn_1 * worldViewDir.y + _unity_tbn_2 * worldViewDir.z; + + frag_common(IN, worldPosition, viewDir, o); + + // compute world normal + float3 WorldNormal; + WorldNormal.x = dot(_unity_tbn_0, o.Normal); + WorldNormal.y = dot(_unity_tbn_1, o.Normal); + WorldNormal.z = dot(_unity_tbn_2, o.Normal); + WorldNormal = normalize(WorldNormal); + o.Normal = WorldNormal; + + KSPLightingStandardSpecular_Deferred(o, outGBuffer0, outGBuffer1, outGBuffer2, outEmission); + outGBuffer0 = lerp(inGBuffer0, outGBuffer0, o.Alpha); + outGBuffer1 = lerp(inGBuffer1, outGBuffer1, o.Alpha); + outGBuffer2 = lerp(inGBuffer2, outGBuffer2, o.Alpha); +} +#endif #endif \ No newline at end of file diff --git a/Assets/Shaders/LegacyToStandard.cginc b/Assets/Shaders/LegacyToStandard.cginc new file mode 100644 index 0000000..3a29fe5 --- /dev/null +++ b/Assets/Shaders/LegacyToStandard.cginc @@ -0,0 +1,25 @@ +// Taken from https://github.com/LGhassen/Deferred + +//TODO: remove this debug settings +float blinnPhongShininessPower; + +// An exact conversion from blinn-phong to PBR is impossible, but the look can be approximated perceptually +// and by observing how blinn-phong looks and feels at various settings, although it can never be perfect +// 1) The specularColor can be used as is in the PBR specular flow, just needs to be divided by PI so it sums up to 1 over the hemisphere +// 2) Blinn-phong shininess doesn't stop feeling shiny unless at very low values, like below 0.04 +// while the PBR smoothness feels more linear -> map shininess to smoothness accordingly using a function +// that increases very quickly at first then slows down, I went with something like x^(1/4) or x^(1/6) then made the power configurable +// I tried various mappings from the literature but nothing really worked as well as this +// 3) Finally I noticed that some parts still looked very shiny like the AV-R8 winglet while in stock they looked rough thanks a low +// specularColor but high shininess and specularMap, so I multiplied the smoothness by the sqrt of the specularColor and that caps +// the smoothness when specularColor is low +void GetStandardSpecularPropertiesFromLegacy(float legacyShininess, float specularMap, float3 legacySpecularColor, + out float smoothness, out float3 specular) +{ + legacySpecularColor = saturate(legacySpecularColor); + + smoothness = pow(legacyShininess, blinnPhongShininessPower) * specularMap; + smoothness *= sqrt(length(legacySpecularColor)); + + specular = legacySpecularColor * (1 / UNITY_PI); +} \ No newline at end of file diff --git a/Assets/Shaders/StandardDecal.cginc b/Assets/Shaders/StandardDecal.cginc index 2b8ac7b..7c492f6 100644 --- a/Assets/Shaders/StandardDecal.cginc +++ b/Assets/Shaders/StandardDecal.cginc @@ -1,7 +1,8 @@ -void surf(DecalSurfaceInput IN, inout SurfaceOutput o) { +void surf(DecalSurfaceInput IN, inout SurfaceOutputStandardSpecular o) { float4 color = tex2D(_Decal, IN.uv_decal); o.Albedo = UnderwaterFog(IN.worldPosition, color).rgb; o.Alpha = _DecalOpacity; + o.Occlusion = 1; #ifdef DECAL_BASE_NORMAL float3 normal = IN.normal; @@ -16,8 +17,8 @@ void surf(DecalSurfaceInput IN, inout SurfaceOutput o) { #ifdef DECAL_SPECMAP float4 specular = tex2D(_SpecMap, IN.uv_specmap); - o.Gloss = specular.r; - o.Specular = _Shininess; + o.Smoothness = _Shininess; + o.Specular = specular #endif half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal)); diff --git a/Assets/Shaders/StandardDecal.shader b/Assets/Shaders/StandardDecal.shader index 95c32ae..dac4268 100644 --- a/Assets/Shaders/StandardDecal.shader +++ b/Assets/Shaders/StandardDecal.shader @@ -55,7 +55,7 @@ Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM - #pragma vertex vert_forward + #pragma vertex vert #pragma fragment frag_forward #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap @@ -85,7 +85,7 @@ Offset -1, -1 CGPROGRAM - #pragma vertex vert_forward + #pragma vertex vert #pragma fragment frag_forward #pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap @@ -102,6 +102,37 @@ #include "SDF.cginc" #include "StandardDecal.cginc" + ENDCG + } + + Pass + { + Name "DEFERRED" + Tags { "LightMode" = "Deferred" } + ZWrite Off + ZTest LEqual + Blend SrcAlpha One + Offset -1, -1 + + CGPROGRAM + #pragma vertex vert + #pragma fragment frag_deferred + #pragma target 3.0 + + #pragma multi_compile_deferred nolightmap nodirlightmap nodynlightmap + #pragma skip_variants SHADOWS_DEPTH SHADOWS_CUBE SHADOWS_SHADOWMASK LIGHTMAP_SHADOW_MIXING POINT_COOKIE + #pragma multi_compile_local __ DECAL_PREVIEW + #pragma multi_compile_local __ DECAL_BASE_NORMAL DECAL_BUMPMAP + #pragma multi_compile_local __ DECAL_SPECMAP + #pragma multi_compile_local __ DECAL_EMISSIVE + #pragma multi_compile_local __ DECAL_SDF_ALPHA + + #include "UnityCG.cginc" + #include "DecalsCommon.cginc" + #include "DecalsSurface.cginc" + #include "SDF.cginc" + #include "StandardDecal.cginc" + ENDCG } } diff --git a/Assets/Shaders/TextDecal.cginc b/Assets/Shaders/TextDecal.cginc index f8d6e6d..0088d59 100644 --- a/Assets/Shaders/TextDecal.cginc +++ b/Assets/Shaders/TextDecal.cginc @@ -3,9 +3,10 @@ float4 _DecalColor; float4 _OutlineColor; float _OutlineWidth; -void surf(DecalSurfaceInput IN, inout SurfaceOutput o) { +void surf(DecalSurfaceInput IN, inout SurfaceOutputStandardSpecular o) { float4 color = _DecalColor; float dist = _Cutoff - tex2D(_Decal, IN.uv_decal).r; // text distance + o.Occlusion = 1; #ifdef DECAL_OUTLINE // Outline @@ -40,8 +41,8 @@ void surf(DecalSurfaceInput IN, inout SurfaceOutput o) { #ifdef DECAL_SPECMAP float4 specular = tex2D(_SpecMap, IN.uv_specmap); - o.Gloss = specular.r; - o.Specular = _Shininess; + o.Smoothness = _Shininess; + o.Specular = specular; #endif half rim = 1.0 - saturate(dot(normalize(IN.viewDir), o.Normal)); diff --git a/Assets/Shaders/TextDecal.shader b/Assets/Shaders/TextDecal.shader index 4cccf5e..40aeda2 100644 --- a/Assets/Shaders/TextDecal.shader +++ b/Assets/Shaders/TextDecal.shader @@ -56,7 +56,7 @@ Blend SrcAlpha OneMinusSrcAlpha CGPROGRAM - #pragma vertex vert_forward + #pragma vertex vert #pragma fragment frag_forward #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap @@ -86,7 +86,7 @@ Offset -1, -1 CGPROGRAM - #pragma vertex vert_forward + #pragma vertex vert #pragma fragment frag_forward #pragma multi_compile_fwdadd nolightmap nodirlightmap nodynlightmap