sky.cpp 26 KB

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