💿🐜 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.

548 lines
19 KiB

  1. /*
  2. * Copyright (C) 2020 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 "renderer/passes/material-pass.hpp"
  20. #include "configuration.hpp"
  21. #include "resources/resource-manager.hpp"
  22. #include "rasterizer/rasterizer.hpp"
  23. #include "rasterizer/framebuffer.hpp"
  24. #include "rasterizer/shader.hpp"
  25. #include "rasterizer/shader-type.hpp"
  26. #include "rasterizer/shader-program.hpp"
  27. #include "rasterizer/shader-input.hpp"
  28. #include "rasterizer/vertex-buffer.hpp"
  29. #include "rasterizer/vertex-array.hpp"
  30. #include "rasterizer/vertex-attribute-type.hpp"
  31. #include "rasterizer/drawing-mode.hpp"
  32. #include "rasterizer/texture-2d.hpp"
  33. #include "rasterizer/texture-wrapping.hpp"
  34. #include "rasterizer/texture-filter.hpp"
  35. #include "renderer/vertex-attributes.hpp"
  36. #include "renderer/material-flags.hpp"
  37. #include "renderer/model.hpp"
  38. #include "renderer/render-context.hpp"
  39. #include "scene/camera.hpp"
  40. #include "scene/scene.hpp"
  41. #include "scene/ambient-light.hpp"
  42. #include "scene/directional-light.hpp"
  43. #include "scene/point-light.hpp"
  44. #include "scene/spotlight.hpp"
  45. #include "scene/scene.hpp"
  46. #include "configuration.hpp"
  47. #include "math/math.hpp"
  48. #include <cmath>
  49. #include <glad/glad.h>
  50. #include <iostream>
  51. #include "shadow-map-pass.hpp"
  52. static bool operation_compare(const render_operation& a, const render_operation& b);
  53. material_pass::material_pass(::rasterizer* rasterizer, const ::framebuffer* framebuffer, resource_manager* resource_manager):
  54. render_pass(rasterizer, framebuffer),
  55. fallback_material(nullptr),
  56. time_tween(nullptr),
  57. focal_point_tween(nullptr),
  58. shadow_map_pass(nullptr),
  59. shadow_map(nullptr)
  60. {
  61. soft_shadows_texture = resource_manager->load<texture_2d>("tree-shadow.png");
  62. soft_shadows_texture->set_wrapping(texture_wrapping::clamp, texture_wrapping::clamp);
  63. soft_shadows_texture->set_filters(texture_min_filter::linear_mipmap_linear, texture_mag_filter::linear);
  64. max_ambient_light_count = MATERIAL_PASS_MAX_AMBIENT_LIGHT_COUNT;
  65. max_point_light_count = MATERIAL_PASS_MAX_POINT_LIGHT_COUNT;
  66. max_directional_light_count = MATERIAL_PASS_MAX_DIRECTIONAL_LIGHT_COUNT;
  67. max_spotlight_count = MATERIAL_PASS_MAX_SPOTLIGHT_COUNT;
  68. ambient_light_colors = new float3[max_ambient_light_count];
  69. point_light_colors = new float3[max_point_light_count];
  70. point_light_positions = new float3[max_point_light_count];
  71. point_light_attenuations = new float3[max_point_light_count];
  72. directional_light_colors = new float3[max_directional_light_count];
  73. directional_light_directions = new float3[max_directional_light_count];
  74. spotlight_colors = new float3[max_spotlight_count];
  75. spotlight_positions = new float3[max_spotlight_count];
  76. spotlight_directions = new float3[max_spotlight_count];
  77. spotlight_attenuations = new float3[max_spotlight_count];
  78. spotlight_cutoffs = new float2[max_spotlight_count];
  79. }
  80. material_pass::~material_pass()
  81. {
  82. delete[] ambient_light_colors;
  83. delete[] point_light_colors;
  84. delete[] point_light_positions;
  85. delete[] point_light_attenuations;
  86. delete[] directional_light_colors;
  87. delete[] directional_light_directions;
  88. delete[] spotlight_colors;
  89. delete[] spotlight_positions;
  90. delete[] spotlight_directions;
  91. delete[] spotlight_attenuations;
  92. delete[] spotlight_cutoffs;
  93. }
  94. void material_pass::render(render_context* context) const
  95. {
  96. rasterizer->use_framebuffer(*framebuffer);
  97. glDisable(GL_BLEND);
  98. glEnable(GL_DEPTH_TEST);
  99. glDepthFunc(GL_LESS);
  100. glDepthMask(GL_TRUE);
  101. glDepthFunc(GL_LESS);
  102. glEnable(GL_CULL_FACE);
  103. glCullFace(GL_BACK);
  104. auto viewport = framebuffer->get_dimensions();
  105. rasterizer->set_viewport(0, 0, std::get<0>(viewport), std::get<1>(viewport));
  106. float2 resolution = {static_cast<float>(std::get<0>(viewport)), static_cast<float>(std::get<1>(viewport))};
  107. float time = (time_tween) ? time_tween->interpolate(context->alpha) : 0.0f;
  108. float3 focal_point = (focal_point_tween) ? focal_point_tween->interpolate(context->alpha) : float3{0, 0, 0};
  109. float4x4 view = context->camera->get_view_tween().interpolate(context->alpha);
  110. float4x4 projection = context->camera->get_projection_tween().interpolate(context->alpha);
  111. float4x4 view_projection = projection * view;
  112. float4x4 model_view_projection;
  113. float4x4 model;
  114. float4x4 model_view;
  115. float3x3 normal_model_view;
  116. int active_material_flags = 0;
  117. const ::shader_program* active_shader_program = nullptr;
  118. const ::material* active_material = nullptr;
  119. const parameter_set* parameters = nullptr;
  120. // Reset light counts
  121. ambient_light_count = 0;
  122. point_light_count = 0;
  123. directional_light_count = 0;
  124. spotlight_count = 0;
  125. // Collect lights
  126. const std::list<scene_object_base*>* lights = context->scene->get_objects(light::object_type_id);
  127. for (const scene_object_base* object: *lights)
  128. {
  129. // Skip inactive lights
  130. if (!object->is_active())
  131. continue;
  132. const ::light* light = static_cast<const ::light*>(object);
  133. switch (light->get_light_type())
  134. {
  135. // Add ambient light
  136. case light_type::ambient:
  137. {
  138. if (ambient_light_count < max_ambient_light_count)
  139. {
  140. ambient_light_colors[ambient_light_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  141. ++ambient_light_count;
  142. }
  143. break;
  144. }
  145. // Add point light
  146. case light_type::point:
  147. {
  148. if (point_light_count < max_point_light_count)
  149. {
  150. point_light_colors[point_light_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  151. // Transform position into view-space
  152. float3 position = light->get_transform_tween().interpolate(context->alpha).translation;
  153. float3 view_space_position = math::resize<3>(view * float4{position.x, position.y, position.z, 1.0f});
  154. point_light_positions[point_light_count] = view_space_position;
  155. point_light_attenuations[point_light_count] = static_cast<const point_light*>(light)->get_attenuation_tween().interpolate(context->alpha);
  156. ++point_light_count;
  157. }
  158. break;
  159. }
  160. // Add directional light
  161. case light_type::directional:
  162. {
  163. if (directional_light_count < max_directional_light_count)
  164. {
  165. directional_light_colors[directional_light_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  166. // Transform direction into view-space
  167. float3 direction = static_cast<const directional_light*>(light)->get_direction_tween().interpolate(context->alpha);
  168. float3 view_space_direction = math::normalize(math::resize<3>(view * math::resize<4>(-direction)));
  169. directional_light_directions[directional_light_count] = view_space_direction;
  170. ++directional_light_count;
  171. }
  172. break;
  173. }
  174. // Add spotlight
  175. case light_type::spot:
  176. {
  177. if (spotlight_count < max_spotlight_count)
  178. {
  179. spotlight_colors[spotlight_count] = light->get_scaled_color_tween().interpolate(context->alpha);
  180. // Transform position into view-space
  181. float3 position = light->get_transform_tween().interpolate(context->alpha).translation;
  182. float3 view_space_position = math::resize<3>(view * float4{position.x, position.y, position.z, 1.0f});
  183. spotlight_positions[spotlight_count] = view_space_position;
  184. const ::spotlight* spotlight = static_cast<const ::spotlight*>(light);
  185. // Transform direction into view-space
  186. float3 direction = spotlight->get_direction_tween().interpolate(context->alpha);
  187. float3 view_space_direction = math::normalize(math::resize<3>(view * math::resize<4>(-direction)));
  188. spotlight_directions[spotlight_count] = view_space_direction;
  189. spotlight_attenuations[spotlight_count] = spotlight->get_attenuation_tween().interpolate(context->alpha);
  190. spotlight_cutoffs[spotlight_count] = spotlight->get_cosine_cutoff_tween().interpolate(context->alpha);
  191. ++spotlight_count;
  192. }
  193. break;
  194. }
  195. default:
  196. break;
  197. }
  198. }
  199. float4x4 shadow_map_matrices[4];
  200. float4 shadow_map_split_distances;
  201. if (shadow_map_pass)
  202. {
  203. for (int i = 0; i < 4; ++i)
  204. shadow_map_matrices[i] = shadow_map_pass->get_shadow_matrices()[i];
  205. // Calculate shadow map split distances
  206. for (int i = 0; i < 4; ++i)
  207. shadow_map_split_distances[i] = shadow_map_pass->get_split_distances()[i + 1];
  208. }
  209. // Sort render operations
  210. context->operations.sort(operation_compare);
  211. for (const render_operation& operation: context->operations)
  212. {
  213. // Get operation material
  214. const ::material* material = operation.material;
  215. if (!material)
  216. {
  217. if (fallback_material)
  218. {
  219. // No material specified, use fallback material
  220. material = fallback_material;
  221. }
  222. else
  223. {
  224. // No material specified and no fallback material, skip operation
  225. continue;
  226. }
  227. }
  228. // Switch materials if necessary
  229. if (active_material != material)
  230. {
  231. active_material = material;
  232. // Change rasterizer state according to material flags
  233. std::uint32_t material_flags = active_material->get_flags();
  234. if (active_material_flags != material_flags)
  235. {
  236. if ((material_flags & MATERIAL_FLAG_TRANSLUCENT) != (active_material_flags & MATERIAL_FLAG_TRANSLUCENT))
  237. {
  238. if (material_flags & MATERIAL_FLAG_TRANSLUCENT)
  239. {
  240. glEnable(GL_BLEND);
  241. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  242. }
  243. else
  244. {
  245. glDisable(GL_BLEND);
  246. }
  247. }
  248. if ((material_flags & MATERIAL_FLAG_BACK_FACES) != (active_material_flags & MATERIAL_FLAG_BACK_FACES))
  249. {
  250. if (material_flags & MATERIAL_FLAG_BACK_FACES)
  251. {
  252. glEnable(GL_CULL_FACE);
  253. glCullFace(GL_FRONT);
  254. }
  255. else
  256. {
  257. glEnable(GL_CULL_FACE);
  258. glCullFace(GL_BACK);
  259. }
  260. }
  261. else if ((material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES) != (active_material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES))
  262. {
  263. if (material_flags & MATERIAL_FLAG_FRONT_AND_BACK_FACES)
  264. {
  265. glDisable(GL_CULL_FACE);
  266. }
  267. else
  268. {
  269. glEnable(GL_CULL_FACE);
  270. glCullFace(GL_BACK);
  271. }
  272. }
  273. if ((material_flags & MATERIAL_FLAG_X_RAY) != (active_material_flags & MATERIAL_FLAG_X_RAY))
  274. {
  275. if (material_flags & MATERIAL_FLAG_X_RAY)
  276. {
  277. glDisable(GL_DEPTH_TEST);
  278. }
  279. else
  280. {
  281. glEnable(GL_DEPTH_TEST);
  282. }
  283. }
  284. active_material_flags = material_flags;
  285. }
  286. // Switch shaders if necessary
  287. const ::shader_program* shader_program = active_material->get_shader_program();
  288. if (active_shader_program != shader_program)
  289. {
  290. active_shader_program = shader_program;
  291. if (!active_shader_program)
  292. {
  293. continue;
  294. }
  295. // Change shader program
  296. rasterizer->use_program(*active_shader_program);
  297. // Get set of known shader input parameters
  298. if (auto it = parameter_sets.find(active_shader_program); it != parameter_sets.end())
  299. {
  300. parameters = it->second;
  301. }
  302. else
  303. {
  304. parameters = load_parameter_set(active_shader_program);
  305. }
  306. // Upload context-dependent shader parameters
  307. if (parameters->time)
  308. parameters->time->upload(time);
  309. if (parameters->resolution)
  310. parameters->resolution->upload(resolution);
  311. if (parameters->view)
  312. parameters->view->upload(view);
  313. if (parameters->view_projection)
  314. parameters->view_projection->upload(view_projection);
  315. if (parameters->ambient_light_count)
  316. parameters->ambient_light_count->upload(ambient_light_count);
  317. if (parameters->ambient_light_colors)
  318. parameters->ambient_light_colors->upload(0, ambient_light_colors, ambient_light_count);
  319. if (parameters->point_light_count)
  320. parameters->point_light_count->upload(point_light_count);
  321. if (parameters->point_light_colors)
  322. parameters->point_light_colors->upload(0, point_light_colors, point_light_count);
  323. if (parameters->point_light_positions)
  324. parameters->point_light_positions->upload(0, point_light_positions, point_light_count);
  325. if (parameters->point_light_attenuations)
  326. parameters->point_light_attenuations->upload(0, point_light_attenuations, point_light_count);
  327. if (parameters->directional_light_count)
  328. parameters->directional_light_count->upload(directional_light_count);
  329. if (parameters->directional_light_colors)
  330. parameters->directional_light_colors->upload(0, directional_light_colors, directional_light_count);
  331. if (parameters->directional_light_directions)
  332. parameters->directional_light_directions->upload(0, directional_light_directions, directional_light_count);
  333. if (parameters->spotlight_count)
  334. parameters->spotlight_count->upload(spotlight_count);
  335. if (parameters->spotlight_colors)
  336. parameters->spotlight_colors->upload(0, spotlight_colors, spotlight_count);
  337. if (parameters->spotlight_positions)
  338. parameters->spotlight_positions->upload(0, spotlight_positions, spotlight_count);
  339. if (parameters->spotlight_directions)
  340. parameters->spotlight_directions->upload(0, spotlight_directions, spotlight_count);
  341. if (parameters->spotlight_attenuations)
  342. parameters->spotlight_attenuations->upload(0, spotlight_attenuations, spotlight_count);
  343. if (parameters->spotlight_cutoffs)
  344. parameters->spotlight_cutoffs->upload(0, spotlight_cutoffs, spotlight_count);
  345. if (parameters->soft_shadows)
  346. parameters->soft_shadows->upload(soft_shadows_texture);
  347. if (parameters->focal_point)
  348. parameters->focal_point->upload(focal_point);
  349. if (parameters->shadow_map_matrices)
  350. parameters->shadow_map_matrices->upload(0, shadow_map_matrices, 4);
  351. if (parameters->shadow_map_split_distances)
  352. parameters->shadow_map_split_distances->upload(shadow_map_split_distances);
  353. if (parameters->shadow_map && shadow_map)
  354. parameters->shadow_map->upload(shadow_map);
  355. }
  356. // Upload material properties to shader
  357. active_material->upload(context->alpha);
  358. }
  359. // Calculate operation-dependent parameters
  360. model = operation.transform;
  361. model_view_projection = view_projection * model;
  362. model_view = view * model;
  363. normal_model_view = math::transpose(math::inverse(math::resize<3, 3>(model_view)));
  364. // Upload operation-dependent parameters
  365. if (parameters->model)
  366. parameters->model->upload(model);
  367. if (parameters->model_view)
  368. parameters->model_view->upload(model_view);
  369. if (parameters->model_view_projection)
  370. parameters->model_view_projection->upload(model_view_projection);
  371. if (parameters->normal_model_view)
  372. parameters->normal_model_view->upload(normal_model_view);
  373. // Draw geometry
  374. if (operation.instance_count)
  375. rasterizer->draw_arrays_instanced(*operation.vertex_array, operation.drawing_mode, operation.start_index, operation.index_count, operation.instance_count);
  376. else
  377. rasterizer->draw_arrays(*operation.vertex_array, operation.drawing_mode, operation.start_index, operation.index_count);
  378. }
  379. }
  380. void material_pass::set_fallback_material(const material* fallback)
  381. {
  382. this->fallback_material = fallback;
  383. }
  384. void material_pass::set_time_tween(const tween<double>* time)
  385. {
  386. this->time_tween = time;
  387. }
  388. void material_pass::set_focal_point_tween(const tween<float3>* focal_point)
  389. {
  390. this->focal_point_tween = focal_point;
  391. }
  392. const material_pass::parameter_set* material_pass::load_parameter_set(const shader_program* program) const
  393. {
  394. // Allocate a new parameter set
  395. parameter_set* parameters = new parameter_set();
  396. // Connect inputs
  397. parameters->time = program->get_input("time");
  398. parameters->resolution = program->get_input("resolution");
  399. parameters->model = program->get_input("model");
  400. parameters->view = program->get_input("view");
  401. parameters->projection = program->get_input("projection");
  402. parameters->model_view = program->get_input("model_view");
  403. parameters->view_projection = program->get_input("view_projection");
  404. parameters->model_view_projection = program->get_input("model_view_projection");
  405. parameters->normal_model_view = program->get_input("normal_model_view");
  406. parameters->ambient_light_count = program->get_input("ambient_light_count");
  407. parameters->ambient_light_colors = program->get_input("ambient_light_colors");
  408. parameters->point_light_count = program->get_input("point_light_count");
  409. parameters->point_light_colors = program->get_input("point_light_colors");
  410. parameters->point_light_positions = program->get_input("point_light_positions");
  411. parameters->point_light_attenuations = program->get_input("point_light_attenuations");
  412. parameters->directional_light_count = program->get_input("directional_light_count");
  413. parameters->directional_light_colors = program->get_input("directional_light_colors");
  414. parameters->directional_light_directions = program->get_input("directional_light_directions");
  415. parameters->spotlight_count = program->get_input("spotlight_count");
  416. parameters->spotlight_colors = program->get_input("spotlight_colors");
  417. parameters->spotlight_positions = program->get_input("spotlight_positions");
  418. parameters->spotlight_directions = program->get_input("spotlight_directions");
  419. parameters->spotlight_attenuations = program->get_input("spotlight_attenuations");
  420. parameters->spotlight_cutoffs = program->get_input("spotlight_cutoffs");
  421. parameters->soft_shadows = program->get_input("soft_shadows");
  422. parameters->focal_point = program->get_input("focal_point");
  423. parameters->shadow_map_matrices = program->get_input("shadow_map_matrices");
  424. parameters->shadow_map_split_distances = program->get_input("shadow_map_split_distances");
  425. parameters->shadow_map = program->get_input("shadow_map");
  426. // Add parameter set to map of parameter sets
  427. parameter_sets[program] = parameters;
  428. return parameters;
  429. }
  430. bool operation_compare(const render_operation& a, const render_operation& b)
  431. {
  432. if (!a.material)
  433. return false;
  434. else if (!b.material)
  435. return true;
  436. // Determine transparency
  437. bool transparent_a = a.material->get_flags() & MATERIAL_FLAG_TRANSLUCENT;
  438. bool transparent_b = b.material->get_flags() & MATERIAL_FLAG_TRANSLUCENT;
  439. if (transparent_a)
  440. {
  441. if (transparent_b)
  442. {
  443. // A and B are both transparent, render back to front
  444. return (a.depth >= b.depth);
  445. }
  446. else
  447. {
  448. // A is transparent, B is opaque. Render B first
  449. return false;
  450. }
  451. }
  452. else
  453. {
  454. if (transparent_b)
  455. {
  456. // A is opaque, B is transparent. Render A first
  457. return true;
  458. }
  459. else
  460. {
  461. // A and B are both opaque
  462. if (a.material->get_shader_program() == b.material->get_shader_program())
  463. {
  464. // A and B have the same shader
  465. if (a.vertex_array == b.vertex_array)
  466. {
  467. // A and B have the same VAO, render front to back
  468. return (a.depth < b.depth);
  469. }
  470. else
  471. {
  472. // Sort by VAO
  473. return (a.vertex_array < b.vertex_array);
  474. }
  475. }
  476. else
  477. {
  478. // A and B are both opaque and have different shaders, sort by shader
  479. return (a.material->get_shader_program() < b.material->get_shader_program());
  480. }
  481. }
  482. }
  483. }