]> git.lizzy.rs Git - dragonfireclient.git/blob - src/client/shadows/dynamicshadowsrender.cpp
Remove unused ITextSceneNode header (#11476)
[dragonfireclient.git] / src / client / shadows / dynamicshadowsrender.cpp
1 /*
2 Minetest
3 Copyright (C) 2021 Liso <anlismon@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <cstring>
21 #include "client/shadows/dynamicshadowsrender.h"
22 #include "client/shadows/shadowsScreenQuad.h"
23 #include "client/shadows/shadowsshadercallbacks.h"
24 #include "settings.h"
25 #include "filesys.h"
26 #include "util/string.h"
27 #include "client/shader.h"
28 #include "client/client.h"
29 #include "client/clientmap.h"
30
31 ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) :
32                 m_device(device), m_smgr(device->getSceneManager()),
33                 m_driver(device->getVideoDriver()), m_client(client)
34 {
35         m_shadows_enabled = true;
36
37         m_shadow_strength = g_settings->getFloat("shadow_strength");
38
39         m_shadow_map_max_distance = g_settings->getFloat("shadow_map_max_distance");
40
41         m_shadow_map_texture_size = g_settings->getFloat("shadow_map_texture_size");
42
43         m_shadow_map_texture_32bit = g_settings->getBool("shadow_map_texture_32bit");
44         m_shadow_map_colored = g_settings->getBool("shadow_map_color");
45         m_shadow_samples = g_settings->getS32("shadow_filters");
46         m_update_delta = g_settings->getFloat("shadow_update_time");
47 }
48
49 ShadowRenderer::~ShadowRenderer()
50 {
51         if (m_shadow_depth_cb)
52                 delete m_shadow_depth_cb;
53         if (m_shadow_mix_cb)
54                 delete m_shadow_mix_cb;
55         m_shadow_node_array.clear();
56         m_light_list.clear();
57
58         if (shadowMapTextureDynamicObjects)
59                 m_driver->removeTexture(shadowMapTextureDynamicObjects);
60
61         if (shadowMapTextureFinal)
62                 m_driver->removeTexture(shadowMapTextureFinal);
63
64         if (shadowMapTextureColors)
65                 m_driver->removeTexture(shadowMapTextureColors);
66
67         if (shadowMapClientMap)
68                 m_driver->removeTexture(shadowMapClientMap);
69 }
70
71 void ShadowRenderer::initialize()
72 {
73         auto *gpu = m_driver->getGPUProgrammingServices();
74
75         // we need glsl
76         if (m_shadows_enabled && gpu && m_driver->queryFeature(video::EVDF_ARB_GLSL)) {
77                 createShaders();
78         } else {
79                 m_shadows_enabled = false;
80
81                 warningstream << "Shadows: GLSL Shader not supported on this system."
82                         << std::endl;
83                 return;
84         }
85
86         m_texture_format = m_shadow_map_texture_32bit
87                                            ? video::ECOLOR_FORMAT::ECF_R32F
88                                            : video::ECOLOR_FORMAT::ECF_R16F;
89
90         m_texture_format_color = m_shadow_map_texture_32bit
91                                                  ? video::ECOLOR_FORMAT::ECF_G32R32F
92                                                  : video::ECOLOR_FORMAT::ECF_G16R16F;
93 }
94
95
96 float ShadowRenderer::getUpdateDelta() const
97 {
98         return m_update_delta;
99 }
100
101 size_t ShadowRenderer::addDirectionalLight()
102 {
103         m_light_list.emplace_back(m_shadow_map_texture_size,
104                         v3f(0.f, 0.f, 0.f),
105                         video::SColor(255, 255, 255, 255), m_shadow_map_max_distance);
106         return m_light_list.size() - 1;
107 }
108
109 DirectionalLight &ShadowRenderer::getDirectionalLight(u32 index)
110 {
111         return m_light_list[index];
112 }
113
114 size_t ShadowRenderer::getDirectionalLightCount() const
115 {
116         return m_light_list.size();
117 }
118
119 f32 ShadowRenderer::getMaxShadowFar() const
120 {
121         if (!m_light_list.empty()) {
122                 float wanted_range = m_client->getEnv().getClientMap().getWantedRange();
123
124                 float zMax = m_light_list[0].getMaxFarValue() > wanted_range
125                                              ? wanted_range
126                                              : m_light_list[0].getMaxFarValue();
127                 return zMax * MAP_BLOCKSIZE;
128         }
129         return 0.0f;
130 }
131
132 void ShadowRenderer::addNodeToShadowList(
133                 scene::ISceneNode *node, E_SHADOW_MODE shadowMode)
134 {
135         m_shadow_node_array.emplace_back(NodeToApply(node, shadowMode));
136 }
137
138 void ShadowRenderer::removeNodeFromShadowList(scene::ISceneNode *node)
139 {
140         for (auto it = m_shadow_node_array.begin(); it != m_shadow_node_array.end();) {
141                 if (it->node == node) {
142                         it = m_shadow_node_array.erase(it);
143                         break;
144                 } else {
145                         ++it;
146                 }
147         }
148 }
149
150 void ShadowRenderer::setClearColor(video::SColor ClearColor)
151 {
152         m_clear_color = ClearColor;
153 }
154
155 void ShadowRenderer::update(video::ITexture *outputTarget)
156 {
157         if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) {
158                 m_smgr->drawAll();
159                 return;
160         }
161
162         if (!shadowMapTextureDynamicObjects) {
163
164                 shadowMapTextureDynamicObjects = getSMTexture(
165                         std::string("shadow_dynamic_") + itos(m_shadow_map_texture_size),
166                         m_texture_format, true);
167         }
168
169         if (!shadowMapClientMap) {
170
171                 shadowMapClientMap = getSMTexture(
172                         std::string("shadow_clientmap_") + itos(m_shadow_map_texture_size),
173                         m_shadow_map_colored ? m_texture_format_color : m_texture_format,
174                         true);
175         }
176
177         if (m_shadow_map_colored && !shadowMapTextureColors) {
178                 shadowMapTextureColors = getSMTexture(
179                         std::string("shadow_colored_") + itos(m_shadow_map_texture_size),
180                         m_shadow_map_colored ? m_texture_format_color : m_texture_format,
181                         true);
182         }
183
184         // The merge all shadowmaps texture
185         if (!shadowMapTextureFinal) {
186                 video::ECOLOR_FORMAT frt;
187                 if (m_shadow_map_texture_32bit) {
188                         if (m_shadow_map_colored)
189                                 frt = video::ECOLOR_FORMAT::ECF_A32B32G32R32F;
190                         else
191                                 frt = video::ECOLOR_FORMAT::ECF_R32F;
192                 } else {
193                         if (m_shadow_map_colored)
194                                 frt = video::ECOLOR_FORMAT::ECF_A16B16G16R16F;
195                         else
196                                 frt = video::ECOLOR_FORMAT::ECF_R16F;
197                 }
198                 shadowMapTextureFinal = getSMTexture(
199                         std::string("shadowmap_final_") + itos(m_shadow_map_texture_size),
200                         frt, true);
201         }
202
203         if (!m_shadow_node_array.empty() && !m_light_list.empty()) {
204                 // for every directional light:
205                 for (DirectionalLight &light : m_light_list) {
206                         // Static shader values.
207                         m_shadow_depth_cb->MapRes = (f32)m_shadow_map_texture_size;
208                         m_shadow_depth_cb->MaxFar = (f32)m_shadow_map_max_distance * BS;
209
210                         // set the Render Target
211                         // right now we can only render in usual RTT, not
212                         // Depth texture is available in irrlicth maybe we
213                         // should put some gl* fn here
214
215                         if (light.should_update_map_shadow) {
216                                 light.should_update_map_shadow = false;
217
218                                 m_driver->setRenderTarget(shadowMapClientMap, true, true,
219                                                 video::SColor(255, 255, 255, 255));
220                                 renderShadowMap(shadowMapClientMap, light);
221
222                                 if (m_shadow_map_colored) {
223                                         m_driver->setRenderTarget(shadowMapTextureColors,
224                                                         true, false, video::SColor(255, 255, 255, 255));
225                                 }
226                                 renderShadowMap(shadowMapTextureColors, light,
227                                                 scene::ESNRP_TRANSPARENT);
228                                 m_driver->setRenderTarget(0, false, false);
229                         }
230
231                         // render shadows for the n0n-map objects.
232                         m_driver->setRenderTarget(shadowMapTextureDynamicObjects, true,
233                                         true, video::SColor(255, 255, 255, 255));
234                         renderShadowObjects(shadowMapTextureDynamicObjects, light);
235                         // clear the Render Target
236                         m_driver->setRenderTarget(0, false, false);
237
238                         // in order to avoid too many map shadow renders,
239                         // we should make a second pass to mix clientmap shadows and
240                         // entities shadows :(
241                         m_screen_quad->getMaterial().setTexture(0, shadowMapClientMap);
242                         // dynamic objs shadow texture.
243                         if (m_shadow_map_colored)
244                                 m_screen_quad->getMaterial().setTexture(1, shadowMapTextureColors);
245                         m_screen_quad->getMaterial().setTexture(2, shadowMapTextureDynamicObjects);
246
247                         m_driver->setRenderTarget(shadowMapTextureFinal, false, false,
248                                         video::SColor(255, 255, 255, 255));
249                         m_screen_quad->render(m_driver);
250                         m_driver->setRenderTarget(0, false, false);
251
252                 } // end for lights
253
254                 // now render the actual MT render pass
255                 m_driver->setRenderTarget(outputTarget, true, true, m_clear_color);
256                 m_smgr->drawAll();
257
258                 /* this code just shows shadows textures in screen and in ONLY for debugging*/
259                 #if 0
260                 // this is debug, ignore for now.
261                 m_driver->draw2DImage(shadowMapTextureFinal,
262                                 core::rect<s32>(0, 50, 128, 128 + 50),
263                                 core::rect<s32>({0, 0}, shadowMapTextureFinal->getSize()));
264
265                 m_driver->draw2DImage(shadowMapClientMap,
266                                 core::rect<s32>(0, 50 + 128, 128, 128 + 50 + 128),
267                                 core::rect<s32>({0, 0}, shadowMapTextureFinal->getSize()));
268                 m_driver->draw2DImage(shadowMapTextureDynamicObjects,
269                                 core::rect<s32>(0, 128 + 50 + 128, 128,
270                                                 128 + 50 + 128 + 128),
271                                 core::rect<s32>({0, 0}, shadowMapTextureDynamicObjects->getSize()));
272
273                 if (m_shadow_map_colored) {
274
275                         m_driver->draw2DImage(shadowMapTextureColors,
276                                         core::rect<s32>(128,128 + 50 + 128 + 128,
277                                                         128 + 128, 128 + 50 + 128 + 128 + 128),
278                                         core::rect<s32>({0, 0}, shadowMapTextureColors->getSize()));
279                 }
280                 #endif
281                 m_driver->setRenderTarget(0, false, false);
282         }
283 }
284
285
286 video::ITexture *ShadowRenderer::getSMTexture(const std::string &shadow_map_name,
287                 video::ECOLOR_FORMAT texture_format, bool force_creation)
288 {
289         if (force_creation) {
290                 return m_driver->addRenderTargetTexture(
291                                 core::dimension2du(m_shadow_map_texture_size,
292                                                 m_shadow_map_texture_size),
293                                 shadow_map_name.c_str(), texture_format);
294         }
295
296         return m_driver->getTexture(shadow_map_name.c_str());
297 }
298
299 void ShadowRenderer::renderShadowMap(video::ITexture *target,
300                 DirectionalLight &light, scene::E_SCENE_NODE_RENDER_PASS pass)
301 {
302         m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix());
303         m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix());
304
305         // Operate on the client map
306         for (const auto &shadow_node : m_shadow_node_array) {
307                 if (strcmp(shadow_node.node->getName(), "ClientMap") != 0)
308                         continue;
309
310                 ClientMap *map_node = static_cast<ClientMap *>(shadow_node.node);
311
312                 video::SMaterial material;
313                 if (map_node->getMaterialCount() > 0) {
314                         // we only want the first material, which is the one with the albedo info
315                         material = map_node->getMaterial(0);
316                 }
317
318                 material.BackfaceCulling = false;
319                 material.FrontfaceCulling = true;
320                 material.PolygonOffsetFactor = 4.0f;
321                 material.PolygonOffsetDirection = video::EPO_BACK;
322                 //material.PolygonOffsetDepthBias = 1.0f/4.0f;
323                 //material.PolygonOffsetSlopeScale = -1.f;
324
325                 if (m_shadow_map_colored && pass != scene::ESNRP_SOLID)
326                         material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader_trans;
327                 else
328                         material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader;
329
330                 // FIXME: I don't think this is needed here
331                 map_node->OnAnimate(m_device->getTimer()->getTime());
332
333                 m_driver->setTransform(video::ETS_WORLD,
334                                 map_node->getAbsoluteTransformation());
335
336                 map_node->renderMapShadows(m_driver, material, pass);
337                 break;
338         }
339 }
340
341 void ShadowRenderer::renderShadowObjects(
342                 video::ITexture *target, DirectionalLight &light)
343 {
344         m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix());
345         m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix());
346
347         for (const auto &shadow_node : m_shadow_node_array) {
348                 // we only take care of the shadow casters
349                 if (shadow_node.shadowMode == ESM_RECEIVE ||
350                                 strcmp(shadow_node.node->getName(), "ClientMap") == 0)
351                         continue;
352
353                 // render other objects
354                 u32 n_node_materials = shadow_node.node->getMaterialCount();
355                 std::vector<s32> BufferMaterialList;
356                 std::vector<std::pair<bool, bool>> BufferMaterialCullingList;
357                 BufferMaterialList.reserve(n_node_materials);
358                 BufferMaterialCullingList.reserve(n_node_materials);
359
360                 // backup materialtype for each material
361                 // (aka shader)
362                 // and replace it by our "depth" shader
363                 for (u32 m = 0; m < n_node_materials; m++) {
364                         auto &current_mat = shadow_node.node->getMaterial(m);
365
366                         BufferMaterialList.push_back(current_mat.MaterialType);
367                         current_mat.MaterialType =
368                                         (video::E_MATERIAL_TYPE)depth_shader;
369
370                         current_mat.setTexture(3, shadowMapTextureFinal);
371
372                         BufferMaterialCullingList.emplace_back(
373                                 (bool)current_mat.BackfaceCulling, (bool)current_mat.FrontfaceCulling);
374
375                         current_mat.BackfaceCulling = true;
376                         current_mat.FrontfaceCulling = false;
377                         current_mat.PolygonOffsetFactor = 1.0f/2048.0f;
378                         current_mat.PolygonOffsetDirection = video::EPO_BACK;
379                         //current_mat.PolygonOffsetDepthBias = 1.0 * 2.8e-6;
380                         //current_mat.PolygonOffsetSlopeScale = -1.f;
381                 }
382
383                 m_driver->setTransform(video::ETS_WORLD,
384                                 shadow_node.node->getAbsoluteTransformation());
385                 shadow_node.node->render();
386
387                 // restore the material.
388
389                 for (u32 m = 0; m < n_node_materials; m++) {
390                         auto &current_mat = shadow_node.node->getMaterial(m);
391
392                         current_mat.MaterialType = (video::E_MATERIAL_TYPE) BufferMaterialList[m];
393
394                         current_mat.BackfaceCulling = BufferMaterialCullingList[m].first;
395                         current_mat.FrontfaceCulling = BufferMaterialCullingList[m].second;
396                 }
397
398         } // end for caster shadow nodes
399 }
400
401 void ShadowRenderer::mixShadowsQuad()
402 {
403 }
404
405 /*
406  * @Liso's disclaimer ;) This function loads the Shadow Mapping Shaders.
407  * I used a custom loader because I couldn't figure out how to use the base
408  * Shaders system with custom IShaderConstantSetCallBack without messing up the
409  * code too much. If anyone knows how to integrate this with the standard MT
410  * shaders, please feel free to change it.
411  */
412
413 void ShadowRenderer::createShaders()
414 {
415         video::IGPUProgrammingServices *gpu = m_driver->getGPUProgrammingServices();
416
417         if (depth_shader == -1) {
418                 std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl");
419                 if (depth_shader_vs.empty()) {
420                         m_shadows_enabled = false;
421                         errorstream << "Error shadow mapping vs shader not found." << std::endl;
422                         return;
423                 }
424                 std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl");
425                 if (depth_shader_fs.empty()) {
426                         m_shadows_enabled = false;
427                         errorstream << "Error shadow mapping fs shader not found." << std::endl;
428                         return;
429                 }
430                 m_shadow_depth_cb = new ShadowDepthShaderCB();
431
432                 depth_shader = gpu->addHighLevelShaderMaterial(
433                                 readShaderFile(depth_shader_vs).c_str(), "vertexMain",
434                                 video::EVST_VS_1_1,
435                                 readShaderFile(depth_shader_fs).c_str(), "pixelMain",
436                                 video::EPST_PS_1_2, m_shadow_depth_cb);
437
438                 if (depth_shader == -1) {
439                         // upsi, something went wrong loading shader.
440                         delete m_shadow_depth_cb;
441                         m_shadows_enabled = false;
442                         errorstream << "Error compiling shadow mapping shader." << std::endl;
443                         return;
444                 }
445
446                 // HACK, TODO: investigate this better
447                 // Grab the material renderer once more so minetest doesn't crash
448                 // on exit
449                 m_driver->getMaterialRenderer(depth_shader)->grab();
450         }
451
452         if (mixcsm_shader == -1) {
453                 std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass2_vertex.glsl");
454                 if (depth_shader_vs.empty()) {
455                         m_shadows_enabled = false;
456                         errorstream << "Error cascade shadow mapping fs shader not found." << std::endl;
457                         return;
458                 }
459
460                 std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass2_fragment.glsl");
461                 if (depth_shader_fs.empty()) {
462                         m_shadows_enabled = false;
463                         errorstream << "Error cascade shadow mapping fs shader not found." << std::endl;
464                         return;
465                 }
466                 m_shadow_mix_cb = new shadowScreenQuadCB();
467                 m_screen_quad = new shadowScreenQuad();
468                 mixcsm_shader = gpu->addHighLevelShaderMaterial(
469                                 readShaderFile(depth_shader_vs).c_str(), "vertexMain",
470                                 video::EVST_VS_1_1,
471                                 readShaderFile(depth_shader_fs).c_str(), "pixelMain",
472                                 video::EPST_PS_1_2, m_shadow_mix_cb);
473
474                 m_screen_quad->getMaterial().MaterialType =
475                                 (video::E_MATERIAL_TYPE)mixcsm_shader;
476
477                 if (mixcsm_shader == -1) {
478                         // upsi, something went wrong loading shader.
479                         delete m_shadow_mix_cb;
480                         delete m_screen_quad;
481                         m_shadows_enabled = false;
482                         errorstream << "Error compiling cascade shadow mapping shader." << std::endl;
483                         return;
484                 }
485
486                 // HACK, TODO: investigate this better
487                 // Grab the material renderer once more so minetest doesn't crash
488                 // on exit
489                 m_driver->getMaterialRenderer(mixcsm_shader)->grab();
490         }
491
492         if (m_shadow_map_colored && depth_shader_trans == -1) {
493                 std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_trans_vertex.glsl");
494                 if (depth_shader_vs.empty()) {
495                         m_shadows_enabled = false;
496                         errorstream << "Error shadow mapping vs shader not found." << std::endl;
497                         return;
498                 }
499                 std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_trans_fragment.glsl");
500                 if (depth_shader_fs.empty()) {
501                         m_shadows_enabled = false;
502                         errorstream << "Error shadow mapping fs shader not found." << std::endl;
503                         return;
504                 }
505                 m_shadow_depth_trans_cb = new ShadowDepthShaderCB();
506
507                 depth_shader_trans = gpu->addHighLevelShaderMaterial(
508                                 readShaderFile(depth_shader_vs).c_str(), "vertexMain",
509                                 video::EVST_VS_1_1,
510                                 readShaderFile(depth_shader_fs).c_str(), "pixelMain",
511                                 video::EPST_PS_1_2, m_shadow_depth_trans_cb);
512
513                 if (depth_shader_trans == -1) {
514                         // upsi, something went wrong loading shader.
515                         delete m_shadow_depth_trans_cb;
516                         m_shadow_map_colored = false;
517                         m_shadows_enabled = false;
518                         errorstream << "Error compiling colored shadow mapping shader." << std::endl;
519                         return;
520                 }
521
522                 // HACK, TODO: investigate this better
523                 // Grab the material renderer once more so minetest doesn't crash
524                 // on exit
525                 m_driver->getMaterialRenderer(depth_shader_trans)->grab();
526         }
527 }
528
529 std::string ShadowRenderer::readShaderFile(const std::string &path)
530 {
531         std::string prefix;
532         if (m_shadow_map_colored)
533                 prefix.append("#define COLORED_SHADOWS 1\n");
534
535         std::string content;
536         fs::ReadFile(path, content);
537
538         return prefix + content;
539 }