Sky.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. namespace EE{
  4. /******************************************************************************/
  5. SkyClass Sky;
  6. /******************************************************************************/
  7. SkyClass::SkyClass()
  8. {
  9. frac (0.8f); // !! if changing default value, then also change in 'Environment.Sky' !!
  10. atmosphericDensityExponent (1);
  11. atmosphericHorizonExponent (3.5f); // !! if changing default value, then also change in 'Environment.Sky' !!
  12. atmosphericColor (Vec4(0.32f, 0.46f, 0.58f, 1.0f), Vec4(0.16f, 0.36f, 0.54f, 1.0f)); // !! if changing default value, then also change in 'Environment.Sky' !!
  13. atmosphericStarsOrientation(MatrixIdentity.orn());
  14. #if MOBILE
  15. atmosphericPrecision (false);
  16. #else
  17. atmosphericPrecision (true);
  18. #endif
  19. skyboxBlend (0.5f);
  20. }
  21. SkyClass& SkyClass::del()
  22. {
  23. _mshr .del ();
  24. REPAO(_image).clear();
  25. _stars .clear();
  26. return T;
  27. }
  28. SkyClass& SkyClass::create()
  29. {
  30. Sh.h_SkyHorCol ->set(_hor_col );
  31. Sh.h_SkySkyCol ->set(_sky_col );
  32. Sh.h_SkyBoxBlend->set(_box_blend);
  33. Sh.h_SkyStarOrn ->set(_stars_m );
  34. Flt temp=_hor_exp; _hor_exp=-1; atmosphericHorizonExponent(temp); // set -1 to force reset
  35. temp=_dns_exp; _dns_exp=-1; atmosphericDensityExponent(temp); // set -1 to force reset
  36. MeshBase mshb;
  37. mshb.createIco(Ball(1), 0, 3); // 3 give 'dist'=0.982246876
  38. _mshr.create(mshb.reverse());
  39. #define SKY_MESH_MIN_DIST 0.98f // it's good to make it a bit smaller than 'dist' to have some epsilon for precision issues, this is the closest point on the mesh to the Vec(0,0,0), it's not equal to radius=1, because the mesh is composed out of triangles, and the triangle surfaces are closer
  40. #if DEBUG && 0 // calculate actual distance
  41. Flt dist=1; C Vec *pos=mshb.vtx.pos();
  42. REPA(mshb.tri ){C VecI &t=mshb.tri .ind(i); MIN(dist, Dist(VecZero, Tri (pos[t.x], pos[t.y], pos[t.z])));}
  43. REPA(mshb.quad){C VecI4 &q=mshb.quad.ind(i); MIN(dist, Dist(VecZero, Quad(pos[q.x], pos[q.y], pos[q.z], pos[q.w])));}
  44. #endif
  45. return T;
  46. }
  47. /******************************************************************************/
  48. Bool SkyClass::wantDepth()C {return frac()<1;}
  49. /******************************************************************************/
  50. SkyClass& SkyClass::clear()
  51. {
  52. _is=false;
  53. return T;
  54. }
  55. SkyClass& SkyClass::atmospheric()
  56. {
  57. T._is =true;
  58. T._image[0]=null;
  59. T._image[1]=null;
  60. return T;
  61. }
  62. SkyClass& SkyClass::skybox(C ImagePtr &image)
  63. {
  64. T._is =(image!=null);
  65. T._image[0]=image;
  66. T._image[1]=null ;
  67. return T;
  68. }
  69. SkyClass& SkyClass::skybox(C ImagePtr &a, C ImagePtr &b)
  70. {
  71. T._is=(a || b);
  72. if(a && b){T._image[0]=a ; T._image[1]=b ;}else
  73. if(a ){T._image[0]=a ; T._image[1]=null;}else
  74. if( b){T._image[0]=b ; T._image[1]=null;}else
  75. {T._image[0]=null; T._image[1]=null;}
  76. return T;
  77. }
  78. /******************************************************************************/
  79. SkyClass& SkyClass::frac ( Flt frac ) {SAT(frac ); T._frac =frac ; return T;}
  80. SkyClass& SkyClass::atmosphericHorizonExponent ( Flt exp ) {MAX(exp, 0); if(exp !=T._hor_exp ){T._hor_exp =exp ; if(Sh.h_SkyHorExp )Sh.h_SkyHorExp ->set(Max(T._hor_exp, EPS_GPU));} return T;} // avoid zero in case "Pow(1-Sat(inTex.y), SkyHorExp)" in shader would cause NaN or slow-downs
  81. SkyClass& SkyClass::atmosphericHorizonColor (C Vec4 &color ) {Flt alpha=Sat(color.w); if(color.xyz!=T._hor_col.xyz || alpha!=T._hor_col.w){T._hor_col.set(color.xyz, alpha); if(Sh.h_SkyHorCol )Sh.h_SkyHorCol ->set( T._hor_col );} return T;} // alpha must be saturated
  82. SkyClass& SkyClass::atmosphericSkyColor (C Vec4 &color ) {Flt alpha=Sat(color.w); if(color.xyz!=T._sky_col.xyz || alpha!=T._sky_col.w){T._sky_col.set(color.xyz, alpha); if(Sh.h_SkySkyCol )Sh.h_SkySkyCol ->set( T._sky_col );} return T;} // alpha must be saturated
  83. SkyClass& SkyClass::skyboxBlend ( Flt blend ) {SAT(blend ); if(blend !=T._box_blend ){T._box_blend =blend ; if(Sh.h_SkyBoxBlend)Sh.h_SkyBoxBlend->set( T._box_blend );} return T;}
  84. SkyClass& SkyClass::atmosphericStars (C ImagePtr &cube ) { T._stars =cube ; return T;}
  85. SkyClass& SkyClass::atmosphericStarsOrientation(C Matrix3 &orn ) { {T._stars_m =orn ; if(Sh.h_SkyStarOrn )Sh.h_SkyStarOrn ->set( T._stars_m );} return T;}
  86. SkyClass& SkyClass::atmosphericPrecision ( Bool per_pixel) { T._precision =per_pixel ; return T;}
  87. SkyClass& SkyClass::atmosphericDensityExponent ( Flt exp )
  88. {
  89. SAT(exp); if(exp!=T._dns_exp)
  90. {
  91. T._dns_exp=exp;
  92. if(Sh.h_SkyDnsExp)
  93. {
  94. /* shader uses the formula based on "Flt AccumulatedDensity(Flt density, Flt range) {return 1-Pow(1-density, range);}"
  95. "1-Pow(SkyDnsExp, alpha)" but that gives the range 0..(1-SkyDnsExp), however we need it normalized, so:
  96. (1-Pow(SkyDnsExp, alpha)) / (1-SkyDnsExp) gives the range 0..1
  97. -Pow(SkyDnsExp, alpha) / (1-SkyDnsExp) + 1/(1-SkyDnsExp)
  98. Pow(SkyDnsExp, alpha) * -(1/(1-SkyDnsExp)) + 1/(1-SkyDnsExp)
  99. Pow(SkyDnsExp, alpha) * mul + add
  100. */
  101. Flt v=1-exp; if(v)v=1/v;
  102. Sh.h_SkyDnsExp ->set(Max(T._dns_exp, EPS_GPU)); // avoid zero in case "Pow(0, alpha)" in shader would cause NaN or slow-downs
  103. Sh.h_SkyDnsMulAdd->set(Vec2(-v, v));
  104. }
  105. }
  106. return T;
  107. }
  108. /******************************************************************************/
  109. void SkyClass::setFracMulAdd()
  110. {
  111. // !! in this method we use 'SkyFracMulAdd' as Object Opacity, and not Sky Opacity, so we use "1-sky_opacity" (reversed compared to drawing the sky) !!
  112. if(isActual())
  113. {
  114. Flt from, to;
  115. Bool can_read_depth=Renderer.safeCanReadDepth(); // use 'safe' version because 'Renderer._ds' can be null here (for example when using RS_REFLECTION)
  116. if( !can_read_depth && Renderer.type()==RT_SIMPLE && !Renderer.simplePrecision()) // if we cannot apply sky frac, but we are in simple vertex fog mode, then use it instead
  117. {
  118. from=D.viewRange()*Renderer.simpleVertexFogStart();
  119. to =D.viewRange()*Renderer.simpleVertexFogEnd ();
  120. }else
  121. {
  122. from=(can_read_depth ? D.viewRange()*frac() : D.viewRange()); // we're using fraction only if we have depth access
  123. to =D.viewRange();
  124. }
  125. MIN(from, to-EPS_SKY_MIN_LERP_DIST); // make sure there's some distance between positions to avoid floating point issues, move 'from' instead of 'to' to make sure we always have zero opacity at the end
  126. //Flt obj_opacity=Length(O.pos)*SkyFracMulAdd.x+SkyFracMulAdd.y;
  127. // 1= from *SkyFracMulAdd.x+SkyFracMulAdd.y;
  128. // 0= to *SkyFracMulAdd.x+SkyFracMulAdd.y;
  129. Vec2 mul_add; mul_add.x=1/(from-to); mul_add.y=-to*mul_add.x;
  130. Sh.h_SkyFracMulAdd->set(mul_add);
  131. }else
  132. {
  133. Sh.h_SkyFracMulAdd->set(Vec2(0, 1));
  134. }
  135. }
  136. /******************************************************************************/
  137. INLINE Shader* SkyTF(Int textures, Bool cloud, Bool dither) {Shader* &s=Sh.h_SkyTF[textures-1][cloud][dither] ; if(SLOW_SHADER_LOAD && !s)s=Sh.getSkyTF(textures, cloud, dither); return s;}
  138. INLINE Shader* SkyT (Int textures, Int multi_sample, Bool dither) {Shader* &s=Sh.h_SkyT [textures-1][multi_sample][dither] ; if(SLOW_SHADER_LOAD && !s)s=Sh.getSkyT (textures, multi_sample, dither); return s;}
  139. INLINE Shader* SkyAF(Bool per_vertex, Bool stars, Bool cloud, Bool dither) {Shader* &s=Sh.h_SkyAF[per_vertex][stars][cloud][dither] ; if(SLOW_SHADER_LOAD && !s)s=Sh.getSkyAF(per_vertex, stars, cloud, dither); return s;}
  140. INLINE Shader* SkyA (Bool per_vertex, Bool stars, Bool density, Int multi_sample, Bool dither) {Shader* &s=Sh.h_SkyA [per_vertex][stars][density][multi_sample][dither]; if(SLOW_SHADER_LOAD && !s)s=Sh.getSkyA (per_vertex, stars, density, multi_sample, dither); return s;}
  141. void SkyClass::draw()
  142. {
  143. if(isActual())
  144. {
  145. Shader *shader, *shader_multi=null;
  146. Bool blend,
  147. density=(atmosphericDensityExponent()<1-EPS_GPU),
  148. dither =(D.dither() && !Renderer._col->highPrecision()),
  149. vertex = !_precision,
  150. stars =((_stars !=null) && (_hor_col.w<1-EPS_COL || _sky_col.w<1-EPS_COL)),
  151. cloud =(Clouds.draw && Clouds.layered.merge_with_sky && Clouds.layered.layers() && Clouds.layered.layer[0].image && Clouds.layered.layer[0].color.a && (Clouds.layered.draw_in_mirror || !Renderer.mirror()));
  152. Int tex =((_image[0]!=null) + (_image[1]!=null)),
  153. multi =(Renderer._col->multiSample() ? ((Renderer._cur_type==RT_DEFERRED) ? 1 : 2) : 0);
  154. Flt from =(Renderer.canReadDepth() ? D.viewRange()*frac() : D.viewRange()), // we're using fraction only if we have depth access
  155. to =D.viewRange();
  156. blend=(from<to-EPS_SKY_MIN_LERP_DIST); // set blend mode if 'from' is far from 'to', and yes use < and not <= in case of precision issues for big values
  157. if(tex)
  158. {
  159. if(blend){shader=SkyT (tex, 0, dither); if(multi)shader_multi=SkyT(tex, multi, dither);}
  160. else shader=SkyTF(tex, cloud, dither);
  161. }else
  162. {
  163. if(blend){shader=SkyA (vertex, stars, density, 0, dither); if(multi)shader_multi=SkyA(vertex, stars, density, multi, dither);}
  164. else shader=SkyAF(vertex, stars, cloud, dither);
  165. }
  166. // set shader parameters
  167. if(tex)
  168. {
  169. Sh.h_ImageRfl[0]->set(_image[0]());
  170. Sh.h_ImageCub ->set(_image[1]());
  171. }else
  172. if(stars)
  173. {
  174. Sh.h_ImageRfl[0]->set(_stars());
  175. }
  176. if(AstrosDraw && Sun.is())
  177. {
  178. Sh.h_SkySunHighlight->set(Vec2(Sun.highlight_front, Sun.highlight_back));
  179. Sh.h_SkySunPos ->set(Sun.pos);
  180. }else
  181. {
  182. Sh.h_SkySunHighlight->set(Vec2(0));
  183. }
  184. if(cloud)Clouds.layered.commit();
  185. Bool ds=true;
  186. Flt sky_ball_mesh_size; if(blend)
  187. {
  188. //Flt sky_opacity=Length(O.pos)*SkyFracMulAdd.x+SkyFracMulAdd.y;
  189. // 0= from *SkyFracMulAdd.x+SkyFracMulAdd.y;
  190. // 1= to *SkyFracMulAdd.x+SkyFracMulAdd.y;
  191. Vec2 mul_add; mul_add.x=1/(to-from); mul_add.y=-from*mul_add.x;
  192. Sh.h_SkyFracMulAdd->set(mul_add);
  193. sky_ball_mesh_size=from;
  194. //sky_ball_mesh_size-=DepthError(D.viewFrom(), D.viewRange(), sky_ball_mesh_size, FovPerspective(D.viewFovMode()), ImageTI[Renderer._ds->hwType()].d); // draw smaller by DepthError to avoid depth precision issues
  195. if(sky_ball_mesh_size*SKY_MESH_MIN_DIST<=FrustumMain.view_quad_max_dist){sky_ball_mesh_size=to; ds=false;} // if the closest point on the mesh surface is in touch with the view quad, it means that the ball would not render fully, we have to render it with full size and with depth test disabled
  196. }else sky_ball_mesh_size=to;
  197. #if !REVERSE_DEPTH // for low precision depth we need to make sure that sky ball mesh is slightly smaller than view range, to avoid mesh clipping, this was observed on OpenGL with viewFrom=0.05, viewRange=1024, Cam.yaw=0, Cam.pitch=PI_2
  198. MIN(sky_ball_mesh_size, to*EPS_SKY_MIN_VIEW_RANGE); // alternatively we could try using D3DRS_CLIPPING, DepthClipEnable, GL_DEPTH_CLAMP
  199. #endif
  200. Renderer.set(Renderer._col(), Renderer._ds(), true, blend ? NEED_DEPTH_READ : NO_DEPTH_READ); // specify correct mode because without it the sky may cover everything completely
  201. D.alpha (blend ? ALPHA_BLEND_DEC : ALPHA_NONE);
  202. D.depthWrite(false);
  203. D.depthFunc (FUNC_LESS_EQUAL); // to make sure we draw at the end of viewRange
  204. //D.cull (true ); ignore changing culling, because we're inside the sky ball, so we will always see its faces, we could potentially set false (to ignore overhead on the GPU for cull testing if any) however we choose to just ignore it to reduce GPU state changes on the CPU which are probably more costly
  205. D.sampler3D ( ); // set in case of drawing clouds
  206. if(shader_multi)D.stencil(STENCIL_MSAA_TEST);
  207. _mshr.set();
  208. SetOneMatrix(MatrixM(sky_ball_mesh_size, CamMatrix.pos)); // normally we have to set matrixes after 'setEyeViewport', however since matrixes are always relative to the camera, and here we set exactly at the camera position, so the matrix will be the same for both eyes
  209. REPS(Renderer._eye, Renderer._eye_num)
  210. {
  211. Renderer.setEyeViewport();
  212. if(shader_multi){D.depth((multi==1) ? false : ds); D.stencilRef(STENCIL_REF_MSAA); shader_multi->begin(); _mshr.drawFull(); ShaderEnd(); D.stencilRef(0);} // MS edges for deferred must not use depth testing
  213. D.depth( ds); shader ->begin(); _mshr.drawFull(); ShaderEnd();
  214. }
  215. D.sampler2D ( );
  216. D.depthWrite (true);
  217. D.depthFunc (FUNC_LESS);
  218. D.stencil (STENCIL_NONE);
  219. MaterialClear( );
  220. #if DX11
  221. D.flush(); // FIXME this is a workaround for Nvidia GeForce bug https://devtalk.nvidia.com/default/topic/1038873/directx-and-direct-compute/geforce-1050-ti-bug/ remove this line once the bug is fixed
  222. #endif
  223. }
  224. }
  225. /******************************************************************************/
  226. }
  227. /******************************************************************************/