Volumetric Clouds.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /******************************************************************************/
  2. #include "!Header.h"
  3. #include "Sky.h"
  4. #include "Volumetric.h"
  5. /******************************************************************************/
  6. struct VolCloudClass
  7. {
  8. Flt AC4_bottom,
  9. AC4_top ,
  10. A2_inv ,
  11. max_steps ;
  12. Vec2 pos ;
  13. Vec pixels ;
  14. };
  15. struct VolCloudMapClass
  16. {
  17. Flt curve, curve2, height, thickness, tex_scale, steps, shadow;
  18. Vec2 pos;
  19. Vec cam;
  20. };
  21. BUFFER(VolCloud)
  22. VolCloudClass Cloud;
  23. BUFFER_END
  24. BUFFER(VolCloudMap)
  25. VolCloudMapClass CloudMap;
  26. BUFFER_END
  27. /******************************************************************************/
  28. // CLOUDS
  29. /******************************************************************************
  30. clouds = -Cloud.curve*x*x + Cloud.height
  31. ray = m*x = dir.y/Length(dir.xz)*x
  32. m*x = -Cloud.curve*x*x + Cloud.height
  33. Cloud.curve*x*x + m*x - Cloud.height = 0
  34. A=Cloud.curve, B=m, C=-Cloud.height
  35. Delta=B*B - 4*A*C = m*m + 4*Cloud.curve*Cloud.height
  36. SqrtDelta=Sqrt(m*m + 4*Cloud.curve*Cloud.height)
  37. x0=(-m-SqrtDelta)/(2*Cloud.curve)
  38. x1=(-m+SqrtDelta)/(2*Cloud.curve)
  39. x1=(SqrtDelta-m)/(2*Cloud.curve)
  40. x1=(SqrtDelta-m)*A2_inv
  41. /******************************************************************************/
  42. void Clouds_VS(VtxInput vtx,
  43. out Vec dir :TEXCOORD,
  44. out Vec4 outVtx:POSITION)
  45. {
  46. dir=Transform3(Vec(ScreenToPosXY(vtx.tex()), 1), CamMatrix); // world-space position
  47. outVtx=Vec4(vtx.pos2(), !REVERSE_DEPTH, 1); AdjustPixelCenter(outVtx); // set Z to be at the end of the viewport, this enables optimizations by optional applying lighting only on solid pixels (no sky/background)
  48. }
  49. #if DX9
  50. Vec4
  51. #else
  52. Vec2
  53. #endif
  54. Clouds_PS(NOPERSP Vec dir:TEXCOORD):COLOR // 'dir'=world-space position
  55. {
  56. Flt a=Sat(dir.y*8); // alternatively, 'a' could be calculated as "a=Sat(max_from-from)"
  57. #if FLOW
  58. BRANCH if(a<=EPS_COL)return 0;
  59. #endif
  60. dir/=Length(dir.xz);
  61. Flt from=(Sqrt(dir.y*dir.y + Cloud.AC4_bottom)-dir.y)*Cloud.A2_inv,
  62. to =(Sqrt(dir.y*dir.y + Cloud.AC4_top )-dir.y)*Cloud.A2_inv, delta=to-from;
  63. Vec pos=Vec( 1, dir.x*from +Cloud.pos.x, dir.z*from +Cloud.pos.y); // correct way would be to start from "1-0.5f/Cloud.pixels.x", however it's really unnoticeable
  64. dir=Vec(-1, dir.x*delta , dir.z*delta );
  65. Flt pixels=Length(dir*Cloud.pixels);
  66. Int steps =Mid (pixels, 2, Cloud.max_steps);
  67. dir/=steps;
  68. Vec2 col=0;
  69. LOOP for(Int i=0; i<steps; i++)
  70. {
  71. #if MODEL>=SM_4
  72. Vec2 sample=Vol.SampleLevel(SamplerLinearCWW, pos, 0).rg;
  73. /* test code for adding detail if(Z)
  74. {
  75. Flt s=0.5f;
  76. Flt m;
  77. if(X>=2.5)m=2.0*(1-Sqr(1-sample.y))*s;else
  78. if(X>=1.5)m=1.1*Sqrt(sample.y)*s;else
  79. if(X)m=0.5*Sat(sample.y*10)*s;else
  80. m=3*sample.y*s;
  81. sample.y+=(Vol1.SampleLevel(SamplerLinearWrap, pos*S*Z , 0).r)*m;
  82. if(Y)sample.y+=(Vol1.SampleLevel(SamplerLinearWrap, pos*S*Z*2, 0).r)*m/2;
  83. sample.y=Sat(sample.y);
  84. }*/
  85. #elif !DX9
  86. Vec2 sample=Tex3DLod(Vol, pos).rg;
  87. #else
  88. Vec2 sample=Tex3DLod(Vol, pos).ra;
  89. #endif
  90. Flt alpha=sample.y*(1-col.y);
  91. col.x+=alpha*sample.x;
  92. col.y+=alpha;
  93. pos+=dir;
  94. }
  95. col.x/=col.y+EPS; // NaN
  96. col.y*=a;
  97. #if DX9
  98. return Vec4(col, 0, 0);
  99. #else
  100. return col;
  101. #endif
  102. }
  103. /******************************************************************************/
  104. // SHADOW MAP
  105. /******************************************************************************/
  106. void CloudsMap_VS(VtxInput vtx,
  107. out Vec outPos:TEXCOORD0,
  108. out Vec outDir:TEXCOORD1,
  109. out Vec4 outVtx:POSITION )
  110. {
  111. outPos=CloudMap.cam // this is CamMatrix.pos-ActiveCam.matrix.pos (light camera relative to main camera)
  112. +CamMatrix[0]*(vtx.pos2().x/ProjMatrix[0][0]) // ProjMatrix.x.x which is 1/fov.x
  113. +CamMatrix[1]*(vtx.pos2().y/ProjMatrix[1][1]); // ProjMatrix.y.y which is 1/fov.y
  114. outDir=CamMatrix[2];
  115. outVtx=vtx.pos4(); AdjustPixelCenter(outVtx);
  116. }
  117. #if DX9
  118. Vec4
  119. #else
  120. Flt
  121. #endif
  122. CloudsMap_PS(NOPERSP Vec pos:TEXCOORD0, // world-space position, relative to main camera
  123. NOPERSP Vec dir:TEXCOORD1 // world-space direction
  124. ):COLOR
  125. {
  126. /* clouds = -Cloud.curve*x*x + Cloud.height
  127. ray = pos + dir*t
  128. x = (pos + dir*t).xz.length() (this is the X as in, distance from cloud Y axis)
  129. x = (pos.xz + dir.xz*t).length()
  130. x*x = (pos.xz + dir.xz*t).length2()
  131. Length2(v) = Sqr(v.x) + Sqr(v.y)
  132. x*x = Sqr(pos.x + dir.x*t) + Sqr(pos.z + dir.z*t)
  133. clouds = -Cloud.curve*(Sqr(pos.x + dir.x*t) + Sqr(pos.z + dir.z*t)) + Cloud.height
  134. pos.y + dir.y*t = -Cloud.curve*(pos.x*pos.x + dir.x*dir.x*t*t + 2*pos.x*dir.x*t + pos.z*pos.z + dir.z*dir.z*t*t + 2*pos.z*dir.z*t) + Cloud.height
  135. pos.y + dir.y*t + Cloud.curve*(pos.x*pos.x + dir.x*dir.x*t*t + 2*pos.x*dir.x*t + pos.z*pos.z + dir.z*dir.z*t*t + 2*pos.z*dir.z*t) - Cloud.height = 0
  136. Cloud.curve*(dir.x*dir.x + dir.z*dir.z)*t*t + (dir.y+Cloud.curve*2*(pos.x*dir.x + pos.z*dir.z))*t + pos.y+Cloud.curve*(pos.x*pos.x + pos.z*pos.z)-Cloud.height
  137. Flt a = CloudMap.curve *(dir.x*dir.x + dir.z*dir.z),
  138. b =dir.y+CloudMap.curve*2*(pos.x*dir.x + pos.z*dir.z),
  139. c =pos.y+CloudMap.curve *(pos.x*pos.x + pos.z*pos.z)-CloudMap.height,
  140. d_u=b*b - 4*a*(c-CloudMap.thickness), // -thickness because 'c' is calculated with -CloudMap.height so we're subtracting
  141. d_l=b*b - 4*a* c ; */
  142. Flt a2 = CloudMap.curve2*(dir.x*dir.x + dir.z*dir.z), // this is a*2, which allows better performance
  143. b =dir.y+CloudMap.curve2*(pos.x*dir.x + pos.z*dir.z),
  144. c =pos.y+CloudMap.curve *(pos.x*pos.x + pos.z*pos.z)-CloudMap.height,
  145. d_u=b*b - 2*a2*(c-CloudMap.thickness), // here "4*a" was replaced with "2*a2", -thickness because 'c' is calculated with -CloudMap.height so we're subtracting
  146. d_l=b*b - 2*a2* c ; // here "4*a" was replaced with "2*a2"
  147. BRANCH if(d_u<=0 || d_l<=0)return 1; // 1=full light (zero shadow)
  148. Flt t_u=(-b - Sqrt(d_u))/a2, // here "(2*a)" was replaced with "a2"
  149. t_l=(-b - Sqrt(d_l))/a2, // here "(2*a)" was replaced with "a2"
  150. delta=(t_l-t_u)*CloudMap.tex_scale;
  151. pos=Vec( 0, (pos.x+dir.x*t_u)*CloudMap.tex_scale+CloudMap.pos.x, (pos.z+dir.z*t_u)*CloudMap.tex_scale+CloudMap.pos.y); // start from upper layer (above clouds)
  152. dir=Vec( 1, dir.x*delta , dir.z*delta ); // go down (below clouds)
  153. Int steps=CloudMap.steps;
  154. dir/=steps;
  155. Flt density=0;
  156. LOOP for(Int i=0; i<steps; i++)
  157. {
  158. #if MODEL>=SM_4
  159. Flt alpha=Vol.SampleLevel(SamplerLinearCWW, pos, 0).g;
  160. #elif !DX9
  161. Flt alpha=Tex3DLod(Vol, pos).g;
  162. #else
  163. Flt alpha=Tex3DLod(Vol, pos).a;
  164. #endif
  165. density+=alpha*(1-density);
  166. pos +=dir;
  167. }
  168. return 1-density*CloudMap.shadow; // Lerp(1, 1-density, CloudMap.shadow) = 1*(1-CloudMap.shadow) + (1-density)*CloudMap.shadow = 1-CloudMap.shadow+CloudMap.shadow - density*CloudMap.shadow
  169. }
  170. /******************************************************************************/
  171. // DRAW
  172. /******************************************************************************/
  173. void CloudsDraw_VS(VtxInput vtx,
  174. out Vec2 outTex:TEXCOORD0,
  175. out Vec outPos:TEXCOORD1,
  176. out Vec4 outVtx:POSITION )
  177. {
  178. outTex=vtx.tex();
  179. outPos=Vec(ScreenToPosXY(vtx.tex()), 1);
  180. outVtx=Vec4(vtx.pos2(), !REVERSE_DEPTH, 1); AdjustPixelCenter(outVtx); // set Z to be at the end of the viewport, this enables optimizations by optional applying lighting only on solid pixels (no sky/background)
  181. }
  182. Vec4 CloudsDraw_PS(NOPERSP Vec2 inTex:TEXCOORD0,
  183. NOPERSP Vec inPos:TEXCOORD1):COLOR
  184. {
  185. Vec2 clouds=TexLod(Col, inTex).xy; // can't use TexPoint because Col may be smaller
  186. #if 1
  187. clouds.y*=Sat(TexDepthPoint(inTex)*Length(inPos)*SkyFracMulAdd.x+SkyFracMulAdd.y);
  188. #else
  189. Vec pos=GetPosPoint(inTex, inPosXY); clouds.y*=Sat(Length(pos)*SkyFracMulAdd.x+SkyFracMulAdd.y);
  190. #endif
  191. return Vec4(Color[0].rgb*clouds.x, clouds.y);
  192. }
  193. /******************************************************************************/
  194. // TECHNIQUES
  195. /******************************************************************************/
  196. TECHNIQUE(Clouds , Clouds_VS (), Clouds_PS ());
  197. TECHNIQUE(CloudsMap , CloudsMap_VS (), CloudsMap_PS ());
  198. TECHNIQUE(CloudsDraw, CloudsDraw_VS(), CloudsDraw_PS());
  199. /******************************************************************************/