HairRenderingResolvePPLL.azsl 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * Modifications Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. //---------------------------------------------------------------------------------------
  9. // Shader code related to per-pixel linked lists.
  10. //-------------------------------------------------------------------------------------
  11. //
  12. // Copyright (c) 2019 Advanced Micro Devices, Inc. All rights reserved.
  13. //
  14. // Permission is hereby granted, free of charge, to any person obtaining a copy
  15. // of this software and associated documentation files (the "Software"), to deal
  16. // in the Software without restriction, including without limitation the rights
  17. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  18. // copies of the Software, and to permit persons to whom the Software is
  19. // furnished to do so, subject to the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be included in
  22. // all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  25. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  26. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  27. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  28. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  29. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  30. // THE SOFTWARE.
  31. //
  32. //==============================================================================
  33. #include <Atom/Features/SrgSemantics.azsli>
  34. #include <HairRenderingSrgs.azsli>
  35. #define AMD_TRESSFX_MAX_HAIR_GROUP_RENDER 16
  36. //!------------------------------ SRG Structure --------------------------------
  37. //! Per pass SRG that holds the dynamic shared read-write buffer shared
  38. //! across all dispatches and draw calls. It is used for all the dynamic buffers
  39. //! that can change between passes due to the application of skinning, simulation
  40. //! and physics affect.
  41. //! Once the compute pases are done, it is read by the rendering shaders.
  42. ShaderResourceGroup PassSrg : SRG_PerPass_WithFallback
  43. {
  44. //! Per Pixel Linked List data used by the render raster pass to generate per pixel
  45. //! hair OIT data and shade it in the full screen resolve pass.
  46. //! Originally used space3 for raster pass linked lists and space0 for the resolve pass.
  47. Texture2D<uint> m_fragmentListHead;
  48. StructuredBuffer<PPLL_STRUCT> m_linkedListNodes;
  49. //! Per hair object material array used by the PPLL resolve pass
  50. //! Originally in TressFXRendering.hlsl this is space 0
  51. HairObjectShadeParams m_hairParams[AMD_TRESSFX_MAX_HAIR_GROUP_RENDER];
  52. // Used as the base color to blend with the furthest hair strand - it is the first
  53. // in the OIT process.
  54. // It can also be used to avoid the HW blend done at the end of the pixel
  55. // shader stage but HW blend might be cheaper than additional PS blend.
  56. Texture2D<float4> m_frameBuffer; // The merged non-MSAA input
  57. // Linear depth is used for getting the screen to world transform
  58. Texture2D<float> m_linearDepth;
  59. //------------------------------
  60. // Lighting Data
  61. //------------------------------
  62. Sampler LinearSampler
  63. { // Required by LightingData.azsli
  64. MinFilter = Linear;
  65. MagFilter = Linear;
  66. MipFilter = Linear;
  67. AddressU = Clamp;
  68. AddressV = Clamp;
  69. AddressW = Clamp;
  70. };
  71. Sampler PointSampler
  72. { // Required by LightingData.azsli
  73. MinFilter = Point;
  74. MagFilter = Point;
  75. MipFilter = Point;
  76. AddressU = Clamp;
  77. AddressV = Clamp;
  78. AddressW = Clamp;
  79. };
  80. Texture2DArray<float> m_directionalLightShadowmap;
  81. Texture2DArray<float> m_directionalLightExponentialShadowmap;
  82. Texture2DArray<float> m_projectedShadowmaps;
  83. Texture2DArray<float> m_projectedExponentialShadowmap;
  84. Texture2D m_brdfMap;
  85. Texture2D<uint4> m_tileLightData;
  86. StructuredBuffer<uint> m_lightListRemapped;
  87. Texture2D<float> m_fullscreenShadow;
  88. }
  89. //------------------------------------------------------------------------------
  90. // Originally defined for the TressFX resolve pass at space0
  91. #define FragmentListHead PassSrg::m_fragmentListHead
  92. #define LinkedListNodes PassSrg::m_linkedListNodes
  93. //! The hair objects' material array buffer used by the rendering resolve pass
  94. #define HairParams PassSrg::m_hairParams
  95. //==============================================================================
  96. #include <HairFullScreenUtils.azsli> // provides the Vertex Shader
  97. #include <HairLighting.azsli>
  98. //////////////////////////////////////////////////////////////
  99. // Bind data for PPLLResolvePS
  100. #define NODE_DATA(x) LinkedListNodes[x].data
  101. #define NODE_NEXT(x) LinkedListNodes[x].uNext
  102. #define NODE_DEPTH(x) LinkedListNodes[x].depth
  103. #define NODE_COLOR(x) LinkedListNodes[x].color
  104. #define GET_DEPTH_AT_INDEX(uIndex) kBuffer[uIndex].x
  105. #define GET_DATA_AT_INDEX(uIndex) kBuffer[uIndex].y
  106. #define GET_COLOR_AT_INDEX(uIndex) kBuffer[uIndex].z
  107. #define STORE_DEPTH_AT_INDEX(uIndex, uValue) kBuffer[uIndex].x = uValue
  108. #define STORE_DATA_AT_INDEX( uIndex, uValue) kBuffer[uIndex].y = uValue
  109. #define STORE_COLOR_AT_INDEX( uIndex, uValue ) kBuffer[uIndex].z = uValue
  110. float GetLinearDepth(float zDepth)
  111. {
  112. return abs(((ViewSrg::GetFarZTimesNearZ()) / (ViewSrg::GetFarZMinusNearZ() * zDepth - ViewSrg::GetFarZ())));
  113. }
  114. float4 GatherLinkedList(float2 vfScreenAddress, float2 screenUV, inout float outDepth )
  115. {
  116. uint2 vScreenAddress = uint2(vfScreenAddress);
  117. uint pointer = FragmentListHead[vScreenAddress];
  118. if (pointer == FRAGMENT_LIST_NULL) // [To Do] Skips the very first hair if reset value is 0
  119. {
  120. discard;
  121. }
  122. uint4 kBuffer[KBUFFER_SIZE];
  123. // Init kbuffer to far depth values (reverse depth - 0 is the furthest)
  124. [unroll]
  125. for (int t = 0; t < KBUFFER_SIZE; ++t)
  126. {
  127. STORE_DEPTH_AT_INDEX(t, asuint(0.0));
  128. STORE_DATA_AT_INDEX(t, 0);
  129. }
  130. // Get first K elements from the top (top to bottom)
  131. // And store them in the kbuffer for later
  132. for (int p = 0; p < KBUFFER_SIZE; ++p)
  133. {
  134. if (pointer != FRAGMENT_LIST_NULL)
  135. {
  136. STORE_DEPTH_AT_INDEX(p, NODE_DEPTH(pointer));
  137. STORE_DATA_AT_INDEX(p, NODE_DATA(pointer));
  138. STORE_COLOR_AT_INDEX(p, NODE_COLOR(pointer));
  139. pointer = NODE_NEXT(pointer);
  140. }
  141. }
  142. // float4 fcolor = float4(1, 1, 1, 1); // Blend alpha and inverse alpha
  143. // float4 fcolor = float4(1, 1, 1, 0); // Blend one and inverse alpha
  144. // The very first color taken is the background render target pixel color.
  145. // Alpha should be 1 for Alpha blend alpha and 0 for alpha One, depending on your
  146. // alpha blending method of choice
  147. // When using the render target as the input, alpha blending mode should be disabled!
  148. float4 backgroundColor = float4(PassSrg::m_frameBuffer.Sample(PassSrg::LinearSampler, screenUV).xyz, 0); // Blend one and inverse alpha
  149. float4 fcolor = backgroundColor;
  150. float backgroundLinearDepth = PassSrg::m_linearDepth.Sample(PassSrg::LinearSampler, screenUV).x;
  151. float previousLinearDepth = backgroundLinearDepth;
  152. // Go through the remaining layers of hair
  153. [allow_uav_condition]
  154. for (int iFragment = 0; iFragment < MAX_FRAGMENTS && pointer != FRAGMENT_LIST_NULL ; ++iFragment)
  155. {
  156. int id = 0;
  157. float minDepth = 1.0;
  158. // Find the current furthest sample in the KBuffer
  159. for (int i = 0; i < KBUFFER_SIZE; i++)
  160. {
  161. float fDepth = asfloat(GET_DEPTH_AT_INDEX(i));
  162. if (minDepth > fDepth)
  163. {
  164. minDepth = fDepth;
  165. id = i;
  166. }
  167. }
  168. // Fetch the node data
  169. uint data = NODE_DATA(pointer);
  170. uint color = NODE_COLOR(pointer);
  171. uint nodeDepth = NODE_DEPTH(pointer);
  172. float fNodeDepth = asfloat(nodeDepth);
  173. // If the node in the linked list is nearer than the furthest one in the local array, exchange the node
  174. // in the local array for the one in the linked list.
  175. if (minDepth < fNodeDepth)
  176. {
  177. uint tmp = GET_DEPTH_AT_INDEX(id);
  178. STORE_DEPTH_AT_INDEX(id, nodeDepth);
  179. fNodeDepth = asfloat(tmp);
  180. tmp = GET_DATA_AT_INDEX(id);
  181. STORE_DATA_AT_INDEX(id, data);
  182. data = tmp;
  183. tmp = GET_COLOR_AT_INDEX(id);
  184. STORE_COLOR_AT_INDEX(id, color);
  185. color = tmp;
  186. }
  187. // Calculate color contribution from whatever sample we are using
  188. float4 vData = UnpackUintIntoFloat4(data);
  189. float alpha = vData.w;
  190. uint shadeParamIndex; // So we know what settings to shade with
  191. float3 fragmentColor = UnpackUintIntoFloat3Byte(color, shadeParamIndex);
  192. // Cheap back layers - the bottom hair layers use background and scalp base color
  193. // The first layer blends the image buffer and the rest of the hairs are blended
  194. // on top.
  195. // These layer also used as the blocking factor for the TT lobe in the Marschner
  196. // lighting model by accumulating the depth.
  197. fcolor.xyz = fcolor.xyz * (1.f - alpha) + fragmentColor * alpha;
  198. fcolor.w += alpha * (1.0f - fcolor.w);
  199. pointer = NODE_NEXT(pointer);
  200. }
  201. // Make sure we are blending the correct number of strands (don't blend more than we have)
  202. float maxAlpha = 0;
  203. float minDepth = 1.0; // furthest fragment in Atom
  204. const float closeRangeTH = 0.01f; // Lying on the skin - block lights from the back
  205. const float gapRangeTH = 0.05f; // Far enough from the previous hair - allow for TT lobe to pass
  206. bool isCloseToObject = false;
  207. // Blend the top-most entries
  208. for (int j = 0; j < KBUFFER_SIZE; j++)
  209. {
  210. int id = 0;
  211. minDepth = 1.0;
  212. // find the furthest node in the array
  213. for (int i = 0; i < KBUFFER_SIZE; i++)
  214. {
  215. float fDepth = asfloat(GET_DEPTH_AT_INDEX(i));
  216. if (minDepth > fDepth)
  217. {
  218. minDepth = fDepth;
  219. id = i;
  220. }
  221. }
  222. // take this node out of the next search
  223. uint nodeDepth = GET_DEPTH_AT_INDEX(id);
  224. uint data = GET_DATA_AT_INDEX(id);
  225. uint color = GET_COLOR_AT_INDEX(id);
  226. // take this node out of the next search
  227. STORE_DEPTH_AT_INDEX(id, asuint(1.0));
  228. // Use high quality shading for the nearest k fragments
  229. float fDepth = asfloat(nodeDepth);
  230. float currentLinearDepth = GetLinearDepth(fDepth);
  231. // Light should not pass through hair if the back of the hair is too close to the
  232. // background object. In this case mark the hair as thick to prevent TT lobe from
  233. // transmitting light and cancel light accumulation passed so far.
  234. bool currentIsCloseToObject = (backgroundLinearDepth - currentLinearDepth < closeRangeTH) ? true : false;
  235. if (!isCloseToObject && currentIsCloseToObject)
  236. { // Indicate that the object behind is very close - need to preven any light passage.
  237. // Food for Thought: should the color be reset to background color / other?
  238. isCloseToObject = true; // TT should be blocked
  239. // fcolor.xyz = backgroundColor; // remove the accumulated lighting so far
  240. fcolor.w = 1.0; // Mark hair as thick / blocked from behind.
  241. }
  242. // When the front hair strands are separated from the back, hence creating a large
  243. // gap we should only count for the front hair group thickness (restart counting).
  244. bool hairHasGap = (previousLinearDepth - currentLinearDepth > gapRangeTH) ? true : false;
  245. if (!currentIsCloseToObject && hairHasGap)
  246. { // These is a gap to the previous strands group - restard depth blocking
  247. fcolor.w = 0.0f; // Reset the hair thickness - large gap.
  248. }
  249. previousLinearDepth = currentLinearDepth;
  250. float4 vData = UnpackUintIntoFloat4(data);
  251. float3 vTangent = vData.xyz;
  252. float alpha = vData.w; // Alpha will be used to determine light pass
  253. uint shadeParamIndex; // So we know what settings to shade with
  254. float3 vColor = UnpackUintIntoFloat3Byte(color, shadeParamIndex);
  255. float3 fragmentColor = TressFXShadingFullScreen(vfScreenAddress, fDepth, vTangent, vColor, fcolor.w, shadeParamIndex);
  256. // Blend in the fragment color
  257. fcolor.xyz = fcolor.xyz * (1.f - alpha) + fragmentColor * alpha;
  258. // No HW alpha blending - the first layer blends the image buffer and
  259. // the rest of the hairs are blended on top. However, this might be used
  260. // as the blocking factor for the TT lobe in the Marschner lighting model
  261. // to gradually block light passing through the hair strands from the back.
  262. fcolor.w += alpha * (1.0f - fcolor.w);
  263. }
  264. outDepth = minDepth; // Output closest hair depth
  265. return fcolor;
  266. }
  267. //!-----------------------------------------------------------------------------
  268. //! This method is a testing method for displaying only the closest hair
  269. //! strand for getting a clear method for testing the lighting elelments, the
  270. //! depth and the blending of a single hair strand.
  271. //!-----------------------------------------------------------------------------
  272. float4 GetClosestFragment(float2 vfScreenAddress, float2 screenUV, inout float closestDepth)
  273. {
  274. uint2 vScreenAddress = uint2(vfScreenAddress);
  275. uint pointer = FragmentListHead[vScreenAddress];
  276. if (pointer == FRAGMENT_LIST_NULL)
  277. {
  278. discard;
  279. }
  280. float4 fcolor = float4(PassSrg::m_frameBuffer.Sample(PassSrg::LinearSampler, screenUV).xyz, 0); // Blend one and inverse alpha
  281. float maxDepth = -999.0f;
  282. float minDepth = 999.0f;
  283. uint curColor, curData;
  284. for ( ; (pointer!=FRAGMENT_LIST_NULL) ; )
  285. {
  286. float depth = asfloat(NODE_DEPTH(pointer));
  287. if (depth > maxDepth)
  288. {
  289. maxDepth = depth;
  290. curColor = NODE_COLOR(pointer);
  291. curData = NODE_DATA(pointer);
  292. }
  293. if (depth < minDepth)
  294. {
  295. minDepth = depth;
  296. }
  297. pointer = NODE_NEXT(pointer);
  298. }
  299. float curDepth = closestDepth = maxDepth;
  300. float4 vData = UnpackUintIntoFloat4(curData);
  301. float3 vTangent = vData.xyz;
  302. float alpha = 1.0;
  303. uint shadeParamIndex; // the material index
  304. float3 vColor = UnpackUintIntoFloat3Byte(curColor, shadeParamIndex);
  305. float3 fragmentColor = TressFXShadingFullScreen(vfScreenAddress, curDepth, vTangent, vColor, fcolor.w, shadeParamIndex);
  306. // Blend in the fragment color
  307. fcolor.xyz = fcolor.xyz * (1.f - alpha) + (fragmentColor * alpha);
  308. fcolor.w = saturate(fcolor.w + alpha); // Blend alpha and inverse alpha
  309. /*--------------------
  310. // Depth Testing - this block will draw [closets hair depth, furthest hair depth, background depth]
  311. float backgroundLinearDepth = PassSrg::m_linearDepth.Sample(PassSrg::LinearSampler, screenUV).x;
  312. float minLinearDepth = GetLinearDepth(minDepth);
  313. float maxLinearDepth = GetLinearDepth(maxDepth);
  314. fcolor = float4( minLinearDepth * 0.1f, maxLinearDepth * 0.1f, backgroundLinearDepth * 0.1f, 1.0f);
  315. //------------------- */
  316. return fcolor;
  317. }
  318. struct PSColorDepthOutput
  319. {
  320. float4 m_color : SV_Target;
  321. float m_depth : SV_Depth;
  322. };
  323. // The resolve will combine the base color driven by the further fragments while
  324. // the actual shading will be combined on top based on the shaded closest fragments.
  325. // The closest depth will be returned and written in the depth buffer.
  326. PSColorDepthOutput PPLLResolvePS(VSOutput input)
  327. {
  328. PSColorDepthOutput pixOut;
  329. // GetClosestFragment is a refernece method for testing the closest hair strand lone
  330. // pixOut.m_color = GetClosestFragment(input.m_position.xy, input.m_texCoord, tangent, pixOut.m_depth);
  331. pixOut.m_color = GatherLinkedList(input.m_position.xy, input.m_texCoord, pixOut.m_depth);
  332. return pixOut;
  333. }