HairStrands.azsli 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  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 hair strands in the graphics pipeline.
  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. #pragma once
  33. #include <HairUtilities.azsli>
  34. #define CM_TO_METERS_RENDER 0.01
  35. float4 GetSharedVector4(int offset)
  36. {
  37. return float4(
  38. float3(
  39. asfloat(PassSrg::m_skinnedHairSharedBuffer[offset]),
  40. asfloat(PassSrg::m_skinnedHairSharedBuffer[offset + 1]),
  41. asfloat(PassSrg::m_skinnedHairSharedBuffer[offset + 2])
  42. ),// * CM_TO_METERS, // convert to meters when using
  43. asfloat(PassSrg::m_skinnedHairSharedBuffer[offset + 3])
  44. );
  45. }
  46. float4 GetSharedPosition(int vertexIndex)
  47. {
  48. int vertexOffset = (HairDynamicDataSrg::m_positionBufferOffset >> 2) + (vertexIndex << 2);
  49. return GetSharedVector4(vertexOffset);
  50. }
  51. float3 GetSharedTangent(int tangentIndex)
  52. {
  53. int tangentOffset = (HairDynamicDataSrg::m_tangentBufferOffset >> 2) + (tangentIndex << 2);
  54. return float3(
  55. asfloat(PassSrg::m_skinnedHairSharedBuffer[tangentOffset]),
  56. asfloat(PassSrg::m_skinnedHairSharedBuffer[tangentOffset + 1]),
  57. asfloat(PassSrg::m_skinnedHairSharedBuffer[tangentOffset + 2])
  58. );
  59. }
  60. //! Hair vertex geometry output - input structure for the Pixel shaders
  61. struct TressFXVertex
  62. {
  63. float4 Position;
  64. float4 Tangent; // xyz = Tangent, w = Strand U
  65. float4 p0p1;
  66. float4 StrandColor; // xyz = Strand Color, w = Strand V
  67. };
  68. //! Matching structure to carry out as VS output / PS input
  69. struct PS_INPUT_HAIR
  70. {
  71. float4 Position : SV_POSITION;
  72. float4 Tangent : Tangent;
  73. float4 p0p1 : TEXCOORD0;
  74. float4 StrandColor : TEXCOORD1;
  75. };
  76. float3 GetStrandColor(int index, float fractionOfStrand)
  77. {
  78. float3 rootColor;
  79. float3 tipColor;
  80. float2 texCd = g_HairStrandTexCd[(float) index / NumVerticesPerStrand].xy;
  81. rootColor = BaseAlbedoTexture.SampleLevel(LinearWrapSampler, texCd, 0).rgb;
  82. tipColor = MatTipColor.rgb;
  83. // Multiply with Base Material color
  84. rootColor *= MatBaseColor.rgb;
  85. // Update the color based on position along the strand (vertex level) and lerp between tip and root if within the tipPercentage requested
  86. float rootRange = 1.f - TipPercentage;
  87. return (fractionOfStrand > rootRange) ? lerp(rootColor, tipColor, (fractionOfStrand - rootRange) / TipPercentage) : rootColor;
  88. }
  89. TressFXVertex GetExpandedTressFXVert(uint vertexId, float3 eye, float2 winSize, float4x4 viewProj)
  90. {
  91. // Access the current line / curve segment - remember that the mesh is built around
  92. // the center line / curve that is expanded as the vertices.
  93. uint index = vertexId / 2; // vertexId is the indexed vertex id when indexed triangles are used
  94. // Get updated positions and tangents from simulation result
  95. // float3 v = GetSharedPosition(index).xyz;
  96. float3 v = g_GuideHairVertexPositions[index].xyz;
  97. // Both approaches (offset to shared buffer or BufferView) will work!
  98. // float3 t = GetSharedTangent(index);
  99. float3 t = g_GuideHairVertexTangents[index].xyz;
  100. // Get hair strand thickness
  101. uint indexInStrand = index % NumVerticesPerStrand;
  102. float fractionOfStrand = (float)indexInStrand / (NumVerticesPerStrand - 1);
  103. float ratio = (EnableThinTip > 0) ? lerp(1.0, FiberRatio, fractionOfStrand) : 1.0; // need length of full strand vs the length of this point on the strand.
  104. // Calculate right and projected right vectors
  105. float3 right = Safe_normalize(cross(t, Safe_normalize(v - eye)));
  106. float2 proj_right = Safe_normalize(MatrixMult(viewProj, float4(right, 0)).xy);
  107. // We always to to expand for faster hair AA, we may want to gauge making this adjustable
  108. float expandPixels = 0.71 * CM_TO_METERS_RENDER;
  109. // Calculate the negative and positive offset screenspace positions
  110. float4 hairEdgePositions[2]; // 0 is negative, 1 is positive
  111. hairEdgePositions[0] = float4(v - right * ratio * FiberRadius, 1.0);
  112. hairEdgePositions[1] = float4(v + right * ratio * FiberRadius, 1.0);
  113. hairEdgePositions[0] = MatrixMult(viewProj, hairEdgePositions[0]);
  114. hairEdgePositions[1] = MatrixMult(viewProj, hairEdgePositions[1]);
  115. // Gonna hi-jack Tangent.w (unused) and add a .w component to strand color to store a strand UV
  116. float2 strandUV;
  117. strandUV.x = (vertexId & 0x01) ? 0.f : 1.f;
  118. strandUV.y = fractionOfStrand;
  119. // Write output data
  120. TressFXVertex Output = (TressFXVertex)0;
  121. float fDirIndex = (vertexId & 0x01) ? -1.0 : 1.0;
  122. Output.Position = ((vertexId & 0x01) ? hairEdgePositions[0] : hairEdgePositions[1])
  123. // [To Do] Hair: remove the scale
  124. + CM_TO_METERS_RENDER * fDirIndex * float4(proj_right * expandPixels / winSize.y, 0.0f, 0.0f)
  125. * ((vertexId & 0x01) ? hairEdgePositions[0].w : hairEdgePositions[1].w);
  126. Output.Tangent = float4(t, strandUV.x);
  127. Output.p0p1 = float4(hairEdgePositions[0].xy / max(hairEdgePositions[0].w, TRESSFX_FLOAT_EPSILON), hairEdgePositions[1].xy / max(hairEdgePositions[1].w, TRESSFX_FLOAT_EPSILON));
  128. Output.StrandColor = float4(GetStrandColor(index, fractionOfStrand), strandUV.y);
  129. return Output;
  130. }
  131. TressFXVertex GetExpandedTressFXShadowVert(uint vertexId, float3 eye, float2 winSize, float4x4 viewProj)
  132. {
  133. // Access the current line segment
  134. uint index = vertexId / 2; // vertexId is actually the indexed vertex id when indexed triangles are used
  135. // Get updated positions and tangents from simulation result
  136. // float3 v = GetSharedPosition(index).xyz;
  137. float3 v = g_GuideHairVertexPositions[index].xyz;
  138. // float3 t = GetSharedTangent(index); // Adi: both approaches will work!!
  139. float3 t = g_GuideHairVertexTangents[index].xyz;
  140. // Get hair strand thickness
  141. uint indexInStrand = index % NumVerticesPerStrand;
  142. float fractionOfStrand = (float)indexInStrand / (NumVerticesPerStrand - 1);
  143. float ratio = (EnableThinTip > 0) ? lerp(1.0, FiberRatio, fractionOfStrand) : 1.0; //need length of full strand vs the length of this point on the strand.
  144. // Calculate right and projected right vectors
  145. float3 right = Safe_normalize(cross(t, Safe_normalize(v - eye)));
  146. float2 proj_right = Safe_normalize(MatrixMult(viewProj, float4(right, 0)).xy);
  147. // We always to to expand for faster hair AA, we may want to gauge making this adjustable
  148. float expandPixels = 1.f * CM_TO_METERS_RENDER; // Disable for shadows 0.71;
  149. // Calculate the negative and positive offset screenspace positions
  150. float4 hairEdgePositions[2]; // 0 is negative, 1 is positive
  151. hairEdgePositions[0] = float4(v + -1.0 * right * ratio * FiberRadius * CM_TO_METERS_RENDER, 1.0);
  152. hairEdgePositions[1] = float4(v + 1.0 * right * ratio * FiberRadius * CM_TO_METERS_RENDER, 1.0);
  153. hairEdgePositions[0] = MatrixMult(viewProj, hairEdgePositions[0]);
  154. hairEdgePositions[1] = MatrixMult(viewProj, hairEdgePositions[1]);
  155. // Write output data
  156. TressFXVertex Output = (TressFXVertex)0;
  157. float fDirIndex = (vertexId & 0x01) ? -1.0 : 1.0;
  158. Output.Position = ((vertexId & 0x01) ? hairEdgePositions[0] : hairEdgePositions[1]) + fDirIndex * float4(proj_right * expandPixels / winSize.y, 0.0f, 0.0f) * ((vertexId & 0x01) ? hairEdgePositions[0].w : hairEdgePositions[1].w);
  159. return Output;
  160. }
  161. //!=============================================================================
  162. //! Hair Render VS - Used by all geometry hair shaders
  163. //!=============================================================================
  164. PS_INPUT_HAIR RenderHairVS(uint vertexId : SV_VertexID)
  165. {
  166. PS_INPUT_HAIR vsOutput;
  167. // uint2 scrSize;
  168. // PassSrg::m_linearDepth.GetDimensions(scrSize.x, scrSize.y);
  169. // TressFXVertex tressfxVert = GetExpandedTressFXVert(vertexId, g_vEye.xyz, float2(scrSize), g_mVP);
  170. // [To Do] Hair: the above code should replace the existing but requires modifications to
  171. // the function GetExpandedTressFXVert.
  172. // Note that in Atom g_vViewport is aspect ratio and NOT size.
  173. TressFXVertex tressfxVert = GetExpandedTressFXVert(vertexId, g_vEye.xyz, g_vViewport.zw, g_mVP);
  174. vsOutput.Position = tressfxVert.Position;
  175. vsOutput.Tangent = tressfxVert.Tangent;
  176. vsOutput.p0p1 = tressfxVert.p0p1;
  177. vsOutput.StrandColor = tressfxVert.StrandColor;
  178. return vsOutput;
  179. }