💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1135 lines
36 KiB

  1. /*
  2. * Copyright (C) 2023 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <engine/render/passes/material-pass.hpp>
  20. #include <engine/config.hpp>
  21. #include <engine/resources/resource-manager.hpp>
  22. #include <engine/gl/rasterizer.hpp>
  23. #include <engine/gl/framebuffer.hpp>
  24. #include <engine/gl/shader-program.hpp>
  25. #include <engine/gl/shader-variable.hpp>
  26. #include <engine/gl/vertex-buffer.hpp>
  27. #include <engine/gl/vertex-array.hpp>
  28. #include <engine/gl/vertex-attribute.hpp>
  29. #include <engine/gl/drawing-mode.hpp>
  30. #include <engine/gl/texture-2d.hpp>
  31. #include <engine/gl/texture-wrapping.hpp>
  32. #include <engine/gl/texture-filter.hpp>
  33. #include <engine/gl/shader-variable-type.hpp>
  34. #include <engine/render/vertex-attribute.hpp>
  35. #include <engine/render/material-flags.hpp>
  36. #include <engine/render/model.hpp>
  37. #include <engine/render/context.hpp>
  38. #include <engine/scene/camera.hpp>
  39. #include <engine/scene/collection.hpp>
  40. #include <engine/scene/directional-light.hpp>
  41. #include <engine/scene/spot-light.hpp>
  42. #include <engine/scene/point-light.hpp>
  43. #include <engine/scene/rectangle-light.hpp>
  44. #include <engine/scene/light-probe.hpp>
  45. #include <engine/config.hpp>
  46. #include <engine/math/quaternion.hpp>
  47. #include <engine/math/projection.hpp>
  48. #include <engine/utility/hash/combine.hpp>
  49. #include <cmath>
  50. #include <glad/glad.h>
  51. #include <execution>
  52. namespace render {
  53. namespace {
  54. /**
  55. * Sorts render operations for the material pass.
  56. */
  57. bool operation_compare(const render::operation* a, const render::operation* b)
  58. {
  59. // Render operations with materials first
  60. if (!a->material)
  61. {
  62. return false;
  63. }
  64. else if (!b->material)
  65. {
  66. return true;
  67. }
  68. const bool translucent_a = a->material->get_blend_mode() == material_blend_mode::translucent;
  69. const bool translucent_b = b->material->get_blend_mode() == material_blend_mode::translucent;
  70. if (translucent_a)
  71. {
  72. if (translucent_b)
  73. {
  74. // A and B are both translucent, render back to front
  75. return (a->depth < b->depth);
  76. }
  77. else
  78. {
  79. // A is translucent, B is opaque. Render B first
  80. return false;
  81. }
  82. }
  83. else
  84. {
  85. if (translucent_b)
  86. {
  87. // A is opaque, B is translucent. Render A first
  88. return true;
  89. }
  90. else
  91. {
  92. // A and B are both opaque
  93. const std::size_t hash_a = a->material->hash();
  94. const std::size_t hash_b = b->material->hash();
  95. if (hash_a == hash_b)
  96. {
  97. // A and B have same material hash, sort by VAO
  98. return (a->vertex_array < b->vertex_array);
  99. }
  100. else
  101. {
  102. // A and B have different material hashes, sort by hash
  103. return (hash_a < hash_b);
  104. }
  105. }
  106. }
  107. }
  108. } // namespace
  109. material_pass::material_pass(gl::rasterizer* rasterizer, const gl::framebuffer* framebuffer, resource_manager* resource_manager):
  110. pass(rasterizer, framebuffer)
  111. {
  112. // Load LTC LUT textures
  113. ltc_lut_1 = resource_manager->load<gl::texture_2d>("ltc-lut-1.tex");
  114. ltc_lut_2 = resource_manager->load<gl::texture_2d>("ltc-lut-2.tex");
  115. // Load IBL BRDF LUT texture
  116. brdf_lut = resource_manager->load<gl::texture_2d>("brdf-lut.tex");
  117. }
  118. void material_pass::render(render::context& ctx)
  119. {
  120. rasterizer->use_framebuffer(*framebuffer);
  121. glDisable(GL_BLEND);
  122. glEnable(GL_DEPTH_TEST);
  123. glDepthMask(GL_TRUE);
  124. glDepthFunc(GL_GREATER);
  125. glEnable(GL_CULL_FACE);
  126. glCullFace(GL_BACK);
  127. glDisable(GL_STENCIL_TEST);
  128. // For half-z buffer
  129. glDepthRange(-1.0f, 1.0f);
  130. auto viewport = framebuffer->get_dimensions();
  131. rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
  132. //const gl::shader_program* active_shader_program = nullptr;
  133. const render::material* active_material = nullptr;
  134. std::size_t active_material_hash = 0;
  135. bool active_two_sided = false;
  136. material_blend_mode active_blend_mode = material_blend_mode::opaque;
  137. std::size_t active_cache_key = 0;
  138. shader_cache_entry* active_cache_entry = nullptr;
  139. // Gather information
  140. evaluate_camera(ctx);
  141. evaluate_lighting(ctx);
  142. evaluate_misc(ctx);
  143. // Sort render operations
  144. std::sort(std::execution::par_unseq, ctx.operations.begin(), ctx.operations.end(), operation_compare);
  145. for (const render::operation* operation: ctx.operations)
  146. {
  147. // Get operation material
  148. const render::material* material = operation->material.get();
  149. if (!material)
  150. {
  151. if (!fallback_material)
  152. {
  153. // No material specified and no fallback material, skip operation
  154. continue;
  155. }
  156. // Use fallback material
  157. material = fallback_material.get();
  158. }
  159. // Switch materials if necessary
  160. if (active_material != material)
  161. {
  162. if (!material->get_shader_template())
  163. {
  164. continue;
  165. }
  166. if (active_material_hash != material->hash())
  167. {
  168. // Set culling mode
  169. if (active_two_sided != material->is_two_sided())
  170. {
  171. if (material->is_two_sided())
  172. {
  173. glDisable(GL_CULL_FACE);
  174. }
  175. else
  176. {
  177. glEnable(GL_CULL_FACE);
  178. }
  179. active_two_sided = material->is_two_sided();
  180. }
  181. // Set blend mode
  182. if (active_blend_mode != material->get_blend_mode())
  183. {
  184. if (material->get_blend_mode() == material_blend_mode::translucent)
  185. {
  186. glEnable(GL_BLEND);
  187. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  188. }
  189. else
  190. {
  191. glDisable(GL_BLEND);
  192. }
  193. active_blend_mode = material->get_blend_mode();
  194. }
  195. active_material_hash = material->hash();
  196. }
  197. // Calculate shader cache key
  198. std::size_t cache_key = hash::combine(lighting_state_hash, material->get_shader_template()->hash());
  199. if (active_cache_key != cache_key)
  200. {
  201. // Lookup shader cache entry
  202. if (auto i = shader_cache.find(cache_key); i != shader_cache.end())
  203. {
  204. active_cache_entry = &i->second;
  205. }
  206. else
  207. {
  208. // Construct cache entry
  209. active_cache_entry = &shader_cache[cache_key];
  210. active_cache_entry->shader_program = generate_shader_program(*material->get_shader_template());
  211. build_shader_command_buffer(active_cache_entry->shader_command_buffer, *active_cache_entry->shader_program);
  212. build_geometry_command_buffer(active_cache_entry->geometry_command_buffer, *active_cache_entry->shader_program);
  213. debug::log::trace("Generated material cache entry {:x}", cache_key);
  214. }
  215. // Bind shader and update shader-specific variables
  216. for (const auto& command: active_cache_entry->shader_command_buffer)
  217. {
  218. command();
  219. }
  220. active_cache_key = cache_key;
  221. }
  222. // Find or build material command buffer
  223. std::vector<std::function<void()>>* material_command_buffer;
  224. if (auto i = active_cache_entry->material_command_buffers.find(material); i != active_cache_entry->material_command_buffers.end())
  225. {
  226. material_command_buffer = &i->second;
  227. }
  228. else
  229. {
  230. material_command_buffer = &active_cache_entry->material_command_buffers[material];
  231. build_material_command_buffer(*material_command_buffer, *active_cache_entry->shader_program, *material);
  232. debug::log::trace("Generated material command buffer");
  233. }
  234. // Update material-dependent shader variables
  235. for (const auto& command: *material_command_buffer)
  236. {
  237. command();
  238. }
  239. active_material = material;
  240. }
  241. // Update geometry-dependent shader variables
  242. model = &operation->transform;
  243. matrix_palette = operation->matrix_palette;
  244. for (const auto& command: active_cache_entry->geometry_command_buffer)
  245. {
  246. command();
  247. }
  248. // Draw geometry
  249. if (operation->instance_count)
  250. {
  251. rasterizer->draw_arrays_instanced(*operation->vertex_array, operation->drawing_mode, operation->start_index, operation->index_count, operation->instance_count);
  252. }
  253. else
  254. {
  255. rasterizer->draw_arrays(*operation->vertex_array, operation->drawing_mode, operation->start_index, operation->index_count);
  256. }
  257. }
  258. ++frame;
  259. }
  260. void material_pass::set_fallback_material(std::shared_ptr<render::material> fallback)
  261. {
  262. this->fallback_material = fallback;
  263. }
  264. void material_pass::evaluate_camera(const render::context& ctx)
  265. {
  266. view = &ctx.camera->get_view();
  267. projection = &ctx.camera->get_projection();
  268. view_projection = &ctx.camera->get_view_projection();
  269. camera_position = &ctx.camera->get_translation();
  270. camera_exposure = ctx.camera->get_exposure_normalization();
  271. clip_depth =
  272. {
  273. ctx.camera->get_clip_near(),
  274. ctx.camera->get_clip_far()
  275. };
  276. log_depth_coef = 2.0f / std::log2(clip_depth[1] + 1.0f);
  277. }
  278. void material_pass::evaluate_lighting(const render::context& ctx)
  279. {
  280. // Reset light and shadow counts
  281. light_probe_count = 0;
  282. directional_light_count = 0;
  283. directional_shadow_count = 0;
  284. spot_light_count = 0;
  285. point_light_count = 0;
  286. rectangle_light_count = 0;
  287. const auto& light_probes = ctx.collection->get_objects(scene::light_probe::object_type_id);
  288. for (const scene::object_base* object: light_probes)
  289. {
  290. if (!light_probe_count)
  291. {
  292. const scene::light_probe& light_probe = static_cast<const scene::light_probe&>(*object);
  293. ++light_probe_count;
  294. light_probe_luminance_texture = light_probe.get_luminance_texture().get();
  295. light_probe_illuminance_texture = light_probe.get_illuminance_texture().get();
  296. }
  297. }
  298. const auto& lights = ctx.collection->get_objects(scene::light::object_type_id);
  299. for (const scene::object_base* object: lights)
  300. {
  301. const scene::light& light = static_cast<const scene::light&>(*object);
  302. switch (light.get_light_type())
  303. {
  304. // Add directional light
  305. case scene::light_type::directional:
  306. {
  307. const scene::directional_light& directional_light = static_cast<const scene::directional_light&>(light);
  308. const std::size_t index = directional_light_count;
  309. ++directional_light_count;
  310. if (directional_light_count > directional_light_colors.size())
  311. {
  312. directional_light_colors.resize(directional_light_count);
  313. directional_light_directions.resize(directional_light_count);
  314. }
  315. directional_light_colors[index] = directional_light.get_colored_illuminance() * ctx.camera->get_exposure_normalization();
  316. directional_light_directions[index] = directional_light.get_direction();
  317. // Add directional shadow
  318. if (directional_light.is_shadow_caster() && directional_light.get_shadow_framebuffer())
  319. {
  320. const std::size_t index = directional_shadow_count;
  321. ++directional_shadow_count;
  322. if (directional_shadow_count > directional_shadow_maps.size())
  323. {
  324. directional_shadow_maps.resize(directional_shadow_count);
  325. directional_shadow_biases.resize(directional_shadow_count);
  326. directional_shadow_splits.resize(directional_shadow_count);
  327. directional_shadow_matrices.resize(directional_shadow_count);
  328. }
  329. directional_shadow_maps[index] = static_cast<const gl::texture_2d*>(directional_light.get_shadow_framebuffer()->get_depth_attachment());
  330. directional_shadow_biases[index] = directional_light.get_shadow_bias();
  331. directional_shadow_splits[index] = &directional_light.get_shadow_cascade_distances();
  332. directional_shadow_matrices[index] = &directional_light.get_shadow_cascade_matrices();
  333. }
  334. break;
  335. }
  336. // Add spot_light
  337. case scene::light_type::spot:
  338. {
  339. const scene::spot_light& spot_light = static_cast<const scene::spot_light&>(light);
  340. const std::size_t index = spot_light_count;
  341. ++spot_light_count;
  342. if (spot_light_count > spot_light_colors.size())
  343. {
  344. spot_light_colors.resize(spot_light_count);
  345. spot_light_positions.resize(spot_light_count);
  346. spot_light_directions.resize(spot_light_count);
  347. spot_light_cutoffs.resize(spot_light_count);
  348. }
  349. spot_light_colors[index] = spot_light.get_luminous_flux() * ctx.camera->get_exposure_normalization();
  350. spot_light_positions[index] = spot_light.get_translation();
  351. spot_light_directions[index] = spot_light.get_direction();
  352. spot_light_cutoffs[index] = spot_light.get_cosine_cutoff();
  353. break;
  354. }
  355. // Add point light
  356. case scene::light_type::point:
  357. {
  358. const scene::point_light& point_light = static_cast<const scene::point_light&>(light);
  359. const std::size_t index = point_light_count;
  360. ++point_light_count;
  361. if (point_light_count > point_light_colors.size())
  362. {
  363. point_light_colors.resize(point_light_count);
  364. point_light_positions.resize(point_light_count);
  365. }
  366. point_light_colors[index] = point_light.get_colored_luminous_flux() * ctx.camera->get_exposure_normalization();
  367. point_light_positions[index] = point_light.get_translation();
  368. break;
  369. }
  370. // Add rectangle light
  371. case scene::light_type::rectangle:
  372. {
  373. const scene::rectangle_light& rectangle_light = static_cast<const scene::rectangle_light&>(light);
  374. const std::size_t index = rectangle_light_count;
  375. ++rectangle_light_count;
  376. if (rectangle_light_count > rectangle_light_colors.size())
  377. {
  378. rectangle_light_colors.resize(rectangle_light_count);
  379. rectangle_light_corners.resize(rectangle_light_count * 4);
  380. }
  381. rectangle_light_colors[index] = rectangle_light.get_colored_luminance() * ctx.camera->get_exposure_normalization();
  382. const auto corners = rectangle_light.get_corners();
  383. for (std::size_t i = 0; i < 4; ++i)
  384. {
  385. rectangle_light_corners[index * 4 + i] = corners[i];
  386. }
  387. break;
  388. }
  389. default:
  390. break;
  391. }
  392. }
  393. // Generate lighting state hash
  394. lighting_state_hash = std::hash<std::size_t>{}(light_probe_count);
  395. lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(directional_light_count));
  396. lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(directional_shadow_count));
  397. lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(point_light_count));
  398. lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(spot_light_count));
  399. lighting_state_hash = hash::combine(lighting_state_hash, std::hash<std::size_t>{}(rectangle_light_count));
  400. }
  401. void material_pass::evaluate_misc(const render::context& ctx)
  402. {
  403. time = ctx.t;
  404. timestep = ctx.dt;
  405. subframe = ctx.alpha;
  406. const auto viewport_size = framebuffer->get_dimensions();
  407. resolution =
  408. {
  409. static_cast<float>(std::get<0>(viewport_size)),
  410. static_cast<float>(std::get<1>(viewport_size))
  411. };
  412. ///mouse_position = ...
  413. }
  414. std::unique_ptr<gl::shader_program> material_pass::generate_shader_program(const gl::shader_template& shader_template) const
  415. {
  416. std::unordered_map<std::string, std::string> definitions;
  417. definitions["VERTEX_POSITION"] = std::to_string(vertex_attribute::position);
  418. definitions["VERTEX_UV"] = std::to_string(vertex_attribute::uv);
  419. definitions["VERTEX_NORMAL"] = std::to_string(vertex_attribute::normal);
  420. definitions["VERTEX_TANGENT"] = std::to_string(vertex_attribute::tangent);
  421. definitions["VERTEX_COLOR"] = std::to_string(vertex_attribute::color);
  422. definitions["VERTEX_BONE_INDEX"] = std::to_string(vertex_attribute::bone_index);
  423. definitions["VERTEX_BONE_WEIGHT"] = std::to_string(vertex_attribute::bone_weight);
  424. definitions["VERTEX_BARYCENTRIC"] = std::to_string(vertex_attribute::barycentric);
  425. definitions["VERTEX_TARGET"] = std::to_string(vertex_attribute::target);
  426. definitions["FRAGMENT_OUTPUT_COLOR"] = std::to_string(0);
  427. definitions["LIGHT_PROBE_COUNT"] = std::to_string(light_probe_count);
  428. definitions["DIRECTIONAL_LIGHT_COUNT"] = std::to_string(directional_light_count);
  429. definitions["DIRECTIONAL_SHADOW_COUNT"] = std::to_string(directional_shadow_count);
  430. definitions["POINT_LIGHT_COUNT"] = std::to_string(point_light_count);
  431. definitions["SPOT_LIGHT_COUNT"] = std::to_string(spot_light_count);
  432. definitions["RECTANGLE_LIGHT_COUNT"] = std::to_string(rectangle_light_count);
  433. auto shader_program = shader_template.build(definitions);
  434. if (!shader_program->linked())
  435. {
  436. debug::log::error("Failed to link material shader program: {}", shader_program->info());
  437. debug::log::warning("{}", shader_template.configure(gl::shader_stage::fragment, definitions));
  438. }
  439. return shader_program;
  440. }
  441. void material_pass::build_shader_command_buffer(std::vector<std::function<void()>>& command_buffer, const gl::shader_program& shader_program) const
  442. {
  443. // Bind shader program
  444. command_buffer.emplace_back([&](){rasterizer->use_program(shader_program);});
  445. // Update camera variables
  446. if (auto view_var = shader_program.variable("view"))
  447. {
  448. command_buffer.emplace_back([&, view_var](){view_var->update(*view);});
  449. }
  450. if (auto projection_var = shader_program.variable("projection"))
  451. {
  452. command_buffer.emplace_back([&, projection_var](){projection_var->update(*projection);});
  453. }
  454. if (auto view_projection_var = shader_program.variable("view_projection"))
  455. {
  456. command_buffer.emplace_back([&, view_projection_var](){view_projection_var->update(*view_projection);});
  457. }
  458. if (auto camera_position_var = shader_program.variable("camera_position"))
  459. {
  460. command_buffer.emplace_back([&, camera_position_var](){camera_position_var->update(*camera_position);});
  461. }
  462. if (auto camera_exposure_var = shader_program.variable("camera_exposure"))
  463. {
  464. command_buffer.emplace_back([&, camera_exposure_var](){camera_exposure_var->update(camera_exposure);});
  465. }
  466. if (auto clip_depth_var = shader_program.variable("clip_depth"))
  467. {
  468. command_buffer.emplace_back([&, clip_depth_var](){clip_depth_var->update(clip_depth);});
  469. }
  470. // Update IBL variables
  471. if (auto brdf_lut_var = shader_program.variable("brdf_lut"))
  472. {
  473. command_buffer.emplace_back
  474. (
  475. [&, brdf_lut_var]()
  476. {
  477. brdf_lut_var->update(*brdf_lut);
  478. }
  479. );
  480. }
  481. // Update light probe variables
  482. if (light_probe_count)
  483. {
  484. if (auto light_probe_luminance_texture_var = shader_program.variable("light_probe_luminance_texture"))
  485. {
  486. command_buffer.emplace_back
  487. (
  488. [&, light_probe_luminance_texture_var]()
  489. {
  490. light_probe_luminance_texture_var->update(*light_probe_luminance_texture);
  491. }
  492. );
  493. }
  494. if (auto light_probe_luminance_mip_scale_var = shader_program.variable("light_probe_luminance_mip_scale"))
  495. {
  496. command_buffer.emplace_back
  497. (
  498. [&, light_probe_luminance_mip_scale_var]()
  499. {
  500. light_probe_luminance_mip_scale_var->update(std::max<float>(static_cast<float>(light_probe_luminance_texture->get_mip_count()) - 4.0f, 0.0f));
  501. }
  502. );
  503. }
  504. if (auto light_probe_illuminance_texture_var = shader_program.variable("light_probe_illuminance_texture"))
  505. {
  506. command_buffer.emplace_back
  507. (
  508. [&, light_probe_illuminance_texture_var]()
  509. {
  510. light_probe_illuminance_texture_var->update(*light_probe_illuminance_texture);
  511. }
  512. );
  513. }
  514. }
  515. // Update LTC variables
  516. if (auto ltc_lut_1_var = shader_program.variable("ltc_lut_1"))
  517. {
  518. if (auto ltc_lut_2_var = shader_program.variable("ltc_lut_2"))
  519. {
  520. command_buffer.emplace_back
  521. (
  522. [&, ltc_lut_1_var, ltc_lut_2_var]()
  523. {
  524. ltc_lut_1_var->update(*ltc_lut_1);
  525. ltc_lut_2_var->update(*ltc_lut_2);
  526. }
  527. );
  528. }
  529. }
  530. if (rectangle_light_count)
  531. {
  532. if (auto rectangle_light_colors_var = shader_program.variable("rectangle_light_colors"))
  533. {
  534. auto rectangle_light_corners_var = shader_program.variable("rectangle_light_corners");
  535. if (rectangle_light_corners_var)
  536. {
  537. command_buffer.emplace_back
  538. (
  539. [&, rectangle_light_colors_var, rectangle_light_corners_var]()
  540. {
  541. rectangle_light_colors_var->update(std::span<const float3>{rectangle_light_colors.data(), rectangle_light_count});
  542. rectangle_light_corners_var->update(std::span<const float3>{rectangle_light_corners.data(), rectangle_light_count * 4});
  543. }
  544. );
  545. }
  546. }
  547. }
  548. // Update directional light variables
  549. if (directional_light_count)
  550. {
  551. if (auto directional_light_colors_var = shader_program.variable("directional_light_colors"))
  552. {
  553. if (auto directional_light_directions_var = shader_program.variable("directional_light_directions"))
  554. {
  555. command_buffer.emplace_back
  556. (
  557. [&, directional_light_colors_var, directional_light_directions_var]()
  558. {
  559. directional_light_colors_var->update(std::span<const float3>{directional_light_colors.data(), directional_light_count});
  560. directional_light_directions_var->update(std::span<const float3>{directional_light_directions.data(), directional_light_count});
  561. }
  562. );
  563. }
  564. }
  565. }
  566. // Update directional shadow variables
  567. if (directional_shadow_count)
  568. {
  569. if (auto directional_shadow_maps_var = shader_program.variable("directional_shadow_maps"))
  570. {
  571. auto directional_shadow_biases_var = shader_program.variable("directional_shadow_biases");
  572. auto directional_shadow_splits_var = shader_program.variable("directional_shadow_splits");
  573. auto directional_shadow_matrices_var = shader_program.variable("directional_shadow_matrices");
  574. if (directional_shadow_maps_var && directional_shadow_biases_var && directional_shadow_splits_var && directional_shadow_matrices_var)
  575. {
  576. command_buffer.emplace_back
  577. (
  578. [&, directional_shadow_maps_var, directional_shadow_biases_var, directional_shadow_splits_var, directional_shadow_matrices_var]()
  579. {
  580. directional_shadow_maps_var->update(std::span<const gl::texture_2d* const>{directional_shadow_maps.data(), directional_shadow_count});
  581. directional_shadow_biases_var->update(std::span<const float>{directional_shadow_biases.data(), directional_shadow_count});
  582. std::size_t offset = 0;
  583. for (std::size_t i = 0; i < directional_shadow_count; ++i)
  584. {
  585. directional_shadow_splits_var->update(*directional_shadow_splits[i], offset * 4);
  586. directional_shadow_matrices_var->update(*directional_shadow_matrices[i], offset);
  587. offset += directional_shadow_splits[i]->size();
  588. }
  589. }
  590. );
  591. }
  592. }
  593. }
  594. // Update point light variables
  595. if (point_light_count)
  596. {
  597. if (auto point_light_colors_var = shader_program.variable("point_light_colors"))
  598. {
  599. auto point_light_positions_var = shader_program.variable("point_light_positions");
  600. if (point_light_positions_var)
  601. {
  602. command_buffer.emplace_back
  603. (
  604. [&, point_light_colors_var, point_light_positions_var]()
  605. {
  606. point_light_colors_var->update(std::span<const float3>{point_light_colors.data(), point_light_count});
  607. point_light_positions_var->update(std::span<const float3>{point_light_positions.data(), point_light_count});
  608. }
  609. );
  610. }
  611. }
  612. }
  613. // Update spot light variables
  614. if (spot_light_count)
  615. {
  616. if (auto spot_light_colors_var = shader_program.variable("spot_light_colors"))
  617. {
  618. auto spot_light_positions_var = shader_program.variable("spot_light_positions");
  619. auto spot_light_directions_var = shader_program.variable("spot_light_directions");
  620. auto spot_light_cutoffs_var = shader_program.variable("spot_light_cutoffs");
  621. if (spot_light_positions_var && spot_light_directions_var && spot_light_cutoffs_var)
  622. {
  623. command_buffer.emplace_back
  624. (
  625. [&, spot_light_colors_var, spot_light_positions_var, spot_light_directions_var, spot_light_cutoffs_var]()
  626. {
  627. spot_light_colors_var->update(std::span<const float3>{spot_light_colors.data(), spot_light_count});
  628. spot_light_positions_var->update(std::span<const float3>{spot_light_positions.data(), spot_light_count});
  629. spot_light_directions_var->update(std::span<const float3>{spot_light_directions.data(), spot_light_count});
  630. spot_light_cutoffs_var->update(std::span<const float2>{spot_light_cutoffs.data(), spot_light_count});
  631. }
  632. );
  633. }
  634. }
  635. }
  636. // Update time variable
  637. if (auto time_var = shader_program.variable("time"))
  638. {
  639. command_buffer.emplace_back([&, time_var](){time_var->update(time);});
  640. }
  641. // Update timestep variable
  642. if (auto timestep_var = shader_program.variable("timestep"))
  643. {
  644. command_buffer.emplace_back([&, timestep_var](){timestep_var->update(timestep);});
  645. }
  646. // Update frame variable
  647. if (auto frame_var = shader_program.variable("frame"))
  648. {
  649. command_buffer.emplace_back([&, frame_var](){frame_var->update(frame);});
  650. }
  651. // Update subframe variable
  652. if (auto subframe_var = shader_program.variable("subframe"))
  653. {
  654. command_buffer.emplace_back([&, subframe_var](){subframe_var->update(subframe);});
  655. }
  656. // Update resolution variable
  657. if (auto resolution_var = shader_program.variable("resolution"))
  658. {
  659. command_buffer.emplace_back([&, resolution_var](){resolution_var->update(resolution);});
  660. }
  661. // Update mouse position variable
  662. if (auto mouse_position_var = shader_program.variable("mouse_position"))
  663. {
  664. command_buffer.emplace_back([&, mouse_position_var](){mouse_position_var->update(mouse_position);});
  665. }
  666. }
  667. void material_pass::build_geometry_command_buffer(std::vector<std::function<void()>>& command_buffer, const gl::shader_program& shader_program) const
  668. {
  669. // Update model matrix variable
  670. if (auto model_var = shader_program.variable("model"))
  671. {
  672. command_buffer.emplace_back([&, model_var](){model_var->update(*model);});
  673. }
  674. // Update normal-model matrix variable
  675. if (auto normal_model_var = shader_program.variable("normal_model"))
  676. {
  677. command_buffer.emplace_back
  678. (
  679. [&, normal_model_var]()
  680. {
  681. normal_model_var->update(math::transpose(math::inverse(math::matrix<float, 3, 3>(*model))));
  682. }
  683. );
  684. }
  685. // Update model-view matrix and normal-model-view matrix variables
  686. auto model_view_var = shader_program.variable("model_view");
  687. auto normal_model_view_var = shader_program.variable("normal_model_view");
  688. if (model_view_var && normal_model_view_var)
  689. {
  690. command_buffer.emplace_back
  691. (
  692. [&, model_view_var, normal_model_view_var]()
  693. {
  694. const auto model_view = (*view) * (*model);
  695. model_view_var->update(model_view);
  696. normal_model_view_var->update(math::transpose(math::inverse(math::matrix<float, 3, 3>(model_view))));
  697. }
  698. );
  699. }
  700. else
  701. {
  702. if (model_view_var)
  703. {
  704. command_buffer.emplace_back([&, model_view_var](){model_view_var->update((*view) * (*model));});
  705. }
  706. else if (normal_model_view_var)
  707. {
  708. command_buffer.emplace_back
  709. (
  710. [&, normal_model_view_var]()
  711. {
  712. const auto model_view = (*view) * (*model);
  713. normal_model_view_var->update(math::transpose(math::inverse(math::matrix<float, 3, 3>(model_view))));
  714. }
  715. );
  716. }
  717. }
  718. // Update model-view-projection matrix variable
  719. if (auto model_view_projection_var = shader_program.variable("model_view_projection"))
  720. {
  721. command_buffer.emplace_back([&, model_view_projection_var](){model_view_projection_var->update((*view_projection) * (*model));});
  722. }
  723. // Update matrix palette variable
  724. if (auto matrix_palette_var = shader_program.variable("matrix_palette"))
  725. {
  726. command_buffer.emplace_back([&, matrix_palette_var](){matrix_palette_var->update(matrix_palette);});
  727. }
  728. }
  729. void material_pass::build_material_command_buffer(std::vector<std::function<void()>>& command_buffer, const gl::shader_program& shader_program, const material& material) const
  730. {
  731. for (const auto& [key, material_var]: material.get_variables())
  732. {
  733. if (!material_var)
  734. {
  735. continue;
  736. }
  737. const auto shader_var = shader_program.variable(key);
  738. if (!shader_var)
  739. {
  740. continue;
  741. }
  742. const std::size_t size = std::min<std::size_t>(material_var->size(), shader_var->size());
  743. switch (shader_var->type())
  744. {
  745. /// @TODO render::material_bool is broken due to the std::vector<bool> specialization.
  746. // case gl::shader_variable_type::bool1:
  747. // if (material_var->type() == material_variable_type::bool1)
  748. // {
  749. // command_buffer.emplace_back
  750. // (
  751. // [size, shader_var, material_var = std::static_pointer_cast<material_bool>(material_var)]()
  752. // {
  753. // shader_var->update(std::span<const bool>{material_var->data(), size});
  754. // }
  755. // );
  756. // }
  757. // break;
  758. case gl::shader_variable_type::bool2:
  759. if (material_var->type() == material_variable_type::bool2)
  760. {
  761. command_buffer.emplace_back
  762. (
  763. [size, shader_var, material_var = std::static_pointer_cast<material_bool2>(material_var)]()
  764. {
  765. shader_var->update(std::span<const bool2>{material_var->data(), size});
  766. }
  767. );
  768. }
  769. break;
  770. case gl::shader_variable_type::bool3:
  771. if (material_var->type() == material_variable_type::bool3)
  772. {
  773. command_buffer.emplace_back
  774. (
  775. [size, shader_var, material_var = std::static_pointer_cast<material_bool3>(material_var)]()
  776. {
  777. shader_var->update(std::span<const bool3>{material_var->data(), size});
  778. }
  779. );
  780. }
  781. break;
  782. case gl::shader_variable_type::bool4:
  783. if (material_var->type() == material_variable_type::bool4)
  784. {
  785. command_buffer.emplace_back
  786. (
  787. [size, shader_var, material_var = std::static_pointer_cast<material_bool4>(material_var)]()
  788. {
  789. shader_var->update(std::span<const bool4>{material_var->data(), size});
  790. }
  791. );
  792. }
  793. break;
  794. case gl::shader_variable_type::int1:
  795. if (material_var->type() == material_variable_type::int1)
  796. {
  797. command_buffer.emplace_back
  798. (
  799. [size, shader_var, material_var = std::static_pointer_cast<material_int>(material_var)]()
  800. {
  801. shader_var->update(std::span<const int>{material_var->data(), size});
  802. }
  803. );
  804. }
  805. break;
  806. case gl::shader_variable_type::int2:
  807. if (material_var->type() == material_variable_type::int2)
  808. {
  809. command_buffer.emplace_back
  810. (
  811. [size, shader_var, material_var = std::static_pointer_cast<material_int2>(material_var)]()
  812. {
  813. shader_var->update(std::span<const int2>{material_var->data(), size});
  814. }
  815. );
  816. }
  817. break;
  818. case gl::shader_variable_type::int3:
  819. if (material_var->type() == material_variable_type::int3)
  820. {
  821. command_buffer.emplace_back
  822. (
  823. [size, shader_var, material_var = std::static_pointer_cast<material_int3>(material_var)]()
  824. {
  825. shader_var->update(std::span<const int3>{material_var->data(), size});
  826. }
  827. );
  828. }
  829. break;
  830. case gl::shader_variable_type::int4:
  831. if (material_var->type() == material_variable_type::int4)
  832. {
  833. command_buffer.emplace_back
  834. (
  835. [size, shader_var, material_var = std::static_pointer_cast<material_int4>(material_var)]()
  836. {
  837. shader_var->update(std::span<const int4>{material_var->data(), size});
  838. }
  839. );
  840. }
  841. break;
  842. case gl::shader_variable_type::uint1:
  843. if (material_var->type() == material_variable_type::uint1)
  844. {
  845. command_buffer.emplace_back
  846. (
  847. [size, shader_var, material_var = std::static_pointer_cast<material_uint>(material_var)]()
  848. {
  849. shader_var->update(std::span<const unsigned int>{material_var->data(), size});
  850. }
  851. );
  852. }
  853. break;
  854. case gl::shader_variable_type::uint2:
  855. if (material_var->type() == material_variable_type::uint2)
  856. {
  857. command_buffer.emplace_back
  858. (
  859. [size, shader_var, material_var = std::static_pointer_cast<material_uint2>(material_var)]()
  860. {
  861. shader_var->update(std::span<const uint2>{material_var->data(), size});
  862. }
  863. );
  864. }
  865. break;
  866. case gl::shader_variable_type::uint3:
  867. if (material_var->type() == material_variable_type::uint3)
  868. {
  869. command_buffer.emplace_back
  870. (
  871. [size, shader_var, material_var = std::static_pointer_cast<material_uint3>(material_var)]()
  872. {
  873. shader_var->update(std::span<const uint3>{material_var->data(), size});
  874. }
  875. );
  876. }
  877. break;
  878. case gl::shader_variable_type::uint4:
  879. if (material_var->type() == material_variable_type::uint4)
  880. {
  881. command_buffer.emplace_back
  882. (
  883. [size, shader_var, material_var = std::static_pointer_cast<material_uint4>(material_var)]()
  884. {
  885. shader_var->update(std::span<const uint4>{material_var->data(), size});
  886. }
  887. );
  888. }
  889. break;
  890. case gl::shader_variable_type::float1:
  891. if (material_var->type() == material_variable_type::float1)
  892. {
  893. command_buffer.emplace_back
  894. (
  895. [size, shader_var, material_var = std::static_pointer_cast<material_float>(material_var)]()
  896. {
  897. shader_var->update(std::span<const float>{material_var->data(), size});
  898. }
  899. );
  900. }
  901. break;
  902. case gl::shader_variable_type::float2:
  903. if (material_var->type() == material_variable_type::float2)
  904. {
  905. command_buffer.emplace_back
  906. (
  907. [size, shader_var, material_var = std::static_pointer_cast<material_float2>(material_var)]()
  908. {
  909. shader_var->update(std::span<const float2>{material_var->data(), size});
  910. }
  911. );
  912. }
  913. break;
  914. case gl::shader_variable_type::float3:
  915. if (material_var->type() == material_variable_type::float3)
  916. {
  917. command_buffer.emplace_back
  918. (
  919. [size, shader_var, material_var = std::static_pointer_cast<material_float3>(material_var)]()
  920. {
  921. shader_var->update(std::span<const float3>{material_var->data(), size});
  922. }
  923. );
  924. }
  925. break;
  926. case gl::shader_variable_type::float4:
  927. if (material_var->type() == material_variable_type::float4)
  928. {
  929. command_buffer.emplace_back
  930. (
  931. [size, shader_var, material_var = std::static_pointer_cast<material_float4>(material_var)]()
  932. {
  933. shader_var->update(std::span<const float4>{material_var->data(), size});
  934. }
  935. );
  936. }
  937. break;
  938. case gl::shader_variable_type::float2x2:
  939. if (material_var->type() == material_variable_type::float2x2)
  940. {
  941. command_buffer.emplace_back
  942. (
  943. [size, shader_var, material_var = std::static_pointer_cast<material_float2x2>(material_var)]()
  944. {
  945. shader_var->update(std::span<const float2x2>{material_var->data(), size});
  946. }
  947. );
  948. }
  949. break;
  950. case gl::shader_variable_type::float3x3:
  951. if (material_var->type() == material_variable_type::float3x3)
  952. {
  953. command_buffer.emplace_back
  954. (
  955. [size, shader_var, material_var = std::static_pointer_cast<material_float3x3>(material_var)]()
  956. {
  957. shader_var->update(std::span<const float3x3>{material_var->data(), size});
  958. }
  959. );
  960. }
  961. break;
  962. case gl::shader_variable_type::float4x4:
  963. if (material_var->type() == material_variable_type::float4x4)
  964. {
  965. command_buffer.emplace_back
  966. (
  967. [size, shader_var, material_var = std::static_pointer_cast<material_float4x4>(material_var)]()
  968. {
  969. shader_var->update(std::span<const float4x4>{material_var->data(), size});
  970. }
  971. );
  972. }
  973. break;
  974. case gl::shader_variable_type::texture_1d:
  975. if (material_var->type() == material_variable_type::texture_1d)
  976. {
  977. command_buffer.emplace_back
  978. (
  979. [size, shader_var, material_var = std::static_pointer_cast<material_texture_1d>(material_var)]()
  980. {
  981. shader_var->update(std::span<const std::shared_ptr<gl::texture_1d>>{material_var->data(), size});
  982. }
  983. );
  984. }
  985. break;
  986. case gl::shader_variable_type::texture_2d:
  987. if (material_var->type() == material_variable_type::texture_2d)
  988. {
  989. command_buffer.emplace_back
  990. (
  991. [size, shader_var, material_var = std::static_pointer_cast<material_texture_2d>(material_var)]()
  992. {
  993. shader_var->update(std::span<const std::shared_ptr<gl::texture_2d>>{material_var->data(), size});
  994. }
  995. );
  996. }
  997. break;
  998. case gl::shader_variable_type::texture_3d:
  999. if (material_var->type() == material_variable_type::texture_3d)
  1000. {
  1001. command_buffer.emplace_back
  1002. (
  1003. [size, shader_var, material_var = std::static_pointer_cast<material_texture_3d>(material_var)]()
  1004. {
  1005. shader_var->update(std::span<const std::shared_ptr<gl::texture_3d>>{material_var->data(), size});
  1006. }
  1007. );
  1008. }
  1009. break;
  1010. case gl::shader_variable_type::texture_cube:
  1011. if (material_var->type() == material_variable_type::texture_cube)
  1012. {
  1013. command_buffer.emplace_back
  1014. (
  1015. [size, shader_var, material_var = std::static_pointer_cast<material_texture_cube>(material_var)]()
  1016. {
  1017. shader_var->update(std::span<const std::shared_ptr<gl::texture_cube>>{material_var->data(), size});
  1018. }
  1019. );
  1020. }
  1021. break;
  1022. default:
  1023. break;
  1024. }
  1025. }
  1026. }
  1027. } // namespace render