sky.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. #include "sky.h"
  2. #include "IVideoDriver.h"
  3. #include "ISceneManager.h"
  4. #include "ICameraSceneNode.h"
  5. #include "S3DVertex.h"
  6. #include "client/tile.h"
  7. #include "noise.h" // easeCurve
  8. #include "profiler.h"
  9. #include "util/numeric.h"
  10. #include <cmath>
  11. #include "client/renderingengine.h"
  12. #include "settings.h"
  13. #include "camera.h" // CameraModes
  14. Sky::Sky(s32 id, ITextureSource *tsrc):
  15. scene::ISceneNode(RenderingEngine::get_scene_manager()->getRootSceneNode(),
  16. RenderingEngine::get_scene_manager(), id)
  17. {
  18. setAutomaticCulling(scene::EAC_OFF);
  19. m_box.MaxEdge.set(0, 0, 0);
  20. m_box.MinEdge.set(0, 0, 0);
  21. // Create material
  22. video::SMaterial mat;
  23. mat.Lighting = false;
  24. mat.ZBuffer = video::ECFN_NEVER;
  25. mat.ZWriteEnable = false;
  26. mat.AntiAliasing = 0;
  27. mat.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
  28. mat.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
  29. mat.BackfaceCulling = false;
  30. m_materials[0] = mat;
  31. m_materials[1] = mat;
  32. //m_materials[1].MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
  33. m_materials[1].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  34. m_materials[2] = mat;
  35. m_materials[2].setTexture(0, tsrc->getTextureForMesh("sunrisebg.png"));
  36. m_materials[2].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  37. //m_materials[2].MaterialType = video::EMT_TRANSPARENT_ADD_COLOR;
  38. m_sun_texture = tsrc->isKnownSourceImage("sun.png") ?
  39. tsrc->getTextureForMesh("sun.png") : NULL;
  40. m_moon_texture = tsrc->isKnownSourceImage("moon.png") ?
  41. tsrc->getTextureForMesh("moon.png") : NULL;
  42. m_sun_tonemap = tsrc->isKnownSourceImage("sun_tonemap.png") ?
  43. tsrc->getTexture("sun_tonemap.png") : NULL;
  44. m_moon_tonemap = tsrc->isKnownSourceImage("moon_tonemap.png") ?
  45. tsrc->getTexture("moon_tonemap.png") : NULL;
  46. if (m_sun_texture) {
  47. m_materials[3] = mat;
  48. m_materials[3].setTexture(0, m_sun_texture);
  49. m_materials[3].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  50. if (m_sun_tonemap)
  51. m_materials[3].Lighting = true;
  52. }
  53. if (m_moon_texture) {
  54. m_materials[4] = mat;
  55. m_materials[4].setTexture(0, m_moon_texture);
  56. m_materials[4].MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
  57. if (m_moon_tonemap)
  58. m_materials[4].Lighting = true;
  59. }
  60. for (v3f &star : m_stars) {
  61. star = v3f(
  62. myrand_range(-10000, 10000),
  63. myrand_range(-10000, 10000),
  64. myrand_range(-10000, 10000)
  65. );
  66. star.normalize();
  67. }
  68. m_directional_colored_fog = g_settings->getBool("directional_colored_fog");
  69. }
  70. void Sky::OnRegisterSceneNode()
  71. {
  72. if (IsVisible)
  73. SceneManager->registerNodeForRendering(this, scene::ESNRP_SKY_BOX);
  74. scene::ISceneNode::OnRegisterSceneNode();
  75. }
  76. void Sky::render()
  77. {
  78. if (!m_visible)
  79. return;
  80. video::IVideoDriver* driver = SceneManager->getVideoDriver();
  81. scene::ICameraSceneNode* camera = SceneManager->getActiveCamera();
  82. if (!camera || !driver)
  83. return;
  84. ScopeProfiler sp(g_profiler, "Sky::render()", SPT_AVG);
  85. // Draw perspective skybox
  86. core::matrix4 translate(AbsoluteTransformation);
  87. translate.setTranslation(camera->getAbsolutePosition());
  88. // Draw the sky box between the near and far clip plane
  89. const f32 viewDistance = (camera->getNearValue() + camera->getFarValue()) * 0.5f;
  90. core::matrix4 scale;
  91. scale.setScale(core::vector3df(viewDistance, viewDistance, viewDistance));
  92. driver->setTransform(video::ETS_WORLD, translate * scale);
  93. if (m_sunlight_seen) {
  94. float sunsize = 0.07;
  95. video::SColorf suncolor_f(1, 1, 0, 1);
  96. suncolor_f.r = 1;
  97. suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.7 + m_time_brightness * 0.5));
  98. suncolor_f.b = MYMAX(0.0, m_brightness * 0.95);
  99. video::SColorf suncolor2_f(1, 1, 1, 1);
  100. suncolor_f.r = 1;
  101. suncolor_f.g = MYMAX(0.3, MYMIN(1.0, 0.85 + m_time_brightness * 0.5));
  102. suncolor_f.b = MYMAX(0.0, m_brightness);
  103. float moonsize = 0.04;
  104. video::SColorf mooncolor_f(0.50, 0.57, 0.65, 1);
  105. video::SColorf mooncolor2_f(0.85, 0.875, 0.9, 1);
  106. float nightlength = 0.415;
  107. float wn = nightlength / 2;
  108. float wicked_time_of_day = 0;
  109. if (m_time_of_day > wn && m_time_of_day < 1.0 - wn)
  110. wicked_time_of_day = (m_time_of_day - wn) / (1.0 - wn * 2) * 0.5 + 0.25;
  111. else if (m_time_of_day < 0.5)
  112. wicked_time_of_day = m_time_of_day / wn * 0.25;
  113. else
  114. wicked_time_of_day = 1.0 - ((1.0 - m_time_of_day) / wn * 0.25);
  115. /*std::cerr<<"time_of_day="<<m_time_of_day<<" -> "
  116. <<"wicked_time_of_day="<<wicked_time_of_day<<std::endl;*/
  117. video::SColor suncolor = suncolor_f.toSColor();
  118. video::SColor suncolor2 = suncolor2_f.toSColor();
  119. video::SColor mooncolor = mooncolor_f.toSColor();
  120. video::SColor mooncolor2 = mooncolor2_f.toSColor();
  121. // Calculate offset normalized to the X dimension of a 512x1 px tonemap
  122. float offset = (1.0 - fabs(sin((m_time_of_day - 0.5) * irr::core::PI))) * 511;
  123. if (m_sun_tonemap) {
  124. u8 * texels = (u8 *)m_sun_tonemap->lock();
  125. video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
  126. video::SColor texel_color (255, texel->getRed(),
  127. texel->getGreen(), texel->getBlue());
  128. m_sun_tonemap->unlock();
  129. m_materials[3].EmissiveColor = texel_color;
  130. }
  131. if (m_moon_tonemap) {
  132. u8 * texels = (u8 *)m_moon_tonemap->lock();
  133. video::SColor* texel = (video::SColor *)(texels + (u32)offset * 4);
  134. video::SColor texel_color (255, texel->getRed(),
  135. texel->getGreen(), texel->getBlue());
  136. m_moon_tonemap->unlock();
  137. m_materials[4].EmissiveColor = texel_color;
  138. }
  139. const f32 t = 1.0f;
  140. const f32 o = 0.0f;
  141. static const u16 indices[4] = {0, 1, 2, 3};
  142. video::S3DVertex vertices[4];
  143. driver->setMaterial(m_materials[1]);
  144. video::SColor cloudyfogcolor = m_bgcolor;
  145. // Draw far cloudy fog thing blended with skycolor
  146. for (u32 j = 0; j < 4; j++) {
  147. video::SColor c = cloudyfogcolor.getInterpolated(m_skycolor, 0.45);
  148. vertices[0] = video::S3DVertex(-1, 0.08, -1, 0, 0, 1, c, t, t);
  149. vertices[1] = video::S3DVertex( 1, 0.08, -1, 0, 0, 1, c, o, t);
  150. vertices[2] = video::S3DVertex( 1, 0.12, -1, 0, 0, 1, c, o, o);
  151. vertices[3] = video::S3DVertex(-1, 0.12, -1, 0, 0, 1, c, t, o);
  152. for (video::S3DVertex &vertex : vertices) {
  153. if (j == 0)
  154. // Don't switch
  155. {}
  156. else if (j == 1)
  157. // Switch from -Z (south) to +X (east)
  158. vertex.Pos.rotateXZBy(90);
  159. else if (j == 2)
  160. // Switch from -Z (south) to -X (west)
  161. vertex.Pos.rotateXZBy(-90);
  162. else
  163. // Switch from -Z (south) to +Z (north)
  164. vertex.Pos.rotateXZBy(-180);
  165. }
  166. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  167. }
  168. // Draw far cloudy fog thing
  169. for (u32 j = 0; j < 4; j++) {
  170. video::SColor c = cloudyfogcolor;
  171. vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 0, 1, c, t, t);
  172. vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 0, 1, c, o, t);
  173. vertices[2] = video::S3DVertex( 1, 0.08, -1, 0, 0, 1, c, o, o);
  174. vertices[3] = video::S3DVertex(-1, 0.08, -1, 0, 0, 1, c, t, o);
  175. for (video::S3DVertex &vertex : vertices) {
  176. if (j == 0)
  177. // Don't switch
  178. {}
  179. else if (j == 1)
  180. // Switch from -Z (south) to +X (east)
  181. vertex.Pos.rotateXZBy(90);
  182. else if (j == 2)
  183. // Switch from -Z (south) to -X (west)
  184. vertex.Pos.rotateXZBy(-90);
  185. else
  186. // Switch from -Z (south) to +Z (north)
  187. vertex.Pos.rotateXZBy(-180);
  188. }
  189. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  190. }
  191. // Draw bottom far cloudy fog thing
  192. video::SColor c = cloudyfogcolor;
  193. vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 1, 0, c, t, t);
  194. vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 1, 0, c, o, t);
  195. vertices[2] = video::S3DVertex( 1, -1.0, 1, 0, 1, 0, c, o, o);
  196. vertices[3] = video::S3DVertex(-1, -1.0, 1, 0, 1, 0, c, t, o);
  197. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  198. // If sun, moon and stars are (temporarily) disabled, abort here
  199. if (!m_bodies_visible)
  200. return;
  201. driver->setMaterial(m_materials[2]);
  202. // Draw sunrise/sunset horizon glow texture (textures/base/pack/sunrisebg.png)
  203. {
  204. float mid1 = 0.25;
  205. float mid = wicked_time_of_day < 0.5 ? mid1 : (1.0 - mid1);
  206. float a_ = 1.0 - fabs(wicked_time_of_day - mid) * 35.0;
  207. float a = easeCurve(MYMAX(0, MYMIN(1, a_)));
  208. //std::cerr<<"a_="<<a_<<" a="<<a<<std::endl;
  209. video::SColor c(255, 255, 255, 255);
  210. float y = -(1.0 - a) * 0.22;
  211. vertices[0] = video::S3DVertex(-1, -0.05 + y, -1, 0, 0, 1, c, t, t);
  212. vertices[1] = video::S3DVertex( 1, -0.05 + y, -1, 0, 0, 1, c, o, t);
  213. vertices[2] = video::S3DVertex( 1, 0.2 + y, -1, 0, 0, 1, c, o, o);
  214. vertices[3] = video::S3DVertex(-1, 0.2 + y, -1, 0, 0, 1, c, t, o);
  215. for (video::S3DVertex &vertex : vertices) {
  216. if (wicked_time_of_day < 0.5)
  217. // Switch from -Z (south) to +X (east)
  218. vertex.Pos.rotateXZBy(90);
  219. else
  220. // Switch from -Z (south) to -X (west)
  221. vertex.Pos.rotateXZBy(-90);
  222. }
  223. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  224. }
  225. // Draw sun
  226. if (wicked_time_of_day > 0.15 && wicked_time_of_day < 0.85) {
  227. if (!m_sun_texture) {
  228. driver->setMaterial(m_materials[1]);
  229. float d = sunsize * 1.7;
  230. video::SColor c = suncolor;
  231. c.setAlpha(0.05 * 255);
  232. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
  233. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
  234. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
  235. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
  236. for (video::S3DVertex &vertex : vertices) {
  237. // Switch from -Z (south) to +X (east)
  238. vertex.Pos.rotateXZBy(90);
  239. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  240. }
  241. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  242. d = sunsize * 1.2;
  243. c = suncolor;
  244. c.setAlpha(0.15 * 255);
  245. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
  246. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
  247. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
  248. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
  249. for (video::S3DVertex &vertex : vertices) {
  250. // Switch from -Z (south) to +X (east)
  251. vertex.Pos.rotateXZBy(90);
  252. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  253. }
  254. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  255. d = sunsize;
  256. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor, t, t);
  257. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor, o, t);
  258. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor, o, o);
  259. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor, t, o);
  260. for (video::S3DVertex &vertex : vertices) {
  261. // Switch from -Z (south) to +X (east)
  262. vertex.Pos.rotateXZBy(90);
  263. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  264. }
  265. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  266. d = sunsize * 0.7;
  267. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, suncolor2, t, t);
  268. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, suncolor2, o, t);
  269. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, suncolor2, o, o);
  270. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, suncolor2, t, o);
  271. for (video::S3DVertex &vertex : vertices) {
  272. // Switch from -Z (south) to +X (east)
  273. vertex.Pos.rotateXZBy(90);
  274. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  275. }
  276. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  277. } else {
  278. driver->setMaterial(m_materials[3]);
  279. float d = sunsize * 1.7;
  280. video::SColor c;
  281. if (m_sun_tonemap)
  282. c = video::SColor (0, 0, 0, 0);
  283. else
  284. c = video::SColor (255, 255, 255, 255);
  285. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
  286. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
  287. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
  288. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
  289. for (video::S3DVertex &vertex : vertices) {
  290. // Switch from -Z (south) to +X (east)
  291. vertex.Pos.rotateXZBy(90);
  292. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  293. }
  294. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  295. }
  296. }
  297. // Draw moon
  298. if (wicked_time_of_day < 0.3 || wicked_time_of_day > 0.7) {
  299. if (!m_moon_texture) {
  300. driver->setMaterial(m_materials[1]);
  301. float d = moonsize * 1.9;
  302. video::SColor c = mooncolor;
  303. c.setAlpha(0.05 * 255);
  304. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
  305. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
  306. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
  307. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
  308. for (video::S3DVertex &vertex : vertices) {
  309. // Switch from -Z (south) to -X (west)
  310. vertex.Pos.rotateXZBy(-90);
  311. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  312. }
  313. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  314. d = moonsize * 1.3;
  315. c = mooncolor;
  316. c.setAlpha(0.15 * 255);
  317. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
  318. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
  319. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
  320. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
  321. for (video::S3DVertex &vertex : vertices) {
  322. // Switch from -Z (south) to -X (west)
  323. vertex.Pos.rotateXZBy(-90);
  324. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  325. }
  326. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  327. d = moonsize;
  328. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor, t, t);
  329. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, mooncolor, o, t);
  330. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, mooncolor, o, o);
  331. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, mooncolor, t, o);
  332. for (video::S3DVertex &vertex : vertices) {
  333. // Switch from -Z (south) to -X (west)
  334. vertex.Pos.rotateXZBy(-90);
  335. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  336. }
  337. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  338. float d2 = moonsize * 0.6;
  339. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, mooncolor2, t, t);
  340. vertices[1] = video::S3DVertex( d2,-d, -1, 0, 0, 1, mooncolor2, o, t);
  341. vertices[2] = video::S3DVertex( d2, d2, -1, 0, 0, 1, mooncolor2, o, o);
  342. vertices[3] = video::S3DVertex(-d, d2, -1, 0, 0, 1, mooncolor2, t, o);
  343. for (video::S3DVertex &vertex : vertices) {
  344. // Switch from -Z (south) to -X (west)
  345. vertex.Pos.rotateXZBy(-90);
  346. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  347. }
  348. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  349. } else {
  350. driver->setMaterial(m_materials[4]);
  351. float d = moonsize * 1.9;
  352. video::SColor c;
  353. if (m_moon_tonemap)
  354. c = video::SColor (0, 0, 0, 0);
  355. else
  356. c = video::SColor (255, 255, 255, 255);
  357. vertices[0] = video::S3DVertex(-d, -d, -1, 0, 0, 1, c, t, t);
  358. vertices[1] = video::S3DVertex( d, -d, -1, 0, 0, 1, c, o, t);
  359. vertices[2] = video::S3DVertex( d, d, -1, 0, 0, 1, c, o, o);
  360. vertices[3] = video::S3DVertex(-d, d, -1, 0, 0, 1, c, t, o);
  361. for (video::S3DVertex &vertex : vertices) {
  362. // Switch from -Z (south) to -X (west)
  363. vertex.Pos.rotateXZBy(-90);
  364. vertex.Pos.rotateXYBy(wicked_time_of_day * 360 - 90);
  365. }
  366. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  367. }
  368. }
  369. // Draw stars
  370. do {
  371. driver->setMaterial(m_materials[1]);
  372. float starbrightness = MYMAX(0, MYMIN(1,
  373. (0.285 - fabs(wicked_time_of_day < 0.5 ?
  374. wicked_time_of_day : (1.0 - wicked_time_of_day))) * 10));
  375. float f = starbrightness;
  376. float d = 0.007;
  377. video::SColor starcolor(255, f * 90, f * 90, f * 90);
  378. if (starcolor.getBlue() < m_skycolor.getBlue())
  379. break;
  380. u16 indices[SKY_STAR_COUNT * 4];
  381. video::S3DVertex vertices[SKY_STAR_COUNT * 4];
  382. for (u32 i = 0; i < SKY_STAR_COUNT; i++) {
  383. indices[i * 4 + 0] = i * 4 + 0;
  384. indices[i * 4 + 1] = i * 4 + 1;
  385. indices[i * 4 + 2] = i * 4 + 2;
  386. indices[i * 4 + 3] = i * 4 + 3;
  387. v3f p = m_stars[i];
  388. core::CMatrix4<f32> a;
  389. a.buildRotateFromTo(v3f(0, 1, 0), v3f(d, 1 + d / 2, 0));
  390. v3f p1 = p;
  391. a.rotateVect(p1);
  392. a.buildRotateFromTo(v3f(0, 1, 0), v3f(d, 1, d));
  393. v3f p2 = p;
  394. a.rotateVect(p2);
  395. a.buildRotateFromTo(v3f(0, 1, 0), v3f(0, 1 - d / 2, d));
  396. v3f p3 = p;
  397. a.rotateVect(p3);
  398. p.rotateXYBy(wicked_time_of_day * 360 - 90);
  399. p1.rotateXYBy(wicked_time_of_day * 360 - 90);
  400. p2.rotateXYBy(wicked_time_of_day * 360 - 90);
  401. p3.rotateXYBy(wicked_time_of_day * 360 - 90);
  402. vertices[i * 4 + 0].Pos = p;
  403. vertices[i * 4 + 0].Color = starcolor;
  404. vertices[i * 4 + 1].Pos = p1;
  405. vertices[i * 4 + 1].Color = starcolor;
  406. vertices[i * 4 + 2].Pos = p2;
  407. vertices[i * 4 + 2].Color = starcolor;
  408. vertices[i * 4 + 3].Pos = p3;
  409. vertices[i * 4 + 3].Color = starcolor;
  410. }
  411. driver->drawVertexPrimitiveList(vertices, SKY_STAR_COUNT * 4,
  412. indices, SKY_STAR_COUNT, video::EVT_STANDARD,
  413. scene::EPT_QUADS, video::EIT_16BIT);
  414. } while(false);
  415. // Draw far cloudy fog thing below east and west horizons
  416. for (u32 j = 0; j < 2; j++) {
  417. video::SColor c = cloudyfogcolor;
  418. vertices[0] = video::S3DVertex(-1, -1.0, -1, 0, 0, 1, c, t, t);
  419. vertices[1] = video::S3DVertex( 1, -1.0, -1, 0, 0, 1, c, o, t);
  420. vertices[2] = video::S3DVertex( 1, -0.02, -1, 0, 0, 1, c, o, o);
  421. vertices[3] = video::S3DVertex(-1, -0.02, -1, 0, 0, 1, c, t, o);
  422. for (video::S3DVertex &vertex : vertices) {
  423. //if (wicked_time_of_day < 0.5)
  424. if (j == 0)
  425. // Switch from -Z (south) to +X (east)
  426. vertex.Pos.rotateXZBy(90);
  427. else
  428. // Switch from -Z (south) to -X (west)
  429. vertex.Pos.rotateXZBy(-90);
  430. }
  431. driver->drawIndexedTriangleFan(&vertices[0], 4, indices, 2);
  432. }
  433. }
  434. }
  435. void Sky::update(float time_of_day, float time_brightness,
  436. float direct_brightness, bool sunlight_seen,
  437. CameraMode cam_mode, float yaw, float pitch)
  438. {
  439. // Stabilize initial brightness and color values by flooding updates
  440. if (m_first_update) {
  441. /*dstream<<"First update with time_of_day="<<time_of_day
  442. <<" time_brightness="<<time_brightness
  443. <<" direct_brightness="<<direct_brightness
  444. <<" sunlight_seen="<<sunlight_seen<<std::endl;*/
  445. m_first_update = false;
  446. for (u32 i = 0; i < 100; i++) {
  447. update(time_of_day, time_brightness, direct_brightness,
  448. sunlight_seen, cam_mode, yaw, pitch);
  449. }
  450. return;
  451. }
  452. m_time_of_day = time_of_day;
  453. m_time_brightness = time_brightness;
  454. m_sunlight_seen = sunlight_seen;
  455. m_bodies_visible = true;
  456. bool is_dawn = (time_brightness >= 0.20 && time_brightness < 0.35);
  457. /*
  458. Development colours
  459. video::SColorf bgcolor_bright_normal_f(170. / 255, 200. / 255, 230. / 255, 1.0);
  460. video::SColorf bgcolor_bright_dawn_f(0.666, 200. / 255 * 0.7, 230. / 255 * 0.5, 1.0);
  461. video::SColorf bgcolor_bright_dawn_f(0.666, 0.549, 0.220, 1.0);
  462. video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.0, 1.0);
  463. video::SColorf bgcolor_bright_dawn_f(0.666 * 1.2, 0.549 * 1.0, 0.220 * 1.2, 1.0);
  464. video::SColorf cloudcolor_bright_dawn_f(1.0, 0.591, 0.4);
  465. video::SColorf cloudcolor_bright_dawn_f(1.0, 0.65, 0.44);
  466. video::SColorf cloudcolor_bright_dawn_f(1.0, 0.7, 0.5);
  467. */
  468. video::SColorf bgcolor_bright_normal_f = video::SColor(255, 155, 193, 240);
  469. video::SColorf bgcolor_bright_indoor_f = video::SColor(255, 100, 100, 100);
  470. video::SColorf bgcolor_bright_dawn_f = video::SColor(255, 186, 193, 240);
  471. video::SColorf bgcolor_bright_night_f = video::SColor(255, 64, 144, 255);
  472. video::SColorf skycolor_bright_normal_f = video::SColor(255, 140, 186, 250);
  473. video::SColorf skycolor_bright_dawn_f = video::SColor(255, 180, 186, 250);
  474. video::SColorf skycolor_bright_night_f = video::SColor(255, 0, 107, 255);
  475. // pure white: becomes "diffuse light component" for clouds
  476. video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 255, 255, 255);
  477. // dawn-factoring version of pure white (note: R is above 1.0)
  478. video::SColorf cloudcolor_bright_dawn_f(255.0f/240.0f, 223.0f/240.0f, 191.0f/255.0f);
  479. float cloud_color_change_fraction = 0.95;
  480. if (sunlight_seen) {
  481. if (fabs(time_brightness - m_brightness) < 0.2) {
  482. m_brightness = m_brightness * 0.95 + time_brightness * 0.05;
  483. } else {
  484. m_brightness = m_brightness * 0.80 + time_brightness * 0.20;
  485. cloud_color_change_fraction = 0.0;
  486. }
  487. } else {
  488. if (direct_brightness < m_brightness)
  489. m_brightness = m_brightness * 0.95 + direct_brightness * 0.05;
  490. else
  491. m_brightness = m_brightness * 0.98 + direct_brightness * 0.02;
  492. }
  493. m_clouds_visible = true;
  494. float color_change_fraction = 0.98;
  495. if (sunlight_seen) {
  496. if (is_dawn) { // Dawn
  497. m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
  498. bgcolor_bright_dawn_f, color_change_fraction);
  499. m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
  500. skycolor_bright_dawn_f, color_change_fraction);
  501. m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
  502. cloudcolor_bright_dawn_f, color_change_fraction);
  503. } else {
  504. if (time_brightness < 0.07) { // Night
  505. m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
  506. bgcolor_bright_night_f, color_change_fraction);
  507. m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
  508. skycolor_bright_night_f, color_change_fraction);
  509. } else { // Day
  510. m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
  511. bgcolor_bright_normal_f, color_change_fraction);
  512. m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
  513. skycolor_bright_normal_f, color_change_fraction);
  514. }
  515. m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
  516. cloudcolor_bright_normal_f, color_change_fraction);
  517. }
  518. } else {
  519. m_bgcolor_bright_f = m_bgcolor_bright_f.getInterpolated(
  520. bgcolor_bright_indoor_f, color_change_fraction);
  521. m_skycolor_bright_f = m_skycolor_bright_f.getInterpolated(
  522. bgcolor_bright_indoor_f, color_change_fraction);
  523. m_cloudcolor_bright_f = m_cloudcolor_bright_f.getInterpolated(
  524. cloudcolor_bright_normal_f, color_change_fraction);
  525. m_clouds_visible = false;
  526. }
  527. video::SColor bgcolor_bright = m_bgcolor_bright_f.toSColor();
  528. m_bgcolor = video::SColor(
  529. 255,
  530. bgcolor_bright.getRed() * m_brightness,
  531. bgcolor_bright.getGreen() * m_brightness,
  532. bgcolor_bright.getBlue() * m_brightness
  533. );
  534. video::SColor skycolor_bright = m_skycolor_bright_f.toSColor();
  535. m_skycolor = video::SColor(
  536. 255,
  537. skycolor_bright.getRed() * m_brightness,
  538. skycolor_bright.getGreen() * m_brightness,
  539. skycolor_bright.getBlue() * m_brightness
  540. );
  541. // Horizon coloring based on sun and moon direction during sunset and sunrise
  542. video::SColor pointcolor = video::SColor(m_bgcolor.getAlpha(), 255, 255, 255);
  543. if (m_directional_colored_fog) {
  544. if (m_horizon_blend() != 0) {
  545. // Calculate hemisphere value from yaw, (inverted in third person front view)
  546. s8 dir_factor = 1;
  547. if (cam_mode > CAMERA_MODE_THIRD)
  548. dir_factor = -1;
  549. f32 pointcolor_blend = wrapDegrees_0_360(yaw * dir_factor + 90);
  550. if (pointcolor_blend > 180)
  551. pointcolor_blend = 360 - pointcolor_blend;
  552. pointcolor_blend /= 180;
  553. // Bound view angle to determine where transition starts and ends
  554. pointcolor_blend = rangelim(1 - pointcolor_blend * 1.375, 0, 1 / 1.375) *
  555. 1.375;
  556. // Combine the colors when looking up or down, otherwise turning looks weird
  557. pointcolor_blend += (0.5 - pointcolor_blend) *
  558. (1 - MYMIN((90 - std::fabs(pitch)) / 90 * 1.5, 1));
  559. // Invert direction to match where the sun and moon are rising
  560. if (m_time_of_day > 0.5)
  561. pointcolor_blend = 1 - pointcolor_blend;
  562. // Horizon colors of sun and moon
  563. f32 pointcolor_light = rangelim(m_time_brightness * 3, 0.2, 1);
  564. video::SColorf pointcolor_sun_f(1, 1, 1, 1);
  565. if (m_sun_tonemap) {
  566. pointcolor_sun_f.r = pointcolor_light *
  567. (float)m_materials[3].EmissiveColor.getRed() / 255;
  568. pointcolor_sun_f.b = pointcolor_light *
  569. (float)m_materials[3].EmissiveColor.getBlue() / 255;
  570. pointcolor_sun_f.g = pointcolor_light *
  571. (float)m_materials[3].EmissiveColor.getGreen() / 255;
  572. } else {
  573. pointcolor_sun_f.r = pointcolor_light * 1;
  574. pointcolor_sun_f.b = pointcolor_light *
  575. (0.25 + (rangelim(m_time_brightness, 0.25, 0.75) - 0.25) * 2 * 0.75);
  576. pointcolor_sun_f.g = pointcolor_light * (pointcolor_sun_f.b * 0.375 +
  577. (rangelim(m_time_brightness, 0.05, 0.15) - 0.05) * 10 * 0.625);
  578. }
  579. video::SColorf pointcolor_moon_f(0.5 * pointcolor_light,
  580. 0.6 * pointcolor_light, 0.8 * pointcolor_light, 1);
  581. if (m_moon_tonemap) {
  582. pointcolor_moon_f.r = pointcolor_light *
  583. (float)m_materials[4].EmissiveColor.getRed() / 255;
  584. pointcolor_moon_f.b = pointcolor_light *
  585. (float)m_materials[4].EmissiveColor.getBlue() / 255;
  586. pointcolor_moon_f.g = pointcolor_light *
  587. (float)m_materials[4].EmissiveColor.getGreen() / 255;
  588. }
  589. video::SColor pointcolor_sun = pointcolor_sun_f.toSColor();
  590. video::SColor pointcolor_moon = pointcolor_moon_f.toSColor();
  591. // Calculate the blend color
  592. pointcolor = m_mix_scolor(pointcolor_moon, pointcolor_sun, pointcolor_blend);
  593. }
  594. m_bgcolor = m_mix_scolor(m_bgcolor, pointcolor, m_horizon_blend() * 0.5);
  595. m_skycolor = m_mix_scolor(m_skycolor, pointcolor, m_horizon_blend() * 0.25);
  596. }
  597. float cloud_direct_brightness = 0;
  598. if (sunlight_seen) {
  599. if (!m_directional_colored_fog) {
  600. cloud_direct_brightness = time_brightness;
  601. if (time_brightness >= 0.2 && time_brightness < 0.7)
  602. cloud_direct_brightness *= 1.3;
  603. } else {
  604. cloud_direct_brightness = MYMIN(m_horizon_blend() * 0.15 +
  605. m_time_brightness, 1);
  606. }
  607. } else {
  608. cloud_direct_brightness = direct_brightness;
  609. }
  610. m_cloud_brightness = m_cloud_brightness * cloud_color_change_fraction +
  611. cloud_direct_brightness * (1.0 - cloud_color_change_fraction);
  612. m_cloudcolor_f = video::SColorf(
  613. m_cloudcolor_bright_f.r * m_cloud_brightness,
  614. m_cloudcolor_bright_f.g * m_cloud_brightness,
  615. m_cloudcolor_bright_f.b * m_cloud_brightness,
  616. 1.0
  617. );
  618. if (m_directional_colored_fog) {
  619. m_cloudcolor_f = m_mix_scolorf(m_cloudcolor_f,
  620. video::SColorf(pointcolor), m_horizon_blend() * 0.25);
  621. }
  622. }