POM_PS.hlsl 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. // RUN: %dxc -E main -T ps_6_0 %s | FileCheck %s
  2. // CHECK: DerivCoarseX
  3. // CHECK: DerivCoarseY
  4. // CHECK: dot3
  5. // CHECK: sampleGrad
  6. // CHECK: sample
  7. // CHECK: sample
  8. // CHECK: Saturate
  9. // CHECK: storeOutput
  10. // CHECK: !"dx.controlflow.hints", i32 2
  11. //--------------------------------------------------------------------------------------
  12. // File: POM.hlsl
  13. //
  14. // HLSL file containing shader functions for Parallax Occlusion Mapping.
  15. //
  16. // Copyright (c) Microsoft Corporation. All rights reserved.
  17. //--------------------------------------------------------------------------------------
  18. #include "shader_include.hlsli"
  19. //--------------------------------------------------------------------------------------
  20. // Structures
  21. //--------------------------------------------------------------------------------------
  22. struct VS_INPUT
  23. {
  24. float3 inPositionOS : POSITION;
  25. float2 inTexCoord : TEXCOORD0;
  26. float3 vInNormalOS : NORMAL;
  27. float3 vInBinormalOS : BINORMAL;
  28. float3 vInTangentOS : TANGENT;
  29. };
  30. struct VS_OUTPUT
  31. {
  32. float2 texCoord : TEXCOORD0;
  33. float3 vLightTS : TEXCOORD1; // Light vector in tangent space, denormalized
  34. float3 vViewTS : TEXCOORD2; // View vector in tangent space, denormalized
  35. float2 vParallaxOffsetTS : TEXCOORD3; // Parallax offset vector in tangent space
  36. float3 vNormalWS : TEXCOORD4; // Normal vector in world space
  37. float3 vViewWS : TEXCOORD5; // View vector in world space
  38. float4 position : SV_POSITION; // Output position
  39. };
  40. struct PS_INPUT
  41. {
  42. float2 texCoord : TEXCOORD0;
  43. float3 vLightTS : TEXCOORD1; // Light vector in tangent space, denormalized
  44. float3 vViewTS : TEXCOORD2; // View vector in tangent space, denormalized
  45. float2 vParallaxOffsetTS : TEXCOORD3; // Parallax offset vector in tangent space
  46. float3 vNormalWS : TEXCOORD4; // Normal vector in world space
  47. float3 vViewWS : TEXCOORD5; // View vector in world space
  48. };
  49. //--------------------------------------------------------------------------------------
  50. // Parallax occlusion mapping pixel shader
  51. //--------------------------------------------------------------------------------------
  52. float4 main( PS_INPUT i ) : SV_TARGET
  53. {
  54. // Normalize the interpolated vectors:
  55. float3 vViewTS = normalize( i.vViewTS );
  56. float3 vViewWS = normalize( i.vViewWS );
  57. float3 vLightTS = normalize( i.vLightTS );
  58. float3 vNormalWS = normalize( i.vNormalWS );
  59. float4 cResultColor = float4( 0, 0, 0, 1 );
  60. // Compute all the derivatives:
  61. float2 dx = ddx( i.texCoord );
  62. float2 dy = ddy( i.texCoord );
  63. //===============================================//
  64. // Parallax occlusion mapping offset computation //
  65. //===============================================//
  66. // Utilize dynamic flow control to change the number of samples per ray
  67. // depending on the viewing angle for the surface. Oblique angles require
  68. // smaller step sizes to achieve more accurate precision for computing displacement.
  69. // We express the sampling rate as a linear function of the angle between
  70. // the geometric normal and the view direction ray:
  71. int nNumSteps = (int)lerp( g_nMaxSamples, g_nMinSamples, dot( vViewWS, vNormalWS ) );
  72. // Intersect the view ray with the height field profile along the direction of
  73. // the parallax offset ray (computed in the vertex shader. Note that the code is
  74. // designed specifically to take advantage of the dynamic flow control constructs
  75. // in HLSL and is very sensitive to specific syntax. When converting to other examples,
  76. // if still want to use dynamic flow control in the resulting assembly shader,
  77. // care must be applied.
  78. //
  79. // In the below steps we approximate the height field profile as piecewise linear
  80. // curve. We find the pair of endpoints between which the intersection between the
  81. // height field profile and the view ray is found and then compute line segment
  82. // intersection for the view ray and the line segment formed by the two endpoints.
  83. // This intersection is the displacement offset from the original texture coordinate.
  84. float fCurrHeight = 0.0;
  85. float fStepSize = 1.0 / (float) nNumSteps;
  86. float fPrevHeight = 1.0;
  87. float fNextHeight = 0.0;
  88. int nStepIndex = 0;
  89. bool bCondition = true;
  90. float2 vTexOffsetPerStep = fStepSize * i.vParallaxOffsetTS;
  91. float2 vTexCurrentOffset = i.texCoord;
  92. float fCurrentBound = 1.0;
  93. float fParallaxAmount = 0.0;
  94. float2 pt1 = 0;
  95. float2 pt2 = 0;
  96. float2 texOffset2 = 0;
  97. while ( nStepIndex < nNumSteps )
  98. {
  99. vTexCurrentOffset -= vTexOffsetPerStep;
  100. // Sample height map which in this case is stored in the alpha channel of the normal map:
  101. fCurrHeight = g_nmhTexture.SampleGrad( g_samLinear, vTexCurrentOffset, dx, dy ).a;
  102. fCurrentBound -= fStepSize;
  103. if ( fCurrHeight > fCurrentBound )
  104. {
  105. pt1 = float2( fCurrentBound, fCurrHeight );
  106. pt2 = float2( fCurrentBound + fStepSize, fPrevHeight );
  107. texOffset2 = vTexCurrentOffset - vTexOffsetPerStep;
  108. nStepIndex = nNumSteps + 1;
  109. }
  110. else
  111. {
  112. nStepIndex++;
  113. fPrevHeight = fCurrHeight;
  114. }
  115. } // End of while ( nStepIndex < nNumSteps )
  116. float fDelta2 = pt2.x - pt2.y;
  117. float fDelta1 = pt1.x - pt1.y;
  118. float fDenominator = fDelta2 - fDelta1;
  119. // SM 3.0 and above requires a check for divide by zero since that operation will generate an 'Inf' number instead of 0
  120. [flatten]if ( fDenominator == 0.0f )
  121. {
  122. fParallaxAmount = 0.0f;
  123. }
  124. else
  125. {
  126. fParallaxAmount = ( pt1.x * fDelta2 - pt2.x * fDelta1 ) / fDenominator;
  127. }
  128. float2 vParallaxOffset = i.vParallaxOffsetTS * ( 1.0 - fParallaxAmount );
  129. // The computed texture offset for the displaced point on the pseudo-extruded surface:
  130. float2 texSample = i.texCoord - vParallaxOffset;
  131. // Compute resulting color for the pixel:
  132. cResultColor = ComputeIllumination( texSample, vLightTS, vViewTS );
  133. return cResultColor;
  134. }