Brak opisu
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UnityGBuffer.hlsl 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. #ifndef UNIVERSAL_GBUFFERUTIL_INCLUDED
  2. #define UNIVERSAL_GBUFFERUTIL_INCLUDED
  3. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/SurfaceData.hlsl"
  4. #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
  5. // inspired from [builtin_shaders]/CGIncludes/UnityGBuffer.cginc
  6. // Non-static meshes with real-time lighting need to write shadow mask, which in that case stores per-object occlusion probe values.
  7. #if !defined(LIGHTMAP_ON) && defined(LIGHTMAP_SHADOW_MIXING) && !defined(SHADOWS_SHADOWMASK)
  8. #define OUTPUT_SHADOWMASK 1 // subtractive
  9. #elif defined(SHADOWS_SHADOWMASK)
  10. #define OUTPUT_SHADOWMASK 2 // shadow mask
  11. #elif defined(_DEFERRED_MIXED_LIGHTING)
  12. #define OUTPUT_SHADOWMASK 3 // we don't know if it's subtractive or just shadowMap (from deferred lighting shader, LIGHTMAP_ON does not need to be defined)
  13. #else
  14. #endif
  15. #if _RENDER_PASS_ENABLED
  16. #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
  17. #define GBUFFER_OPTIONAL_SLOT_1_TYPE float
  18. #if OUTPUT_SHADOWMASK && (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
  19. #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
  20. #define GBUFFER_OPTIONAL_SLOT_3 GBuffer6
  21. #define GBUFFER_LIGHT_LAYERS GBuffer5
  22. #define GBUFFER_SHADOWMASK GBuffer6
  23. #elif OUTPUT_SHADOWMASK
  24. #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
  25. #define GBUFFER_SHADOWMASK GBuffer5
  26. #elif (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
  27. #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
  28. #define GBUFFER_LIGHT_LAYERS GBuffer5
  29. #endif //#if OUTPUT_SHADOWMASK && defined(_WRITE_RENDERING_LAYERS)
  30. #else
  31. #define GBUFFER_OPTIONAL_SLOT_1_TYPE half4
  32. #if OUTPUT_SHADOWMASK && (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
  33. #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
  34. #define GBUFFER_OPTIONAL_SLOT_2 GBuffer5
  35. #define GBUFFER_LIGHT_LAYERS GBuffer4
  36. #define GBUFFER_SHADOWMASK GBuffer5
  37. #elif OUTPUT_SHADOWMASK
  38. #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
  39. #define GBUFFER_SHADOWMASK GBuffer4
  40. #elif (defined(_WRITE_RENDERING_LAYERS) || defined(_LIGHT_LAYERS))
  41. #define GBUFFER_OPTIONAL_SLOT_1 GBuffer4
  42. #define GBUFFER_LIGHT_LAYERS GBuffer4
  43. #endif //#if OUTPUT_SHADOWMASK && defined(_WRITE_RENDERING_LAYERS)
  44. #endif //#if _RENDER_PASS_ENABLED
  45. #define kLightingInvalid -1 // No dynamic lighting: can aliase any other material type as they are skipped using stencil
  46. #define kLightingLit 1 // lit shader
  47. #define kLightingSimpleLit 2 // Simple lit shader
  48. // clearcoat 3
  49. // backscatter 4
  50. // skin 5
  51. // Material flags
  52. #define kMaterialFlagReceiveShadowsOff 1 // Does not receive dynamic shadows
  53. #define kMaterialFlagSpecularHighlightsOff 2 // Does not receivce specular
  54. #define kMaterialFlagSubtractiveMixedLighting 4 // The geometry uses subtractive mixed lighting
  55. #define kMaterialFlagSpecularSetup 8 // Lit material use specular setup instead of metallic setup
  56. // Light flags.
  57. #define kLightFlagSubtractiveMixedLighting 4 // The light uses subtractive mixed lighting.
  58. struct FragmentOutput
  59. {
  60. half4 GBuffer0 : SV_Target0;
  61. half4 GBuffer1 : SV_Target1;
  62. half4 GBuffer2 : SV_Target2;
  63. half4 GBuffer3 : SV_Target3; // Camera color attachment
  64. #ifdef GBUFFER_OPTIONAL_SLOT_1
  65. GBUFFER_OPTIONAL_SLOT_1_TYPE GBuffer4 : SV_Target4;
  66. #endif
  67. #ifdef GBUFFER_OPTIONAL_SLOT_2
  68. half4 GBuffer5 : SV_Target5;
  69. #endif
  70. #ifdef GBUFFER_OPTIONAL_SLOT_3
  71. half4 GBuffer6 : SV_Target6;
  72. #endif
  73. };
  74. float PackMaterialFlags(uint materialFlags)
  75. {
  76. return materialFlags * (1.0h / 255.0h);
  77. }
  78. uint UnpackMaterialFlags(float packedMaterialFlags)
  79. {
  80. return uint((packedMaterialFlags * 255.0h) + 0.5h);
  81. }
  82. #ifdef _GBUFFER_NORMALS_OCT
  83. half3 PackNormal(half3 n)
  84. {
  85. float2 octNormalWS = PackNormalOctQuadEncode(n); // values between [-1, +1], must use fp32 on some platforms.
  86. float2 remappedOctNormalWS = saturate(octNormalWS * 0.5 + 0.5); // values between [ 0, +1]
  87. return half3(PackFloat2To888(remappedOctNormalWS)); // values between [ 0, +1]
  88. }
  89. half3 UnpackNormal(half3 pn)
  90. {
  91. half2 remappedOctNormalWS = half2(Unpack888ToFloat2(pn)); // values between [ 0, +1]
  92. half2 octNormalWS = remappedOctNormalWS.xy * half(2.0) - half(1.0);// values between [-1, +1]
  93. return half3(UnpackNormalOctQuadEncode(octNormalWS)); // values between [-1, +1]
  94. }
  95. #else
  96. half3 PackNormal(half3 n)
  97. { return n; } // values between [-1, +1]
  98. half3 UnpackNormal(half3 pn)
  99. { return pn; } // values between [-1, +1]
  100. #endif
  101. // This will encode SurfaceData into GBuffer
  102. FragmentOutput SurfaceDataToGbuffer(SurfaceData surfaceData, InputData inputData, half3 globalIllumination, int lightingMode)
  103. {
  104. half3 packedNormalWS = PackNormal(inputData.normalWS);
  105. uint materialFlags = 0;
  106. // SimpleLit does not use _SPECULARHIGHLIGHTS_OFF to disable specular highlights.
  107. #ifdef _RECEIVE_SHADOWS_OFF
  108. materialFlags |= kMaterialFlagReceiveShadowsOff;
  109. #endif
  110. #if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
  111. materialFlags |= kMaterialFlagSubtractiveMixedLighting;
  112. #endif
  113. FragmentOutput output;
  114. output.GBuffer0 = half4(surfaceData.albedo.rgb, PackMaterialFlags(materialFlags)); // albedo albedo albedo materialFlags (sRGB rendertarget)
  115. output.GBuffer1 = half4(surfaceData.specular.rgb, surfaceData.occlusion); // specular specular specular occlusion
  116. output.GBuffer2 = half4(packedNormalWS, surfaceData.smoothness); // encoded-normal encoded-normal encoded-normal smoothness
  117. output.GBuffer3 = half4(globalIllumination, 1); // GI GI GI unused (lighting buffer)
  118. #if _RENDER_PASS_ENABLED
  119. output.GBuffer4 = inputData.positionCS.z;
  120. #endif
  121. #if OUTPUT_SHADOWMASK
  122. output.GBUFFER_SHADOWMASK = inputData.shadowMask; // will have unity_ProbesOcclusion value if subtractive lighting is used (baked)
  123. #endif
  124. #ifdef _WRITE_RENDERING_LAYERS
  125. uint renderingLayers = GetMeshRenderingLayer();
  126. output.GBUFFER_LIGHT_LAYERS = float4(EncodeMeshRenderingLayer(renderingLayers), 0.0, 0.0, 0.0);
  127. #endif
  128. return output;
  129. }
  130. // This decodes the Gbuffer into a SurfaceData struct
  131. SurfaceData SurfaceDataFromGbuffer(half4 gbuffer0, half4 gbuffer1, half4 gbuffer2, int lightingMode)
  132. {
  133. SurfaceData surfaceData;
  134. surfaceData.albedo = gbuffer0.rgb;
  135. uint materialFlags = UnpackMaterialFlags(gbuffer0.a);
  136. surfaceData.occlusion = 1.0; // Not used by SimpleLit material.
  137. surfaceData.specular = gbuffer1.rgb;
  138. half smoothness = gbuffer2.a;
  139. surfaceData.metallic = 0.0; // Not used by SimpleLit material.
  140. surfaceData.alpha = 1.0; // gbuffer only contains opaque materials
  141. surfaceData.smoothness = smoothness;
  142. surfaceData.emission = (half3)0; // Note: this is not made available at lighting pass in this renderer - emission contribution is included (with GI) in the value GBuffer3.rgb, that is used as a renderTarget during lighting
  143. surfaceData.normalTS = (half3)0; // Note: does this normalTS member need to be in SurfaceData? It looks like an intermediate value
  144. return surfaceData;
  145. }
  146. // This will encode SurfaceData into GBuffer
  147. FragmentOutput BRDFDataToGbuffer(BRDFData brdfData, InputData inputData, half smoothness, half3 globalIllumination, half occlusion = 1.0)
  148. {
  149. half3 packedNormalWS = PackNormal(inputData.normalWS);
  150. uint materialFlags = 0;
  151. #ifdef _RECEIVE_SHADOWS_OFF
  152. materialFlags |= kMaterialFlagReceiveShadowsOff;
  153. #endif
  154. half3 packedSpecular;
  155. #ifdef _SPECULAR_SETUP
  156. materialFlags |= kMaterialFlagSpecularSetup;
  157. packedSpecular = brdfData.specular.rgb;
  158. #else
  159. packedSpecular.r = brdfData.reflectivity;
  160. packedSpecular.gb = 0.0;
  161. #endif
  162. #ifdef _SPECULARHIGHLIGHTS_OFF
  163. // During the next deferred shading pass, we don't use a shader variant to disable specular calculations.
  164. // Instead, we can either silence specular contribution when writing the gbuffer, and/or reserve a bit in the gbuffer
  165. // and use this during shading to skip computations via dynamic branching. Fastest option depends on platforms.
  166. materialFlags |= kMaterialFlagSpecularHighlightsOff;
  167. packedSpecular = 0.0.xxx;
  168. #endif
  169. #if defined(LIGHTMAP_ON) && defined(_MIXED_LIGHTING_SUBTRACTIVE)
  170. materialFlags |= kMaterialFlagSubtractiveMixedLighting;
  171. #endif
  172. FragmentOutput output;
  173. output.GBuffer0 = half4(brdfData.albedo.rgb, PackMaterialFlags(materialFlags)); // diffuse diffuse diffuse materialFlags (sRGB rendertarget)
  174. output.GBuffer1 = half4(packedSpecular, occlusion); // metallic/specular specular specular occlusion
  175. output.GBuffer2 = half4(packedNormalWS, smoothness); // encoded-normal encoded-normal encoded-normal smoothness
  176. output.GBuffer3 = half4(globalIllumination, 1); // GI GI GI unused (lighting buffer)
  177. #if _RENDER_PASS_ENABLED
  178. output.GBuffer4 = inputData.positionCS.z;
  179. #endif
  180. #if OUTPUT_SHADOWMASK
  181. output.GBUFFER_SHADOWMASK = inputData.shadowMask; // will have unity_ProbesOcclusion value if subtractive lighting is used (baked)
  182. #endif
  183. #ifdef _WRITE_RENDERING_LAYERS
  184. uint renderingLayers = GetMeshRenderingLayer();
  185. output.GBUFFER_LIGHT_LAYERS = float4(EncodeMeshRenderingLayer(renderingLayers), 0.0, 0.0, 0.0);
  186. #endif
  187. return output;
  188. }
  189. // This decodes the Gbuffer into a SurfaceData struct
  190. BRDFData BRDFDataFromGbuffer(half4 gbuffer0, half4 gbuffer1, half4 gbuffer2)
  191. {
  192. half3 albedo = gbuffer0.rgb;
  193. half3 specular = gbuffer1.rgb;
  194. uint materialFlags = UnpackMaterialFlags(gbuffer0.a);
  195. half smoothness = gbuffer2.a;
  196. BRDFData brdfData = (BRDFData)0;
  197. half alpha = half(1.0); // NOTE: alpha can get modfied, forward writes it out (_ALPHAPREMULTIPLY_ON).
  198. half3 brdfDiffuse;
  199. half3 brdfSpecular;
  200. half reflectivity;
  201. half oneMinusReflectivity;
  202. if ((materialFlags & kMaterialFlagSpecularSetup) != 0)
  203. {
  204. // Specular setup
  205. reflectivity = ReflectivitySpecular(specular);
  206. oneMinusReflectivity = half(1.0) - reflectivity;
  207. brdfDiffuse = albedo * oneMinusReflectivity;
  208. brdfSpecular = specular;
  209. }
  210. else
  211. {
  212. // Metallic setup
  213. reflectivity = specular.r;
  214. oneMinusReflectivity = 1.0 - reflectivity;
  215. half metallic = MetallicFromReflectivity(reflectivity);
  216. brdfDiffuse = albedo * oneMinusReflectivity;
  217. brdfSpecular = lerp(kDielectricSpec.rgb, albedo, metallic);
  218. }
  219. InitializeBRDFDataDirect(albedo, brdfDiffuse, brdfSpecular, reflectivity, oneMinusReflectivity, smoothness, alpha, brdfData);
  220. return brdfData;
  221. }
  222. InputData InputDataFromGbufferAndWorldPosition(half4 gbuffer2, float3 wsPos)
  223. {
  224. InputData inputData = (InputData)0;
  225. inputData.positionWS = wsPos;
  226. inputData.normalWS = normalize(UnpackNormal(gbuffer2.xyz)); // normalize() is required because terrain shaders use additive blending for normals (not unit-length anymore)
  227. inputData.viewDirectionWS = GetWorldSpaceNormalizeViewDir(wsPos.xyz);
  228. // TODO: pass this info?
  229. inputData.shadowCoord = (float4)0;
  230. inputData.fogCoord = (half )0;
  231. inputData.vertexLighting = (half3 )0;
  232. inputData.bakedGI = (half3)0; // Note: this is not made available at lighting pass in this renderer - bakedGI contribution is included (with emission) in the value GBuffer3.rgb, that is used as a renderTarget during lighting
  233. return inputData;
  234. }
  235. #endif // UNIVERSAL_GBUFFERUTIL_INCLUDED