reflectiveshadowmap.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  1. /*
  2. * Copyright 2016 Joseph Cherlin. All rights reserved.
  3. * License: https://github.com/bkaradzic/bgfx#license-bsd-2-clause
  4. */
  5. #include <common.h>
  6. #include <camera.h>
  7. #include <bgfx_utils.h>
  8. #include <imgui/imgui.h>
  9. #include <bx/rng.h>
  10. namespace
  11. {
  12. /*
  13. * Intro
  14. * =====
  15. *
  16. * RSM (reflective shadow map) is a technique for global illumination.
  17. * It is similar to shadow map. It piggybacks on the shadow map, in fact.
  18. *
  19. * RSM is compatible with any type of lighting which can handle handle
  20. * a lot of point lights. This sample happens to use a deferred renderer,
  21. * but other types would work.
  22. *
  23. * Overview:
  24. *
  25. * - Draw into G-Buffer
  26. * - Draw Shadow Map (with RSM piggybacked on)
  27. * - Populate light buffer
  28. * - Deferred "combine" pass.
  29. *
  30. * Details
  31. * =======
  32. *
  33. * ## G-Buffer
  34. *
  35. * Typical G-Buffer with normals, color, depth.
  36. *
  37. * ## RSM
  38. *
  39. * A typical shadow map, except it also outputs to a "RSM" buffer.
  40. * The RSM contains the color of the item drawn, as well as a scalar value which represents
  41. * how much light would bounce off of the surface if it were hit with light from the origin
  42. * of the shadow map.
  43. *
  44. * ## Light Buffer
  45. *
  46. * We draw a lot of spheres into the light buffer. These spheres are called VPL (virtual
  47. * point lights). VPLs represent bounced light, and let us eliminate the classic "ambient"
  48. * term. Instead of us supplying their world space position in a transform matrix,
  49. * VPLs gain their position from the shadow map from step 2, using an unprojection. They gain
  50. * their color from the RSM. You could also store their position in a buffer while drawing shadows,
  51. * I'm just using depth to keep the sample smaller.
  52. *
  53. * ## Deferred combine
  54. *
  55. * Typical combine used in almost any sort of deferred renderer.
  56. *
  57. * References
  58. * ==========
  59. *
  60. * http: *www.bpeers.com/blog/?itemid=517
  61. *
  62. */
  63. // Render passes
  64. #define RENDER_PASS_GBUFFER 0 // GBuffer for normals and albedo
  65. #define RENDER_PASS_SHADOW_MAP 1 // Draw into the shadow map (RSM and regular shadow map at same time)
  66. #define RENDER_PASS_LIGHT_BUFFER 2 // Light buffer for point lights
  67. #define RENDER_PASS_COMBINE 3 // Directional light and final result
  68. // Gbuffer has multiple render targets
  69. #define GBUFFER_RT_NORMAL 0
  70. #define GBUFFER_RT_COLOR 1
  71. #define GBUFFER_RT_DEPTH 2
  72. // Shadow map has multiple render targets
  73. #define SHADOW_RT_RSM 0 // In this algorithm, shadows write lighting info as well.
  74. #define SHADOW_RT_DEPTH 1 // Shadow maps always write a depth
  75. // Random meshes we draw
  76. #define MODEL_COUNT 222 // In this demo, a model is a mesh plus a transform and a color
  77. #define SHADOW_MAP_DIM 512
  78. #define LIGHT_DIST 10.0f
  79. static const char * s_meshPaths[] =
  80. {
  81. "meshes/cube.bin",
  82. "meshes/orb.bin",
  83. "meshes/column.bin",
  84. "meshes/bunny.bin",
  85. "meshes/tree.bin",
  86. "meshes/hollowcube.bin"
  87. };
  88. static const float s_meshScale[] =
  89. {
  90. 0.25f,
  91. 0.5f,
  92. 0.05f,
  93. 0.5f,
  94. 0.05f,
  95. 0.05f
  96. };
  97. // Vertex layout for our screen space quad (used in deferred rendering)
  98. struct PosTexCoord0Vertex
  99. {
  100. float m_x;
  101. float m_y;
  102. float m_z;
  103. float m_u;
  104. float m_v;
  105. static void init()
  106. {
  107. ms_layout
  108. .begin()
  109. .add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float)
  110. .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
  111. .end();
  112. }
  113. static bgfx::VertexLayout ms_layout;
  114. };
  115. bgfx::VertexLayout PosTexCoord0Vertex::ms_layout;
  116. // Utility function to draw a screen space quad for deferred rendering
  117. void screenSpaceQuad(float _textureWidth, float _textureHeight, float _texelHalf, bool _originBottomLeft, float _width = 1.0f, float _height = 1.0f)
  118. {
  119. if (3 == bgfx::getAvailTransientVertexBuffer(3, PosTexCoord0Vertex::ms_layout) )
  120. {
  121. bgfx::TransientVertexBuffer vb;
  122. bgfx::allocTransientVertexBuffer(&vb, 3, PosTexCoord0Vertex::ms_layout);
  123. PosTexCoord0Vertex* vertex = (PosTexCoord0Vertex*)vb.data;
  124. const float minx = -_width;
  125. const float maxx = _width;
  126. const float miny = 0.0f;
  127. const float maxy = _height*2.0f;
  128. const float texelHalfW = _texelHalf/_textureWidth;
  129. const float texelHalfH = _texelHalf/_textureHeight;
  130. const float minu = -1.0f + texelHalfW;
  131. const float maxu = 1.0f + texelHalfH;
  132. const float zz = 0.0f;
  133. float minv = texelHalfH;
  134. float maxv = 2.0f + texelHalfH;
  135. if (_originBottomLeft)
  136. {
  137. float temp = minv;
  138. minv = maxv;
  139. maxv = temp;
  140. minv -= 1.0f;
  141. maxv -= 1.0f;
  142. }
  143. vertex[0].m_x = minx;
  144. vertex[0].m_y = miny;
  145. vertex[0].m_z = zz;
  146. vertex[0].m_u = minu;
  147. vertex[0].m_v = minv;
  148. vertex[1].m_x = maxx;
  149. vertex[1].m_y = miny;
  150. vertex[1].m_z = zz;
  151. vertex[1].m_u = maxu;
  152. vertex[1].m_v = minv;
  153. vertex[2].m_x = maxx;
  154. vertex[2].m_y = maxy;
  155. vertex[2].m_z = zz;
  156. vertex[2].m_u = maxu;
  157. vertex[2].m_v = maxv;
  158. bgfx::setVertexBuffer(0, &vb);
  159. }
  160. }
  161. class ExampleRSM : public entry::AppI
  162. {
  163. public:
  164. ExampleRSM(const char* _name, const char* _description, const char* _url)
  165. : entry::AppI(_name, _description, _url)
  166. , m_reading(0)
  167. , m_currFrame(UINT32_MAX)
  168. , m_cameraSpin(false)
  169. , m_lightElevation(35.0f)
  170. , m_lightAzimuth(215.0f)
  171. , m_rsmAmount(0.25f)
  172. , m_vplRadius(3.0f)
  173. , m_texelHalf(0.0f)
  174. {
  175. }
  176. void init(int32_t _argc, const char* const* _argv, uint32_t _width, uint32_t _height) override
  177. {
  178. Args args(_argc, _argv);
  179. m_width = _width;
  180. m_height = _height;
  181. m_debug = BGFX_DEBUG_NONE;
  182. m_reset = BGFX_RESET_VSYNC;
  183. bgfx::Init init;
  184. init.type = args.m_type;
  185. init.vendorId = args.m_pciId;
  186. init.resolution.width = m_width;
  187. init.resolution.height = m_height;
  188. init.resolution.reset = m_reset;
  189. bgfx::init(init);
  190. // Enable debug text.
  191. bgfx::setDebug(m_debug);
  192. // Labeling for renderdoc captures, etc
  193. bgfx::setViewName(RENDER_PASS_GBUFFER, "gbuffer" );
  194. bgfx::setViewName(RENDER_PASS_SHADOW_MAP, "shadow map" );
  195. bgfx::setViewName(RENDER_PASS_LIGHT_BUFFER, "light buffer");
  196. bgfx::setViewName(RENDER_PASS_COMBINE, "post combine");
  197. // Set up screen clears
  198. bgfx::setViewClear(RENDER_PASS_GBUFFER
  199. , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
  200. , 0
  201. , 1.0f
  202. , 0
  203. );
  204. bgfx::setViewClear(RENDER_PASS_LIGHT_BUFFER
  205. , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
  206. , 0
  207. , 1.0f
  208. , 0
  209. );
  210. bgfx::setViewClear(RENDER_PASS_SHADOW_MAP
  211. , BGFX_CLEAR_COLOR|BGFX_CLEAR_DEPTH
  212. , 0
  213. , 1.0f
  214. , 0
  215. );
  216. // Create uniforms
  217. u_tint = bgfx::createUniform("u_tint", bgfx::UniformType::Vec4); // Tint for when you click on items
  218. u_lightDir = bgfx::createUniform("u_lightDir", bgfx::UniformType::Vec4); // Single directional light for entire scene
  219. u_sphereInfo = bgfx::createUniform("u_sphereInfo", bgfx::UniformType::Vec4); // Info for RSM
  220. u_invMvp = bgfx::createUniform("u_invMvp", bgfx::UniformType::Mat4); // Matrix needed in light buffer
  221. u_invMvpShadow = bgfx::createUniform("u_invMvpShadow", bgfx::UniformType::Mat4); // Matrix needed in light buffer
  222. u_lightMtx = bgfx::createUniform("u_lightMtx", bgfx::UniformType::Mat4); // Matrix needed to use shadow map (world to shadow space)
  223. u_shadowDimsInv = bgfx::createUniform("u_shadowDimsInv", bgfx::UniformType::Vec4); // Used in PCF
  224. u_rsmAmount = bgfx::createUniform("u_rsmAmount", bgfx::UniformType::Vec4); // How much RSM to use vs directional light
  225. // Create texture sampler uniforms (used when we bind textures)
  226. s_normal = bgfx::createUniform("s_normal", bgfx::UniformType::Sampler); // Normal gbuffer
  227. s_depth = bgfx::createUniform("s_depth", bgfx::UniformType::Sampler); // Normal gbuffer
  228. s_color = bgfx::createUniform("s_color", bgfx::UniformType::Sampler); // Color (albedo) gbuffer
  229. s_light = bgfx::createUniform("s_light", bgfx::UniformType::Sampler); // Light buffer
  230. s_shadowMap = bgfx::createUniform("s_shadowMap", bgfx::UniformType::Sampler); // Shadow map
  231. s_rsm = bgfx::createUniform("s_rsm", bgfx::UniformType::Sampler); // Reflective shadow map
  232. // Create program from shaders.
  233. m_gbufferProgram = loadProgram("vs_rsm_gbuffer", "fs_rsm_gbuffer"); // Gbuffer
  234. m_shadowProgram = loadProgram("vs_rsm_shadow", "fs_rsm_shadow" ); // Drawing shadow map
  235. m_lightProgram = loadProgram("vs_rsm_lbuffer", "fs_rsm_lbuffer"); // Light buffer
  236. m_combineProgram = loadProgram("vs_rsm_combine", "fs_rsm_combine"); // Combiner
  237. // Load some meshes
  238. for (uint32_t ii = 0; ii < BX_COUNTOF(s_meshPaths); ++ii)
  239. {
  240. m_meshes[ii] = meshLoad(s_meshPaths[ii]);
  241. }
  242. // Randomly create some models
  243. bx::RngMwc mwc; // Random number generator
  244. for (uint32_t ii = 0; ii < BX_COUNTOF(m_models); ++ii)
  245. {
  246. Model& model = m_models[ii];
  247. uint32_t rr = mwc.gen() % 256;
  248. uint32_t gg = mwc.gen() % 256;
  249. uint32_t bb = mwc.gen() % 256;
  250. model.mesh = 1+mwc.gen()%(BX_COUNTOF(s_meshPaths)-1);
  251. model.color[0] = rr/255.0f;
  252. model.color[1] = gg/255.0f;
  253. model.color[2] = bb/255.0f;
  254. model.color[3] = 1.0f;
  255. model.position[0] = (((mwc.gen() % 256)) - 128.0f)/20.0f;
  256. model.position[1] = 0;
  257. model.position[2] = (((mwc.gen() % 256)) - 128.0f)/20.0f;
  258. }
  259. // Load ground. We'll just use the cube since I don't have a ground model right now
  260. m_ground = meshLoad("meshes/cube.bin");
  261. // Light sphere
  262. m_lightSphere = meshLoad("meshes/unit_sphere.bin");
  263. const uint64_t tsFlags = 0
  264. | BGFX_TEXTURE_RT
  265. | BGFX_SAMPLER_MIN_POINT
  266. | BGFX_SAMPLER_MAG_POINT
  267. | BGFX_SAMPLER_MIP_POINT
  268. | BGFX_SAMPLER_U_CLAMP
  269. | BGFX_SAMPLER_V_CLAMP
  270. ;
  271. // Make gbuffer and related textures
  272. bgfx::TextureFormat::Enum depthFormat = bgfx::getRendererType() == bgfx::RendererType::WebGPU
  273. ? bgfx::TextureFormat::D32F
  274. : bgfx::TextureFormat::D24;
  275. m_gbufferTex[GBUFFER_RT_NORMAL] = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::BGRA8, tsFlags);
  276. m_gbufferTex[GBUFFER_RT_COLOR] = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::BGRA8, tsFlags);
  277. m_gbufferTex[GBUFFER_RT_DEPTH] = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, depthFormat, tsFlags);
  278. m_gbuffer = bgfx::createFrameBuffer(BX_COUNTOF(m_gbufferTex), m_gbufferTex, true);
  279. // Make light buffer
  280. m_lightBufferTex = bgfx::createTexture2D(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::BGRA8, tsFlags);
  281. bgfx::TextureHandle lightBufferRTs[] = {
  282. m_lightBufferTex
  283. };
  284. m_lightBuffer = bgfx::createFrameBuffer(BX_COUNTOF(lightBufferRTs), lightBufferRTs, true);
  285. // Make shadow buffer
  286. const uint64_t rsmFlags = 0
  287. | BGFX_TEXTURE_RT
  288. | BGFX_SAMPLER_MIN_POINT
  289. | BGFX_SAMPLER_MAG_POINT
  290. | BGFX_SAMPLER_MIP_POINT
  291. | BGFX_SAMPLER_U_CLAMP
  292. | BGFX_SAMPLER_V_CLAMP
  293. ;
  294. // Reflective shadow map
  295. m_shadowBufferTex[SHADOW_RT_RSM] = bgfx::createTexture2D(
  296. SHADOW_MAP_DIM
  297. , SHADOW_MAP_DIM
  298. , false
  299. , 1
  300. , bgfx::TextureFormat::BGRA8
  301. , rsmFlags
  302. );
  303. // Typical shadow map
  304. m_shadowBufferTex[SHADOW_RT_DEPTH] = bgfx::createTexture2D(
  305. SHADOW_MAP_DIM
  306. , SHADOW_MAP_DIM
  307. , false
  308. , 1
  309. , bgfx::TextureFormat::D16
  310. , BGFX_TEXTURE_RT /* | BGFX_SAMPLER_COMPARE_LEQUAL*/
  311. ); // Note I'm not setting BGFX_SAMPLER_COMPARE_LEQUAL. Why?
  312. // Normally a PCF shadow map such as this requires a compare. However, this sample also
  313. // reads from this texture in the lighting pass, and only uses the PCF capabilites in the
  314. // combine pass, so the flag is disabled by default.
  315. m_shadowBuffer = bgfx::createFrameBuffer(BX_COUNTOF(m_shadowBufferTex), m_shadowBufferTex, true);
  316. // Vertex layout
  317. PosTexCoord0Vertex::init();
  318. // Init camera
  319. cameraCreate();
  320. cameraSetPosition({0.0f, 1.5f, 0.0f});
  321. cameraSetVerticalAngle(-0.3f);
  322. // Init directional light
  323. updateLightDir();
  324. // Get renderer capabilities info.
  325. m_caps = bgfx::getCaps();
  326. const bgfx::RendererType::Enum renderer = bgfx::getRendererType();
  327. m_texelHalf = bgfx::RendererType::Direct3D9 == renderer ? 0.5f : 0.0f;
  328. imguiCreate();
  329. }
  330. int shutdown() override
  331. {
  332. for (uint32_t ii = 0; ii < BX_COUNTOF(s_meshPaths); ++ii)
  333. {
  334. meshUnload(m_meshes[ii]);
  335. }
  336. meshUnload(m_ground);
  337. meshUnload(m_lightSphere);
  338. // Cleanup.
  339. bgfx::destroy(m_gbufferProgram);
  340. bgfx::destroy(m_lightProgram);
  341. bgfx::destroy(m_combineProgram);
  342. bgfx::destroy(m_shadowProgram);
  343. bgfx::destroy(u_tint);
  344. bgfx::destroy(u_lightDir);
  345. bgfx::destroy(u_sphereInfo);
  346. bgfx::destroy(u_invMvp);
  347. bgfx::destroy(u_invMvpShadow);
  348. bgfx::destroy(u_lightMtx);
  349. bgfx::destroy(u_shadowDimsInv);
  350. bgfx::destroy(u_rsmAmount);
  351. bgfx::destroy(s_normal);
  352. bgfx::destroy(s_depth);
  353. bgfx::destroy(s_light);
  354. bgfx::destroy(s_color);
  355. bgfx::destroy(s_shadowMap);
  356. bgfx::destroy(s_rsm);
  357. bgfx::destroy(m_gbuffer);
  358. bgfx::destroy(m_lightBuffer);
  359. bgfx::destroy(m_shadowBuffer);
  360. for (uint32_t ii = 0; ii < BX_COUNTOF(m_gbufferTex); ++ii)
  361. {
  362. bgfx::destroy(m_gbufferTex[ii]);
  363. }
  364. bgfx::destroy(m_lightBufferTex);
  365. for (uint32_t ii = 0; ii < BX_COUNTOF(m_shadowBufferTex); ++ii)
  366. {
  367. bgfx::destroy(m_shadowBufferTex[ii]);
  368. }
  369. cameraDestroy();
  370. imguiDestroy();
  371. // Shutdown bgfx.
  372. bgfx::shutdown();
  373. return 0;
  374. }
  375. bool update() override
  376. {
  377. if (!entry::processEvents(m_width, m_height, m_debug, m_reset, &m_mouseState) )
  378. {
  379. // Update frame timer
  380. int64_t now = bx::getHPCounter();
  381. static int64_t last = now;
  382. const int64_t frameTime = now - last;
  383. last = now;
  384. const double freq = double(bx::getHPFrequency());
  385. const float deltaTime = float(frameTime/freq);
  386. // Update camera
  387. cameraUpdate(deltaTime*0.15f, m_mouseState);
  388. // Set up matrices for gbuffer
  389. float view[16];
  390. cameraGetViewMtx(view);
  391. float proj[16];
  392. bx::mtxProj(proj, 60.0f, float(m_width)/float(m_height), 0.1f, 100.0f, bgfx::getCaps()->homogeneousDepth);
  393. bgfx::setViewRect(RENDER_PASS_GBUFFER, 0, 0, uint16_t(m_width), uint16_t(m_height));
  394. bgfx::setViewTransform(RENDER_PASS_GBUFFER, view, proj);
  395. // Make sure when we draw it goes into gbuffer and not backbuffer
  396. bgfx::setViewFrameBuffer(RENDER_PASS_GBUFFER, m_gbuffer);
  397. // Draw everything into g-buffer
  398. drawAllModels(RENDER_PASS_GBUFFER, m_gbufferProgram);
  399. // Draw shadow map
  400. // Set up transforms for shadow map
  401. float smView[16], smProj[16], lightEye[3], lightAt[3];
  402. lightEye[0] = m_lightDir[0]*LIGHT_DIST;
  403. lightEye[1] = m_lightDir[1]*LIGHT_DIST;
  404. lightEye[2] = m_lightDir[2]*LIGHT_DIST;
  405. lightAt[0] = 0.0f;
  406. lightAt[1] = 0.0f;
  407. lightAt[2] = 0.0f;
  408. bx::mtxLookAt(smView, bx::load<bx::Vec3>(lightEye), bx::load<bx::Vec3>(lightAt) );
  409. const float area = 10.0f;
  410. const bgfx::Caps* caps = bgfx::getCaps();
  411. bx::mtxOrtho(smProj, -area, area, -area, area, -100.0f, 100.0f, 0.0f, caps->homogeneousDepth);
  412. bgfx::setViewTransform(RENDER_PASS_SHADOW_MAP, smView, smProj);
  413. bgfx::setViewFrameBuffer(RENDER_PASS_SHADOW_MAP, m_shadowBuffer);
  414. bgfx::setViewRect(RENDER_PASS_SHADOW_MAP, 0, 0, SHADOW_MAP_DIM, SHADOW_MAP_DIM);
  415. drawAllModels(RENDER_PASS_SHADOW_MAP, m_shadowProgram);
  416. // Next draw light buffer
  417. // Set up matrices for light buffer
  418. bgfx::setViewRect(RENDER_PASS_LIGHT_BUFFER, 0, 0, uint16_t(m_width), uint16_t(m_height));
  419. bgfx::setViewTransform(RENDER_PASS_LIGHT_BUFFER, view, proj); // Notice, same view and proj as gbuffer
  420. // Set drawing into light buffer
  421. bgfx::setViewFrameBuffer(RENDER_PASS_LIGHT_BUFFER, m_lightBuffer);
  422. // Inverse view projection is needed in shader so set that up
  423. float vp[16], invMvp[16];
  424. bx::mtxMul(vp, view, proj);
  425. bx::mtxInverse(invMvp, vp);
  426. // Light matrix used in combine pass and inverse used in light pass
  427. float lightMtx[16]; // World space to light space (shadow map space)
  428. bx::mtxMul(lightMtx, smView, smProj);
  429. float invMvpShadow[16];
  430. bx::mtxInverse(invMvpShadow, lightMtx);
  431. // Draw some lights (these should really be instanced but for this example they aren't...)
  432. const uint32_t kMaxSpheres = 32;
  433. for (uint32_t i = 0; i < kMaxSpheres; i++)
  434. {
  435. for (uint32_t j = 0; j < kMaxSpheres; j++)
  436. {
  437. // These are used in the fragment shader
  438. bgfx::setTexture(0, s_normal, bgfx::getTexture(m_gbuffer, GBUFFER_RT_NORMAL) ); // Normal for lighting calculations
  439. bgfx::setTexture(1, s_depth, bgfx::getTexture(m_gbuffer, GBUFFER_RT_DEPTH) ); // Depth to reconstruct world position
  440. // Thse are used in the vert shader
  441. bgfx::setTexture(2, s_shadowMap, bgfx::getTexture(m_shadowBuffer, SHADOW_RT_DEPTH) ); // Used to place sphere
  442. bgfx::setTexture(3, s_rsm, bgfx::getTexture(m_shadowBuffer, SHADOW_RT_RSM) ); // Used to scale/color sphere
  443. bgfx::setUniform(u_invMvp, invMvp);
  444. bgfx::setUniform(u_invMvpShadow, invMvpShadow);
  445. float sphereInfo[4];
  446. sphereInfo[0] = ((float)i/(kMaxSpheres-1));
  447. sphereInfo[1] = ((float)j/(kMaxSpheres-1));
  448. sphereInfo[2] = m_vplRadius;
  449. sphereInfo[3] = 0.0; // Unused
  450. bgfx::setUniform(u_sphereInfo, sphereInfo);
  451. const uint64_t lightDrawState = 0
  452. | BGFX_STATE_WRITE_RGB
  453. | BGFX_STATE_BLEND_ADD // <=== Overlapping lights contribute more
  454. | BGFX_STATE_WRITE_A
  455. | BGFX_STATE_CULL_CW // <=== If we go into the lights, there will be problems, so we draw the far back face.
  456. ;
  457. meshSubmit(
  458. m_lightSphere
  459. , RENDER_PASS_LIGHT_BUFFER
  460. , m_lightProgram
  461. , NULL
  462. , lightDrawState
  463. );
  464. }
  465. }
  466. // Draw combine pass
  467. // Texture inputs for combine pass
  468. bgfx::setTexture(0, s_normal, bgfx::getTexture(m_gbuffer, GBUFFER_RT_NORMAL) );
  469. bgfx::setTexture(1, s_color, bgfx::getTexture(m_gbuffer, GBUFFER_RT_COLOR) );
  470. bgfx::setTexture(2, s_light, bgfx::getTexture(m_lightBuffer, 0) );
  471. bgfx::setTexture(3, s_depth, bgfx::getTexture(m_gbuffer, GBUFFER_RT_DEPTH) );
  472. bgfx::setTexture(4, s_shadowMap, bgfx::getTexture(m_shadowBuffer, SHADOW_RT_DEPTH)
  473. , BGFX_SAMPLER_COMPARE_LEQUAL
  474. );
  475. // Uniforms for combine pass
  476. bgfx::setUniform(u_lightDir, m_lightDir);
  477. bgfx::setUniform(u_invMvp, invMvp);
  478. bgfx::setUniform(u_lightMtx, lightMtx);
  479. const float invDim[4] = {1.0f/SHADOW_MAP_DIM, 0.0f, 0.0f, 0.0f};
  480. bgfx::setUniform(u_shadowDimsInv, invDim);
  481. float rsmAmount[4] = {m_rsmAmount,m_rsmAmount,m_rsmAmount,m_rsmAmount};
  482. bgfx::setUniform(u_rsmAmount, rsmAmount);
  483. // Set up state for combine pass
  484. // point of this is to avoid doing depth test, which is in the default state
  485. bgfx::setState(0
  486. | BGFX_STATE_WRITE_RGB
  487. | BGFX_STATE_WRITE_A
  488. );
  489. // Set up transform matrix for fullscreen quad
  490. float orthoProj[16];
  491. bx::mtxOrtho(orthoProj, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 100.0f, 0.0f, caps->homogeneousDepth);
  492. bgfx::setViewTransform(RENDER_PASS_COMBINE, NULL, orthoProj);
  493. bgfx::setViewRect(RENDER_PASS_COMBINE, 0, 0, uint16_t(m_width), uint16_t(m_height) );
  494. // Bind vertex buffer and draw quad
  495. screenSpaceQuad( (float)m_width, (float)m_height, m_texelHalf, m_caps->originBottomLeft);
  496. bgfx::submit(RENDER_PASS_COMBINE, m_combineProgram);
  497. // Draw UI
  498. imguiBeginFrame(m_mouseState.m_mx
  499. , m_mouseState.m_my
  500. , (m_mouseState.m_buttons[entry::MouseButton::Left] ? IMGUI_MBUT_LEFT : 0)
  501. | (m_mouseState.m_buttons[entry::MouseButton::Right] ? IMGUI_MBUT_RIGHT : 0)
  502. | (m_mouseState.m_buttons[entry::MouseButton::Middle] ? IMGUI_MBUT_MIDDLE : 0)
  503. , m_mouseState.m_mz
  504. , uint16_t(m_width)
  505. , uint16_t(m_height)
  506. );
  507. showExampleDialog(this);
  508. ImGui::SetNextWindowPos(
  509. ImVec2(m_width - m_width / 5.0f - 10.0f, 10.0f)
  510. , ImGuiCond_FirstUseEver
  511. );
  512. ImGui::SetNextWindowSize(
  513. ImVec2(m_width / 5.0f, m_height / 3.0f)
  514. , ImGuiCond_FirstUseEver
  515. );
  516. ImGui::Begin("Settings"
  517. , NULL
  518. , 0
  519. );
  520. ImGui::SliderFloat("RSM Amount", &m_rsmAmount, 0.0f, 0.7f);
  521. ImGui::SliderFloat("VPL Radius", &m_vplRadius, 0.25f, 20.0f);
  522. ImGui::SliderFloat("Light Azimuth", &m_lightAzimuth, 0.0f, 360.0f);
  523. ImGui::SliderFloat("Light Elevation", &m_lightElevation, 35.0f, 90.0f);
  524. ImGui::End();
  525. imguiEndFrame();
  526. updateLightDir();
  527. // Advance to next frame. Rendering thread will be kicked to
  528. // process submitted rendering primitives.
  529. m_currFrame = bgfx::frame();
  530. return true;
  531. }
  532. return false;
  533. }
  534. void drawAllModels(uint8_t _pass, bgfx::ProgramHandle _program)
  535. {
  536. for (uint32_t ii = 0; ii < BX_COUNTOF(m_models); ++ii)
  537. {
  538. const Model& model = m_models[ii];
  539. // Set up transform matrix for each model
  540. float scale = s_meshScale[model.mesh];
  541. float mtx[16];
  542. bx::mtxSRT(mtx
  543. , scale
  544. , scale
  545. , scale
  546. , 0.0f
  547. , 0.0f
  548. , 0.0f
  549. , model.position[0]
  550. , model.position[1]
  551. , model.position[2]
  552. );
  553. // Submit mesh to gbuffer
  554. bgfx::setUniform(u_tint, model.color);
  555. meshSubmit(m_meshes[model.mesh], _pass, _program, mtx);
  556. }
  557. // Draw ground
  558. const float white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
  559. bgfx::setUniform(u_tint, white);
  560. float mtxScale[16];
  561. float scale = 10.0;
  562. bx::mtxScale(mtxScale
  563. , scale
  564. , scale
  565. , scale
  566. );
  567. float mtxTrans[16];
  568. bx::mtxTranslate(mtxTrans
  569. , 0.0f
  570. , -10.0f
  571. , 0.0f
  572. );
  573. float mtx[16];
  574. bx::mtxMul(mtx, mtxScale, mtxTrans);
  575. meshSubmit(m_ground, _pass, _program, mtx);
  576. }
  577. void updateLightDir()
  578. {
  579. float el = m_lightElevation * (bx::kPi/180.0f);
  580. float az = m_lightAzimuth * (bx::kPi/180.0f);
  581. m_lightDir[0] = bx::cos(el)*bx::cos(az);
  582. m_lightDir[2] = bx::cos(el)*bx::sin(az);
  583. m_lightDir[1] = bx::sin(el);
  584. m_lightDir[3] = 0.0f;
  585. }
  586. uint32_t m_width;
  587. uint32_t m_height;
  588. uint32_t m_debug;
  589. uint32_t m_reset;
  590. entry::MouseState m_mouseState;
  591. Mesh* m_ground;
  592. Mesh* m_lightSphere; // Unit sphere
  593. // Resource handles
  594. bgfx::ProgramHandle m_gbufferProgram;
  595. bgfx::ProgramHandle m_shadowProgram;
  596. bgfx::ProgramHandle m_lightProgram;
  597. bgfx::ProgramHandle m_combineProgram;
  598. bgfx::FrameBufferHandle m_gbuffer;
  599. bgfx::FrameBufferHandle m_lightBuffer;
  600. bgfx::FrameBufferHandle m_shadowBuffer;
  601. // Shader uniforms
  602. bgfx::UniformHandle u_tint;
  603. bgfx::UniformHandle u_invMvp;
  604. bgfx::UniformHandle u_invMvpShadow;
  605. bgfx::UniformHandle u_lightMtx;
  606. bgfx::UniformHandle u_lightDir;
  607. bgfx::UniformHandle u_sphereInfo;
  608. bgfx::UniformHandle u_shadowDimsInv;
  609. bgfx::UniformHandle u_rsmAmount;
  610. // Uniforms to identify texture samples
  611. bgfx::UniformHandle s_normal;
  612. bgfx::UniformHandle s_depth;
  613. bgfx::UniformHandle s_color;
  614. bgfx::UniformHandle s_light;
  615. bgfx::UniformHandle s_shadowMap;
  616. bgfx::UniformHandle s_rsm;
  617. // Various render targets
  618. bgfx::TextureHandle m_gbufferTex[3];
  619. bgfx::TextureHandle m_lightBufferTex;
  620. bgfx::TextureHandle m_shadowBufferTex[2];
  621. const bgfx::Caps* m_caps;
  622. struct Model
  623. {
  624. uint32_t mesh; // Index of mesh in m_meshes
  625. float color[4];
  626. float position[3];
  627. };
  628. Model m_models[MODEL_COUNT];
  629. Mesh * m_meshes[BX_COUNTOF(s_meshPaths)];
  630. uint32_t m_reading;
  631. uint32_t m_currFrame;
  632. // UI
  633. bool m_cameraSpin;
  634. // Light position;
  635. float m_lightDir[4];
  636. float m_lightElevation;
  637. float m_lightAzimuth;
  638. float m_rsmAmount; // Amount of rsm
  639. float m_vplRadius; // Radius of virtual point light
  640. float m_texelHalf;
  641. };
  642. } // namespace
  643. ENTRY_IMPLEMENT_MAIN(
  644. ExampleRSM
  645. , "31-rsm"
  646. , "Global Illumination with Reflective Shadow Map."
  647. , "https://bkaradzic.github.io/bgfx/examples.html#rsm"
  648. );