2
0

sky.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. /*
  2. * Copyright 2017 Stanislav Pidhorskyi. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. /*
  6. * This example demonstrates:
  7. * - Usage of Perez sky model [1] to render a dynamic sky.
  8. * - Rendering a mesh with a lightmap, shading of which is driven by the same parameters as the sky.
  9. *
  10. * Typically, the sky is rendered using cubemaps or other environment maps.
  11. * This approach can provide a high-quality sky, but the downside is that the
  12. * image is static. To achieve daytime changes in sky appearance, there is a need
  13. * in a dynamic model.
  14. *
  15. * Perez "An All-Weather Model for Sky Luminance Distribution" is a simple,
  16. * but good enough model which is, in essence, a function that
  17. * interpolates a sky color. As input, it requires several turbidity
  18. * coefficients, a color at zenith and direction to the sun.
  19. * Turbidity coefficients are taken from [2], which are computed using more
  20. * complex physically based models. Color at zenith depends on daytime and can
  21. * vary depending on many factors.
  22. *
  23. * In the code below, there are two tables that contain sky and sun luminance
  24. * which were computed using code from [3]. Luminance in those tables
  25. * represents actual scale of light energy that comes from sun compared to
  26. * the sky.
  27. *
  28. * The sky is driven by luminance of the sky, while the material of the
  29. * landscape is driven by both, the luminance of the sky and the sun. The
  30. * lightening model is very simple and consists of two parts: directional
  31. * light and hemisphere light. The first is used for the sun while the second
  32. * is used for the sky. Additionally, the second part is modulated by a
  33. * lightmap to achieve ambient occlusion effect.
  34. *
  35. * References
  36. * ==========
  37. *
  38. * [1] R. Perez, R. Seals, and J. Michalsky."An All-Weather Model for Sky Luminance Distribution".
  39. * Solar Energy, Volume 50, Number 3 (March 1993), pp. 235–245.
  40. *
  41. * [2] A. J. Preetham, Peter Shirley, and Brian Smits. "A Practical Analytic Model for Daylight",
  42. * Proceedings of the 26th Annual Conference on Computer Graphics and Interactive Techniques,
  43. * 1999, pp. 91–100.
  44. * https://www.cs.utah.edu/~shirley/papers/sunsky/sunsky.pdf
  45. *
  46. * [3] E. Lengyel, Game Engine Gems, Volume One. Jones & Bartlett Learning, 2010. pp. 219 - 234
  47. *
  48. */
  49. #include "common.h"
  50. #include "bgfx_utils.h"
  51. #include "imgui/imgui.h"
  52. #include "camera.h"
  53. #include "bounds.h"
  54. #include <map>
  55. namespace
  56. {
  57. // Represents color. Color-space depends on context.
  58. // In the code below, used to represent color in XYZ, and RGB color-space
  59. union Color
  60. {
  61. struct {
  62. float X;
  63. float Y;
  64. float Z;
  65. };
  66. struct {
  67. float r;
  68. float g;
  69. float b;
  70. };
  71. float data[3];
  72. };
  73. // HDTV rec. 709 matrix.
  74. static float M_XYZ2RGB[] =
  75. {
  76. 3.240479f, -0.969256f, 0.055648f,
  77. -1.53715f, 1.875991f, -0.204043f,
  78. -0.49853f, 0.041556f, 1.057311f
  79. };
  80. // Converts color repesentation from CIE XYZ to RGB color-space.
  81. Color XYZToRGB(const Color& xyz)
  82. {
  83. Color rgb;
  84. rgb.r = M_XYZ2RGB[0] * xyz.X + M_XYZ2RGB[3] * xyz.Y + M_XYZ2RGB[6] * xyz.Z;
  85. rgb.g = M_XYZ2RGB[1] * xyz.X + M_XYZ2RGB[4] * xyz.Y + M_XYZ2RGB[7] * xyz.Z;
  86. rgb.b = M_XYZ2RGB[2] * xyz.X + M_XYZ2RGB[5] * xyz.Y + M_XYZ2RGB[8] * xyz.Z;
  87. return rgb;
  88. };
  89. // Precomputed luminance of sunlight in XYZ colorspace.
  90. // Computed using code from Game Engine Gems, Volume One, chapter 15. Implementation based on Dr. Richard Bird model.
  91. // This table is used for piecewise linear interpolation. Transitions from and to 0.0 at sunset and sunrise are highly inaccurate
  92. static std::map<float, Color> sunLuminanceXYZTable = {
  93. { 5.0f, {{ 0.000000f, 0.000000f, 0.000000f }} },
  94. { 7.0f, {{ 12.703322f, 12.989393f, 9.100411f }} },
  95. { 8.0f, {{ 13.202644f, 13.597814f, 11.524929f }} },
  96. { 9.0f, {{ 13.192974f, 13.597458f, 12.264488f }} },
  97. { 10.0f, {{ 13.132943f, 13.535914f, 12.560032f }} },
  98. { 11.0f, {{ 13.088722f, 13.489535f, 12.692996f }} },
  99. { 12.0f, {{ 13.067827f, 13.467483f, 12.745179f }} },
  100. { 13.0f, {{ 13.069653f, 13.469413f, 12.740822f }} },
  101. { 14.0f, {{ 13.094319f, 13.495428f, 12.678066f }} },
  102. { 15.0f, {{ 13.142133f, 13.545483f, 12.526785f }} },
  103. { 16.0f, {{ 13.201734f, 13.606017f, 12.188001f }} },
  104. { 17.0f, {{ 13.182774f, 13.572725f, 11.311157f }} },
  105. { 18.0f, {{ 12.448635f, 12.672520f, 8.267771f }} },
  106. { 20.0f, {{ 0.000000f, 0.000000f, 0.000000f }} }
  107. };
  108. // Precomputed luminance of sky in the zenith point in XYZ colorspace.
  109. // Computed using code from Game Engine Gems, Volume One, chapter 15. Implementation based on Dr. Richard Bird model.
  110. // This table is used for piecewise linear interpolation. Day/night transitions are highly inaccurate.
  111. // The scale of luminance change in Day/night transitions is not preserved.
  112. // Luminance at night was increased to eliminate need the of HDR render.
  113. static std::map<float, Color> skyLuminanceXYZTable = {
  114. { 0.0f, {{ 0.308f, 0.308f, 0.411f }} },
  115. { 1.0f, {{ 0.308f, 0.308f, 0.410f }} },
  116. { 2.0f, {{ 0.301f, 0.301f, 0.402f }} },
  117. { 3.0f, {{ 0.287f, 0.287f, 0.382f }} },
  118. { 4.0f, {{ 0.258f, 0.258f, 0.344f }} },
  119. { 5.0f, {{ 0.258f, 0.258f, 0.344f }} },
  120. { 7.0f, {{ 0.962851f, 1.000000f, 1.747835f }} },
  121. { 8.0f, {{ 0.967787f, 1.000000f, 1.776762f }} },
  122. { 9.0f, {{ 0.970173f, 1.000000f, 1.788413f }} },
  123. { 10.0f, {{ 0.971431f, 1.000000f, 1.794102f }} },
  124. { 11.0f, {{ 0.972099f, 1.000000f, 1.797096f }} },
  125. { 12.0f, {{ 0.972385f, 1.000000f, 1.798389f }} },
  126. { 13.0f, {{ 0.972361f, 1.000000f, 1.798278f }} },
  127. { 14.0f, {{ 0.972020f, 1.000000f, 1.796740f }} },
  128. { 15.0f, {{ 0.971275f, 1.000000f, 1.793407f }} },
  129. { 16.0f, {{ 0.969885f, 1.000000f, 1.787078f }} },
  130. { 17.0f, {{ 0.967216f, 1.000000f, 1.773758f }} },
  131. { 18.0f, {{ 0.961668f, 1.000000f, 1.739891f }} },
  132. { 20.0f, {{ 0.264f, 0.264f, 0.352f }} },
  133. { 21.0f, {{ 0.264f, 0.264f, 0.352f }} },
  134. { 22.0f, {{ 0.290f, 0.290f, 0.386f }} },
  135. { 23.0f, {{ 0.303f, 0.303f, 0.404f }} }
  136. };
  137. // Turbidity tables. Taken from:
  138. // A. J. Preetham, P. Shirley, and B. Smits. A Practical Analytic Model for Daylight. SIGGRAPH ’99
  139. // Coefficients correspond to xyY colorspace.
  140. static Color ABCDE[] =
  141. {
  142. {{ -0.2592f, -0.2608f, -1.4630f }},
  143. {{ 0.0008f, 0.0092f, 0.4275f }},
  144. {{ 0.2125f, 0.2102f, 5.3251f }},
  145. {{ -0.8989f, -1.6537f, -2.5771f }},
  146. {{ 0.0452f, 0.0529f, 0.3703f }}
  147. };
  148. static Color ABCDE_t[] =
  149. {
  150. {{ -0.0193f, -0.0167f, 0.1787f }},
  151. {{ -0.0665f, -0.0950f, -0.3554f }},
  152. {{ -0.0004f, -0.0079f, -0.0227f }},
  153. {{ -0.0641f, -0.0441f, 0.1206f }},
  154. {{ -0.0033f, -0.0109f, -0.0670f }}
  155. };
  156. // Performs piecewise linear interpolation of a Color parameter.
  157. class DynamicValueController
  158. {
  159. typedef Color ValueType;
  160. typedef std::map<float, ValueType> KeyMap;
  161. public:
  162. DynamicValueController() {};
  163. ~DynamicValueController() {};
  164. void SetMap(const KeyMap& keymap)
  165. {
  166. m_keyMap = keymap;
  167. }
  168. ValueType GetValue(float time) const
  169. {
  170. typename KeyMap::const_iterator itUpper = m_keyMap.upper_bound(time + 1e-6f);
  171. typename KeyMap::const_iterator itLower = itUpper;
  172. --itLower;
  173. if (itLower == m_keyMap.end())
  174. {
  175. return itUpper->second;
  176. }
  177. if (itUpper == m_keyMap.end())
  178. {
  179. return itLower->second;
  180. }
  181. float lowerTime = itLower->first;
  182. const ValueType& lowerVal = itLower->second;
  183. float upperTime = itUpper->first;
  184. const ValueType& upperVal = itUpper->second;
  185. if (lowerTime == upperTime)
  186. {
  187. return lowerVal;
  188. }
  189. return interpolate(lowerTime, lowerVal, upperTime, upperVal, time);
  190. };
  191. void Clear()
  192. {
  193. m_keyMap.clear();
  194. };
  195. private:
  196. const ValueType interpolate(float lowerTime, const ValueType& lowerVal, float upperTime, const ValueType& upperVal, float time) const
  197. {
  198. float x = (time - lowerTime) / (upperTime - lowerTime);
  199. ValueType result;
  200. bx::vec3Lerp(result.data, lowerVal.data, upperVal.data, x);
  201. return result;
  202. };
  203. KeyMap m_keyMap;
  204. };
  205. // Controls sun position according to time, month, and observer's latitude.
  206. // Sun position computation based on Earth's orbital elements: https://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html
  207. class SunController
  208. {
  209. public:
  210. enum Month : int
  211. {
  212. January = 0,
  213. February,
  214. March,
  215. April,
  216. May,
  217. June,
  218. July,
  219. August,
  220. September,
  221. October,
  222. November,
  223. December
  224. };
  225. SunController():
  226. m_latitude(50.0f),
  227. m_month(June),
  228. m_eclipticObliquity(bx::toRad(23.4f)),
  229. m_delta(0.0f)
  230. {
  231. m_northDirection[0] = 1.0;
  232. m_northDirection[1] = 0.0;
  233. m_northDirection[2] = 0.0;
  234. m_upvector[0] = 0.0f;
  235. m_upvector[1] = 1.0f;
  236. m_upvector[2] = 0.0f;
  237. }
  238. void Update(float time)
  239. {
  240. CalculateSunOrbit();
  241. UpdateSunPosition(time - 12.0f);
  242. }
  243. float m_northDirection[3];
  244. float m_sunDirection[4];
  245. float m_upvector[3];
  246. float m_latitude;
  247. Month m_month;
  248. private:
  249. void CalculateSunOrbit()
  250. {
  251. float day = 30.0f * m_month + 15.0f;
  252. float lambda = 280.46f + 0.9856474f * day;
  253. lambda = bx::toRad(lambda);
  254. m_delta = bx::fasin(bx::fsin(m_eclipticObliquity) * bx::fsin(lambda));
  255. }
  256. void UpdateSunPosition(float hour)
  257. {
  258. float latitude = bx::toRad(m_latitude);
  259. float h = hour * bx::kPi / 12.0f;
  260. float azimuth = bx::fatan2(
  261. bx::fsin(h),
  262. bx::fcos(h) * bx::fsin(latitude) - bx::ftan(m_delta) * bx::fcos(latitude)
  263. );
  264. float altitude = bx::fasin(
  265. bx::fsin(latitude) * bx::fsin(m_delta) + bx::fcos(latitude) * bx::fcos(m_delta) * bx::fcos(h)
  266. );
  267. float rotation[4];
  268. bx::quatRotateAxis(rotation, m_upvector, -azimuth);
  269. float direction[3];
  270. bx::vec3MulQuat(direction, m_northDirection, rotation);
  271. float v[3];
  272. bx::vec3Cross(v, m_upvector, direction);
  273. bx::quatRotateAxis(rotation, v, altitude);
  274. bx::vec3MulQuat(m_sunDirection, direction, rotation);
  275. }
  276. float m_eclipticObliquity;
  277. float m_delta;
  278. };
  279. struct ScreenPosVertex
  280. {
  281. float m_x;
  282. float m_y;
  283. static void init()
  284. {
  285. ms_decl
  286. .begin()
  287. .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
  288. .end();
  289. }
  290. static bgfx::VertexDecl ms_decl;
  291. };
  292. bgfx::VertexDecl ScreenPosVertex::ms_decl;
  293. // Renders a screen-space grid of triangles.
  294. // Because of performance reasons, and because sky color is smooth, sky color is computed in vertex shader.
  295. // 32x32 is a reasonable size for the grid to have smooth enough colors.
  296. struct ProceduralSky
  297. {
  298. void init(int verticalCount, int horizontalCount)
  299. {
  300. // Create vertex stream declaration.
  301. ScreenPosVertex::init();
  302. m_skyProgram = loadProgram("vs_sky", "fs_sky");
  303. m_skyProgram_colorBandingFix = loadProgram("vs_sky", "fs_sky_color_banding_fix");
  304. m_preventBanding = true;
  305. bx::AllocatorI* allocator = entry::getAllocator();
  306. ScreenPosVertex* vertices = (ScreenPosVertex*)BX_ALLOC(allocator
  307. , verticalCount * horizontalCount * sizeof(ScreenPosVertex)
  308. );
  309. for (int i = 0; i < verticalCount; i++)
  310. {
  311. for (int j = 0; j < horizontalCount; j++)
  312. {
  313. ScreenPosVertex& v = vertices[i * verticalCount + j];
  314. v.m_x = float(j) / (horizontalCount - 1) * 2.0f - 1.0f;
  315. v.m_y = float(i) / (verticalCount - 1) * 2.0f - 1.0f;
  316. }
  317. }
  318. uint16_t* indices = (uint16_t*)BX_ALLOC(allocator
  319. , (verticalCount - 1) * (horizontalCount - 1) * 6 * sizeof(uint16_t)
  320. );
  321. int k = 0;
  322. for (int i = 0; i < verticalCount - 1; i++)
  323. {
  324. for (int j = 0; j < horizontalCount - 1; j++)
  325. {
  326. indices[k++] = (uint16_t)(j + 0 + horizontalCount * (i + 0));
  327. indices[k++] = (uint16_t)(j + 1 + horizontalCount * (i + 0));
  328. indices[k++] = (uint16_t)(j + 0 + horizontalCount * (i + 1));
  329. indices[k++] = (uint16_t)(j + 1 + horizontalCount * (i + 0));
  330. indices[k++] = (uint16_t)(j + 1 + horizontalCount * (i + 1));
  331. indices[k++] = (uint16_t)(j + 0 + horizontalCount * (i + 1));
  332. }
  333. }
  334. m_vbh = bgfx::createVertexBuffer(bgfx::copy(vertices, sizeof(ScreenPosVertex) * verticalCount * horizontalCount), ScreenPosVertex::ms_decl);
  335. m_ibh = bgfx::createIndexBuffer(bgfx::copy(indices, sizeof(uint16_t) * k));
  336. BX_FREE(allocator, indices);
  337. BX_FREE(allocator, vertices);
  338. }
  339. void shutdown()
  340. {
  341. bgfx::destroy(m_ibh);
  342. bgfx::destroy(m_vbh);
  343. bgfx::destroy(m_skyProgram);
  344. bgfx::destroy(m_skyProgram_colorBandingFix);
  345. }
  346. void draw()
  347. {
  348. bgfx::setState(BGFX_STATE_RGB_WRITE | BGFX_STATE_DEPTH_TEST_EQUAL);
  349. bgfx::setIndexBuffer(m_ibh);
  350. bgfx::setVertexBuffer(0, m_vbh);
  351. bgfx::submit(0, m_preventBanding ? m_skyProgram_colorBandingFix : m_skyProgram);
  352. }
  353. bgfx::VertexBufferHandle m_vbh;
  354. bgfx::IndexBufferHandle m_ibh;
  355. bgfx::ProgramHandle m_skyProgram;
  356. bgfx::ProgramHandle m_skyProgram_colorBandingFix;
  357. bool m_preventBanding;
  358. };
  359. class ExampleProceduralSky : public entry::AppI
  360. {
  361. public:
  362. ExampleProceduralSky(const char* _name, const char* _description): entry::AppI(_name, _description)
  363. {}
  364. void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
  365. {
  366. Args args(_argc, _argv);
  367. m_width = _width;
  368. m_height = _height;
  369. m_debug = BGFX_DEBUG_NONE;
  370. m_reset = BGFX_RESET_VSYNC;
  371. bgfx::init(args.m_type, args.m_pciId);
  372. bgfx::reset(m_width, m_height, m_reset);
  373. // Enable m_debug text.
  374. bgfx::setDebug(m_debug);
  375. // Set view 0 clear state.
  376. bgfx::setViewClear(0
  377. , BGFX_CLEAR_COLOR | BGFX_CLEAR_DEPTH
  378. , 0x000000ff
  379. , 1.0f
  380. , 0
  381. );
  382. m_sunLuminanceXYZ.SetMap(sunLuminanceXYZTable);
  383. m_skyLuminanceXYZ.SetMap(skyLuminanceXYZTable);
  384. m_mesh = meshLoad("meshes/test_scene.bin");
  385. m_lightmapTexture = loadTexture("textures/lightmap.ktx");
  386. // Imgui.
  387. imguiCreate();
  388. m_timeOffset = bx::getHPCounter();
  389. m_time = 0.0f;
  390. m_timeScale = 1.0f;
  391. s_texLightmap = bgfx::createUniform("s_texLightmap", bgfx::UniformType::Int1);
  392. u_sunLuminance = bgfx::createUniform("u_sunLuminance", bgfx::UniformType::Vec4);
  393. u_skyLuminanceXYZ = bgfx::createUniform("u_skyLuminanceXYZ", bgfx::UniformType::Vec4);
  394. u_skyLuminance = bgfx::createUniform("u_skyLuminance", bgfx::UniformType::Vec4);
  395. u_sunDirection = bgfx::createUniform("u_sunDirection", bgfx::UniformType::Vec4);
  396. u_parameters = bgfx::createUniform("u_parameters", bgfx::UniformType::Vec4);
  397. u_perezCoeff = bgfx::createUniform("u_perezCoeff", bgfx::UniformType::Vec4, 5);
  398. m_landscapeProgram = loadProgram("vs_sky_landscape", "fs_sky_landscape");
  399. m_sky.init(32, 32);
  400. m_sun.Update(0);
  401. cameraCreate();
  402. const float initialPos[3] = { 5.0f, 3.0, 0.0f };
  403. cameraSetPosition(initialPos);
  404. cameraSetVerticalAngle(bx::kPi / 8.0f);
  405. cameraSetHorizontalAngle(-bx::kPi / 3.0f);
  406. m_turbidity = 2.15f;
  407. }
  408. virtual int shutdown() override
  409. {
  410. // Cleanup.
  411. cameraDestroy();
  412. imguiDestroy();
  413. meshUnload(m_mesh);
  414. m_sky.shutdown();
  415. bgfx::destroy(s_texLightmap);
  416. bgfx::destroy(u_sunLuminance);
  417. bgfx::destroy(u_skyLuminanceXYZ);
  418. bgfx::destroy(u_skyLuminance);
  419. bgfx::destroy(u_sunDirection);
  420. bgfx::destroy(u_parameters);
  421. bgfx::destroy(u_perezCoeff);
  422. bgfx::destroy(m_lightmapTexture);
  423. bgfx::destroy(m_landscapeProgram);
  424. bgfx::frame();
  425. // Shutdown bgfx.
  426. bgfx::shutdown();
  427. return 0;
  428. }
  429. void imgui(float _width)
  430. {
  431. ImGui::Begin("ProceduralSky");
  432. ImGui::SetWindowSize(ImVec2(_width, 200.0f) );
  433. ImGui::SliderFloat("Time scale", &m_timeScale, 0.0f, 1.0f);
  434. ImGui::SliderFloat("Time", &m_time, 0.0f, 24.0f);
  435. ImGui::SliderFloat("Latitude", &m_sun.m_latitude, -90.0f, 90.0f);
  436. ImGui::SliderFloat("Turbidity", &m_turbidity, 1.9f, 10.0f);
  437. ImGui::Checkbox("Prevent color banding", &m_sky.m_preventBanding);
  438. const char* items[] = {
  439. "January",
  440. "February",
  441. "March",
  442. "April",
  443. "May",
  444. "June",
  445. "July",
  446. "August",
  447. "September",
  448. "October",
  449. "November",
  450. "December"
  451. };
  452. ImGui::Combo("Month", (int*)&m_sun.m_month, items, 12);
  453. ImGui::End();
  454. }
  455. bool update() override
  456. {
  457. if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState))
  458. {
  459. int64_t now = bx::getHPCounter();
  460. static int64_t last = now;
  461. const int64_t frameTime = now - last;
  462. last = now;
  463. const double freq = double(bx::getHPFrequency());
  464. const float deltaTime = float(frameTime / freq);
  465. m_time += m_timeScale * deltaTime;
  466. m_time = bx::fmod(m_time, 24.0f);
  467. m_sun.Update(m_time);
  468. imguiBeginFrame(m_mouseState.m_mx
  469. , m_mouseState.m_my
  470. , (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0)
  471. | (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0)
  472. | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
  473. , m_mouseState.m_mz
  474. , uint16_t(m_width)
  475. , uint16_t(m_height)
  476. );
  477. showExampleDialog(this);
  478. ImGui::SetNextWindowPos(
  479. ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
  480. , ImGuiCond_FirstUseEver
  481. );
  482. imgui(m_width / 5.0f - 10.0f);
  483. imguiEndFrame();
  484. if (!ImGui::MouseOverArea())
  485. {
  486. // Update camera.
  487. cameraUpdate(deltaTime, m_mouseState);
  488. }
  489. // Set view 0 default viewport.
  490. bgfx::setViewRect(0, 0, 0, uint16_t(m_width), uint16_t(m_height));
  491. float view[16];
  492. cameraGetViewMtx(view);
  493. float proj[16];
  494. bx::mtxProj(proj, 60.0f, float(m_width) / float(m_height), 0.1f, 2000.0f, bgfx::getCaps()->homogeneousDepth);
  495. bgfx::setViewTransform(0, view, proj);
  496. Color sunLuminanceXYZ = m_sunLuminanceXYZ.GetValue(m_time);
  497. Color sunLuminanceRGB = XYZToRGB(sunLuminanceXYZ);
  498. Color skyLuminanceXYZ = m_skyLuminanceXYZ.GetValue(m_time);
  499. Color skyLuminanceRGB = XYZToRGB(skyLuminanceXYZ);
  500. bgfx::setUniform(u_sunLuminance, sunLuminanceRGB.data);
  501. bgfx::setUniform(u_skyLuminanceXYZ, skyLuminanceXYZ.data);
  502. bgfx::setUniform(u_skyLuminance, skyLuminanceRGB.data);
  503. bgfx::setUniform(u_sunDirection, m_sun.m_sunDirection);
  504. float exposition[4] = { 0.02f, 3.0f, 0.1f, m_time };
  505. bgfx::setUniform(u_parameters, exposition);
  506. float perezCoeff[4 * 5];
  507. computePerezCoeff(m_turbidity, perezCoeff);
  508. bgfx::setUniform(u_perezCoeff, perezCoeff, 5);
  509. bgfx::setTexture(0, s_texLightmap, m_lightmapTexture);
  510. meshSubmit(m_mesh, 0, m_landscapeProgram, NULL);
  511. m_sky.draw();
  512. bgfx::frame();
  513. return true;
  514. }
  515. return false;
  516. }
  517. void computePerezCoeff(float turbidity, float* perezCoeff)
  518. {
  519. for (int i = 0; i < 5; ++i)
  520. {
  521. Color tmp;
  522. bx::vec3Mul(tmp.data, ABCDE_t[i].data, turbidity);
  523. bx::vec3Add(perezCoeff + 4 * i, tmp.data, ABCDE[i].data);
  524. perezCoeff[4 * i + 3] = 0.0f;
  525. }
  526. }
  527. bgfx::ProgramHandle m_landscapeProgram;
  528. bgfx::UniformHandle s_texLightmap;
  529. bgfx::TextureHandle m_lightmapTexture;
  530. bgfx::UniformHandle u_sunLuminance;
  531. bgfx::UniformHandle u_skyLuminanceXYZ;
  532. bgfx::UniformHandle u_skyLuminance;
  533. bgfx::UniformHandle u_sunDirection;
  534. bgfx::UniformHandle u_parameters;
  535. bgfx::UniformHandle u_perezCoeff;
  536. ProceduralSky m_sky;
  537. SunController m_sun;
  538. DynamicValueController m_sunLuminanceXYZ;
  539. DynamicValueController m_skyLuminanceXYZ;
  540. uint32_t m_width;
  541. uint32_t m_height;
  542. uint32_t m_debug;
  543. uint32_t m_reset;
  544. Mesh* m_mesh;
  545. entry::MouseState m_mouseState;
  546. float m_time;
  547. float m_timeScale;
  548. int64_t m_timeOffset;
  549. float m_turbidity;
  550. };
  551. } // namespace
  552. ENTRY_IMPLEMENT_MAIN(ExampleProceduralSky, "36-sky", "Perez dynamic sky model.");