mirror of
https://github.com/luanti-org/luanti.git
synced 2025-08-16 18:01:40 +00:00
Shadow mapping render pass (#11244)
Co-authored-by: x2048 <codeforsmile@gmail.com>
This commit is contained in:
parent
46f42e15c4
commit
c47313db65
35 changed files with 2624 additions and 38 deletions
145
src/client/shadows/dynamicshadows.cpp
Normal file
145
src/client/shadows/dynamicshadows.cpp
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "client/shadows/dynamicshadows.h"
|
||||
#include "client/client.h"
|
||||
#include "client/clientenvironment.h"
|
||||
#include "client/clientmap.h"
|
||||
#include "client/camera.h"
|
||||
|
||||
using m4f = core::matrix4;
|
||||
|
||||
void DirectionalLight::createSplitMatrices(const Camera *cam)
|
||||
{
|
||||
float radius;
|
||||
v3f newCenter;
|
||||
v3f look = cam->getDirection();
|
||||
|
||||
v3f camPos2 = cam->getPosition();
|
||||
v3f camPos = v3f(camPos2.X - cam->getOffset().X * BS,
|
||||
camPos2.Y - cam->getOffset().Y * BS,
|
||||
camPos2.Z - cam->getOffset().Z * BS);
|
||||
camPos += look * shadow_frustum.zNear;
|
||||
camPos2 += look * shadow_frustum.zNear;
|
||||
float end = shadow_frustum.zNear + shadow_frustum.zFar;
|
||||
newCenter = camPos + look * (shadow_frustum.zNear + 0.05f * end);
|
||||
v3f world_center = camPos2 + look * (shadow_frustum.zNear + 0.05f * end);
|
||||
// Create a vector to the frustum far corner
|
||||
// @Liso: move all vars we can outside the loop.
|
||||
float tanFovY = tanf(cam->getFovY() * 0.5f);
|
||||
float tanFovX = tanf(cam->getFovX() * 0.5f);
|
||||
|
||||
const v3f &viewUp = cam->getCameraNode()->getUpVector();
|
||||
// viewUp.normalize();
|
||||
|
||||
v3f viewRight = look.crossProduct(viewUp);
|
||||
// viewRight.normalize();
|
||||
|
||||
v3f farCorner = look + viewRight * tanFovX + viewUp * tanFovY;
|
||||
// Compute the frustumBoundingSphere radius
|
||||
v3f boundVec = (camPos + farCorner * shadow_frustum.zFar) - newCenter;
|
||||
radius = boundVec.getLength() * 2.0f;
|
||||
// boundVec.getLength();
|
||||
float vvolume = radius * 2.0f;
|
||||
|
||||
float texelsPerUnit = getMapResolution() / vvolume;
|
||||
m4f mTexelScaling;
|
||||
mTexelScaling.setScale(texelsPerUnit);
|
||||
|
||||
m4f mLookAt, mLookAtInv;
|
||||
|
||||
mLookAt.buildCameraLookAtMatrixLH(v3f(0.0f, 0.0f, 0.0f), -direction, v3f(0.0f, 1.0f, 0.0f));
|
||||
|
||||
mLookAt *= mTexelScaling;
|
||||
mLookAtInv = mLookAt;
|
||||
mLookAtInv.makeInverse();
|
||||
|
||||
v3f frustumCenter = newCenter;
|
||||
mLookAt.transformVect(frustumCenter);
|
||||
frustumCenter.X = floorf(frustumCenter.X); // clamp to texel increment
|
||||
frustumCenter.Y = floorf(frustumCenter.Y); // clamp to texel increment
|
||||
frustumCenter.Z = floorf(frustumCenter.Z);
|
||||
mLookAtInv.transformVect(frustumCenter);
|
||||
// probar radius multipliacdor en funcion del I, a menor I mas multiplicador
|
||||
v3f eye_displacement = direction * vvolume;
|
||||
|
||||
// we must compute the viewmat with the position - the camera offset
|
||||
// but the shadow_frustum position must be the actual world position
|
||||
v3f eye = frustumCenter - eye_displacement;
|
||||
shadow_frustum.position = world_center - eye_displacement;
|
||||
shadow_frustum.length = vvolume;
|
||||
shadow_frustum.ViewMat.buildCameraLookAtMatrixLH(eye, frustumCenter, v3f(0.0f, 1.0f, 0.0f));
|
||||
shadow_frustum.ProjOrthMat.buildProjectionMatrixOrthoLH(shadow_frustum.length,
|
||||
shadow_frustum.length, -shadow_frustum.length,
|
||||
shadow_frustum.length,false);
|
||||
}
|
||||
|
||||
DirectionalLight::DirectionalLight(const u32 shadowMapResolution,
|
||||
const v3f &position, video::SColorf lightColor,
|
||||
f32 farValue) :
|
||||
diffuseColor(lightColor),
|
||||
farPlane(farValue), mapRes(shadowMapResolution), pos(position)
|
||||
{}
|
||||
|
||||
void DirectionalLight::update_frustum(const Camera *cam, Client *client)
|
||||
{
|
||||
should_update_map_shadow = true;
|
||||
float zNear = cam->getCameraNode()->getNearValue();
|
||||
float zFar = getMaxFarValue();
|
||||
|
||||
///////////////////////////////////
|
||||
// update splits near and fars
|
||||
shadow_frustum.zNear = zNear;
|
||||
shadow_frustum.zFar = zFar;
|
||||
|
||||
// update shadow frustum
|
||||
createSplitMatrices(cam);
|
||||
// get the draw list for shadows
|
||||
client->getEnv().getClientMap().updateDrawListShadow(
|
||||
getPosition(), getDirection(), shadow_frustum.length);
|
||||
should_update_map_shadow = true;
|
||||
}
|
||||
|
||||
void DirectionalLight::setDirection(v3f dir)
|
||||
{
|
||||
direction = -dir;
|
||||
direction.normalize();
|
||||
}
|
||||
|
||||
v3f DirectionalLight::getPosition() const
|
||||
{
|
||||
return shadow_frustum.position;
|
||||
}
|
||||
|
||||
const m4f &DirectionalLight::getViewMatrix() const
|
||||
{
|
||||
return shadow_frustum.ViewMat;
|
||||
}
|
||||
|
||||
const m4f &DirectionalLight::getProjectionMatrix() const
|
||||
{
|
||||
return shadow_frustum.ProjOrthMat;
|
||||
}
|
||||
|
||||
m4f DirectionalLight::getViewProjMatrix()
|
||||
{
|
||||
return shadow_frustum.ProjOrthMat * shadow_frustum.ViewMat;
|
||||
}
|
102
src/client/shadows/dynamicshadows.h
Normal file
102
src/client/shadows/dynamicshadows.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "irrlichttypes_bloated.h"
|
||||
#include <matrix4.h>
|
||||
#include "util/basic_macros.h"
|
||||
|
||||
class Camera;
|
||||
class Client;
|
||||
|
||||
struct shadowFrustum
|
||||
{
|
||||
float zNear{0.0f};
|
||||
float zFar{0.0f};
|
||||
float length{0.0f};
|
||||
core::matrix4 ProjOrthMat;
|
||||
core::matrix4 ViewMat;
|
||||
v3f position;
|
||||
};
|
||||
|
||||
class DirectionalLight
|
||||
{
|
||||
public:
|
||||
DirectionalLight(const u32 shadowMapResolution,
|
||||
const v3f &position,
|
||||
video::SColorf lightColor = video::SColor(0xffffffff),
|
||||
f32 farValue = 100.0f);
|
||||
~DirectionalLight() = default;
|
||||
|
||||
//DISABLE_CLASS_COPY(DirectionalLight)
|
||||
|
||||
void update_frustum(const Camera *cam, Client *client);
|
||||
|
||||
// when set direction is updated to negative normalized(direction)
|
||||
void setDirection(v3f dir);
|
||||
v3f getDirection() const{
|
||||
return direction;
|
||||
};
|
||||
v3f getPosition() const;
|
||||
|
||||
/// Gets the light's matrices.
|
||||
const core::matrix4 &getViewMatrix() const;
|
||||
const core::matrix4 &getProjectionMatrix() const;
|
||||
core::matrix4 getViewProjMatrix();
|
||||
|
||||
/// Gets the light's far value.
|
||||
f32 getMaxFarValue() const
|
||||
{
|
||||
return farPlane;
|
||||
}
|
||||
|
||||
|
||||
/// Gets the light's color.
|
||||
const video::SColorf &getLightColor() const
|
||||
{
|
||||
return diffuseColor;
|
||||
}
|
||||
|
||||
/// Sets the light's color.
|
||||
void setLightColor(const video::SColorf &lightColor)
|
||||
{
|
||||
diffuseColor = lightColor;
|
||||
}
|
||||
|
||||
/// Gets the shadow map resolution for this light.
|
||||
u32 getMapResolution() const
|
||||
{
|
||||
return mapRes;
|
||||
}
|
||||
|
||||
bool should_update_map_shadow{true};
|
||||
|
||||
private:
|
||||
void createSplitMatrices(const Camera *cam);
|
||||
|
||||
video::SColorf diffuseColor;
|
||||
|
||||
f32 farPlane;
|
||||
u32 mapRes;
|
||||
|
||||
v3f pos;
|
||||
v3f direction{0};
|
||||
shadowFrustum shadow_frustum;
|
||||
};
|
539
src/client/shadows/dynamicshadowsrender.cpp
Normal file
539
src/client/shadows/dynamicshadowsrender.cpp
Normal file
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "client/shadows/dynamicshadowsrender.h"
|
||||
#include "client/shadows/shadowsScreenQuad.h"
|
||||
#include "client/shadows/shadowsshadercallbacks.h"
|
||||
#include "settings.h"
|
||||
#include "filesys.h"
|
||||
#include "util/string.h"
|
||||
#include "client/shader.h"
|
||||
#include "client/client.h"
|
||||
#include "client/clientmap.h"
|
||||
|
||||
ShadowRenderer::ShadowRenderer(IrrlichtDevice *device, Client *client) :
|
||||
m_device(device), m_smgr(device->getSceneManager()),
|
||||
m_driver(device->getVideoDriver()), m_client(client)
|
||||
{
|
||||
m_shadows_enabled = true;
|
||||
|
||||
m_shadow_strength = g_settings->getFloat("shadow_strength");
|
||||
|
||||
m_shadow_map_max_distance = g_settings->getFloat("shadow_map_max_distance");
|
||||
|
||||
m_shadow_map_texture_size = g_settings->getFloat("shadow_map_texture_size");
|
||||
|
||||
m_shadow_map_texture_32bit = g_settings->getBool("shadow_map_texture_32bit");
|
||||
m_shadow_map_colored = g_settings->getBool("shadow_map_color");
|
||||
m_shadow_samples = g_settings->getS32("shadow_filters");
|
||||
m_update_delta = g_settings->getFloat("shadow_update_time");
|
||||
}
|
||||
|
||||
ShadowRenderer::~ShadowRenderer()
|
||||
{
|
||||
if (m_shadow_depth_cb)
|
||||
delete m_shadow_depth_cb;
|
||||
if (m_shadow_mix_cb)
|
||||
delete m_shadow_mix_cb;
|
||||
m_shadow_node_array.clear();
|
||||
m_light_list.clear();
|
||||
|
||||
if (shadowMapTextureDynamicObjects)
|
||||
m_driver->removeTexture(shadowMapTextureDynamicObjects);
|
||||
|
||||
if (shadowMapTextureFinal)
|
||||
m_driver->removeTexture(shadowMapTextureFinal);
|
||||
|
||||
if (shadowMapTextureColors)
|
||||
m_driver->removeTexture(shadowMapTextureColors);
|
||||
|
||||
if (shadowMapClientMap)
|
||||
m_driver->removeTexture(shadowMapClientMap);
|
||||
}
|
||||
|
||||
void ShadowRenderer::initialize()
|
||||
{
|
||||
auto *gpu = m_driver->getGPUProgrammingServices();
|
||||
|
||||
// we need glsl
|
||||
if (m_shadows_enabled && gpu && m_driver->queryFeature(video::EVDF_ARB_GLSL)) {
|
||||
createShaders();
|
||||
} else {
|
||||
m_shadows_enabled = false;
|
||||
|
||||
warningstream << "Shadows: GLSL Shader not supported on this system."
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_texture_format = m_shadow_map_texture_32bit
|
||||
? video::ECOLOR_FORMAT::ECF_R32F
|
||||
: video::ECOLOR_FORMAT::ECF_R16F;
|
||||
|
||||
m_texture_format_color = m_shadow_map_texture_32bit
|
||||
? video::ECOLOR_FORMAT::ECF_G32R32F
|
||||
: video::ECOLOR_FORMAT::ECF_G16R16F;
|
||||
}
|
||||
|
||||
|
||||
float ShadowRenderer::getUpdateDelta() const
|
||||
{
|
||||
return m_update_delta;
|
||||
}
|
||||
|
||||
size_t ShadowRenderer::addDirectionalLight()
|
||||
{
|
||||
m_light_list.emplace_back(m_shadow_map_texture_size,
|
||||
v3f(0.f, 0.f, 0.f),
|
||||
video::SColor(255, 255, 255, 255), m_shadow_map_max_distance);
|
||||
return m_light_list.size() - 1;
|
||||
}
|
||||
|
||||
DirectionalLight &ShadowRenderer::getDirectionalLight(u32 index)
|
||||
{
|
||||
return m_light_list[index];
|
||||
}
|
||||
|
||||
size_t ShadowRenderer::getDirectionalLightCount() const
|
||||
{
|
||||
return m_light_list.size();
|
||||
}
|
||||
|
||||
f32 ShadowRenderer::getMaxShadowFar() const
|
||||
{
|
||||
if (!m_light_list.empty()) {
|
||||
float wanted_range = m_client->getEnv().getClientMap().getWantedRange();
|
||||
|
||||
float zMax = m_light_list[0].getMaxFarValue() > wanted_range
|
||||
? wanted_range
|
||||
: m_light_list[0].getMaxFarValue();
|
||||
return zMax * MAP_BLOCKSIZE;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
void ShadowRenderer::addNodeToShadowList(
|
||||
scene::ISceneNode *node, E_SHADOW_MODE shadowMode)
|
||||
{
|
||||
m_shadow_node_array.emplace_back(NodeToApply(node, shadowMode));
|
||||
}
|
||||
|
||||
void ShadowRenderer::removeNodeFromShadowList(scene::ISceneNode *node)
|
||||
{
|
||||
for (auto it = m_shadow_node_array.begin(); it != m_shadow_node_array.end();) {
|
||||
if (it->node == node) {
|
||||
it = m_shadow_node_array.erase(it);
|
||||
break;
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowRenderer::setClearColor(video::SColor ClearColor)
|
||||
{
|
||||
m_clear_color = ClearColor;
|
||||
}
|
||||
|
||||
void ShadowRenderer::update(video::ITexture *outputTarget)
|
||||
{
|
||||
if (!m_shadows_enabled || m_smgr->getActiveCamera() == nullptr) {
|
||||
m_smgr->drawAll();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!shadowMapTextureDynamicObjects) {
|
||||
|
||||
shadowMapTextureDynamicObjects = getSMTexture(
|
||||
std::string("shadow_dynamic_") + itos(m_shadow_map_texture_size),
|
||||
m_texture_format, true);
|
||||
}
|
||||
|
||||
if (!shadowMapClientMap) {
|
||||
|
||||
shadowMapClientMap = getSMTexture(
|
||||
std::string("shadow_clientmap_") + itos(m_shadow_map_texture_size),
|
||||
m_shadow_map_colored ? m_texture_format_color : m_texture_format,
|
||||
true);
|
||||
}
|
||||
|
||||
if (m_shadow_map_colored && !shadowMapTextureColors) {
|
||||
shadowMapTextureColors = getSMTexture(
|
||||
std::string("shadow_colored_") + itos(m_shadow_map_texture_size),
|
||||
m_shadow_map_colored ? m_texture_format_color : m_texture_format,
|
||||
true);
|
||||
}
|
||||
|
||||
// The merge all shadowmaps texture
|
||||
if (!shadowMapTextureFinal) {
|
||||
video::ECOLOR_FORMAT frt;
|
||||
if (m_shadow_map_texture_32bit) {
|
||||
if (m_shadow_map_colored)
|
||||
frt = video::ECOLOR_FORMAT::ECF_A32B32G32R32F;
|
||||
else
|
||||
frt = video::ECOLOR_FORMAT::ECF_R32F;
|
||||
} else {
|
||||
if (m_shadow_map_colored)
|
||||
frt = video::ECOLOR_FORMAT::ECF_A16B16G16R16F;
|
||||
else
|
||||
frt = video::ECOLOR_FORMAT::ECF_R16F;
|
||||
}
|
||||
shadowMapTextureFinal = getSMTexture(
|
||||
std::string("shadowmap_final_") + itos(m_shadow_map_texture_size),
|
||||
frt, true);
|
||||
}
|
||||
|
||||
if (!m_shadow_node_array.empty() && !m_light_list.empty()) {
|
||||
// for every directional light:
|
||||
for (DirectionalLight &light : m_light_list) {
|
||||
// Static shader values.
|
||||
m_shadow_depth_cb->MapRes = (f32)m_shadow_map_texture_size;
|
||||
m_shadow_depth_cb->MaxFar = (f32)m_shadow_map_max_distance * BS;
|
||||
|
||||
// set the Render Target
|
||||
// right now we can only render in usual RTT, not
|
||||
// Depth texture is available in irrlicth maybe we
|
||||
// should put some gl* fn here
|
||||
|
||||
if (light.should_update_map_shadow) {
|
||||
light.should_update_map_shadow = false;
|
||||
|
||||
m_driver->setRenderTarget(shadowMapClientMap, true, true,
|
||||
video::SColor(255, 255, 255, 255));
|
||||
renderShadowMap(shadowMapClientMap, light);
|
||||
|
||||
if (m_shadow_map_colored) {
|
||||
m_driver->setRenderTarget(shadowMapTextureColors,
|
||||
true, false, video::SColor(255, 255, 255, 255));
|
||||
}
|
||||
renderShadowMap(shadowMapTextureColors, light,
|
||||
scene::ESNRP_TRANSPARENT);
|
||||
m_driver->setRenderTarget(0, false, false);
|
||||
}
|
||||
|
||||
// render shadows for the n0n-map objects.
|
||||
m_driver->setRenderTarget(shadowMapTextureDynamicObjects, true,
|
||||
true, video::SColor(255, 255, 255, 255));
|
||||
renderShadowObjects(shadowMapTextureDynamicObjects, light);
|
||||
// clear the Render Target
|
||||
m_driver->setRenderTarget(0, false, false);
|
||||
|
||||
// in order to avoid too many map shadow renders,
|
||||
// we should make a second pass to mix clientmap shadows and
|
||||
// entities shadows :(
|
||||
m_screen_quad->getMaterial().setTexture(0, shadowMapClientMap);
|
||||
// dynamic objs shadow texture.
|
||||
if (m_shadow_map_colored)
|
||||
m_screen_quad->getMaterial().setTexture(1, shadowMapTextureColors);
|
||||
m_screen_quad->getMaterial().setTexture(2, shadowMapTextureDynamicObjects);
|
||||
|
||||
m_driver->setRenderTarget(shadowMapTextureFinal, false, false,
|
||||
video::SColor(255, 255, 255, 255));
|
||||
m_screen_quad->render(m_driver);
|
||||
m_driver->setRenderTarget(0, false, false);
|
||||
|
||||
} // end for lights
|
||||
|
||||
// now render the actual MT render pass
|
||||
m_driver->setRenderTarget(outputTarget, true, true, m_clear_color);
|
||||
m_smgr->drawAll();
|
||||
|
||||
/* this code just shows shadows textures in screen and in ONLY for debugging*/
|
||||
#if 0
|
||||
// this is debug, ignore for now.
|
||||
m_driver->draw2DImage(shadowMapTextureFinal,
|
||||
core::rect<s32>(0, 50, 128, 128 + 50),
|
||||
core::rect<s32>({0, 0}, shadowMapTextureFinal->getSize()));
|
||||
|
||||
m_driver->draw2DImage(shadowMapClientMap,
|
||||
core::rect<s32>(0, 50 + 128, 128, 128 + 50 + 128),
|
||||
core::rect<s32>({0, 0}, shadowMapTextureFinal->getSize()));
|
||||
m_driver->draw2DImage(shadowMapTextureDynamicObjects,
|
||||
core::rect<s32>(0, 128 + 50 + 128, 128,
|
||||
128 + 50 + 128 + 128),
|
||||
core::rect<s32>({0, 0}, shadowMapTextureDynamicObjects->getSize()));
|
||||
|
||||
if (m_shadow_map_colored) {
|
||||
|
||||
m_driver->draw2DImage(shadowMapTextureColors,
|
||||
core::rect<s32>(128,128 + 50 + 128 + 128,
|
||||
128 + 128, 128 + 50 + 128 + 128 + 128),
|
||||
core::rect<s32>({0, 0}, shadowMapTextureColors->getSize()));
|
||||
}
|
||||
#endif
|
||||
m_driver->setRenderTarget(0, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
video::ITexture *ShadowRenderer::getSMTexture(const std::string &shadow_map_name,
|
||||
video::ECOLOR_FORMAT texture_format, bool force_creation)
|
||||
{
|
||||
if (force_creation) {
|
||||
return m_driver->addRenderTargetTexture(
|
||||
core::dimension2du(m_shadow_map_texture_size,
|
||||
m_shadow_map_texture_size),
|
||||
shadow_map_name.c_str(), texture_format);
|
||||
}
|
||||
|
||||
return m_driver->getTexture(shadow_map_name.c_str());
|
||||
}
|
||||
|
||||
void ShadowRenderer::renderShadowMap(video::ITexture *target,
|
||||
DirectionalLight &light, scene::E_SCENE_NODE_RENDER_PASS pass)
|
||||
{
|
||||
m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix());
|
||||
m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix());
|
||||
|
||||
// Operate on the client map
|
||||
for (const auto &shadow_node : m_shadow_node_array) {
|
||||
if (strcmp(shadow_node.node->getName(), "ClientMap") != 0)
|
||||
continue;
|
||||
|
||||
ClientMap *map_node = static_cast<ClientMap *>(shadow_node.node);
|
||||
|
||||
video::SMaterial material;
|
||||
if (map_node->getMaterialCount() > 0) {
|
||||
// we only want the first material, which is the one with the albedo info
|
||||
material = map_node->getMaterial(0);
|
||||
}
|
||||
|
||||
material.BackfaceCulling = false;
|
||||
material.FrontfaceCulling = true;
|
||||
material.PolygonOffsetFactor = 4.0f;
|
||||
material.PolygonOffsetDirection = video::EPO_BACK;
|
||||
//material.PolygonOffsetDepthBias = 1.0f/4.0f;
|
||||
//material.PolygonOffsetSlopeScale = -1.f;
|
||||
|
||||
if (m_shadow_map_colored && pass != scene::ESNRP_SOLID)
|
||||
material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader_trans;
|
||||
else
|
||||
material.MaterialType = (video::E_MATERIAL_TYPE) depth_shader;
|
||||
|
||||
// FIXME: I don't think this is needed here
|
||||
map_node->OnAnimate(m_device->getTimer()->getTime());
|
||||
|
||||
m_driver->setTransform(video::ETS_WORLD,
|
||||
map_node->getAbsoluteTransformation());
|
||||
|
||||
map_node->renderMapShadows(m_driver, material, pass);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ShadowRenderer::renderShadowObjects(
|
||||
video::ITexture *target, DirectionalLight &light)
|
||||
{
|
||||
m_driver->setTransform(video::ETS_VIEW, light.getViewMatrix());
|
||||
m_driver->setTransform(video::ETS_PROJECTION, light.getProjectionMatrix());
|
||||
|
||||
for (const auto &shadow_node : m_shadow_node_array) {
|
||||
// we only take care of the shadow casters
|
||||
if (shadow_node.shadowMode == ESM_RECEIVE ||
|
||||
strcmp(shadow_node.node->getName(), "ClientMap") == 0)
|
||||
continue;
|
||||
|
||||
// render other objects
|
||||
u32 n_node_materials = shadow_node.node->getMaterialCount();
|
||||
std::vector<s32> BufferMaterialList;
|
||||
std::vector<std::pair<bool, bool>> BufferMaterialCullingList;
|
||||
BufferMaterialList.reserve(n_node_materials);
|
||||
BufferMaterialCullingList.reserve(n_node_materials);
|
||||
|
||||
// backup materialtype for each material
|
||||
// (aka shader)
|
||||
// and replace it by our "depth" shader
|
||||
for (u32 m = 0; m < n_node_materials; m++) {
|
||||
auto ¤t_mat = shadow_node.node->getMaterial(m);
|
||||
|
||||
BufferMaterialList.push_back(current_mat.MaterialType);
|
||||
current_mat.MaterialType =
|
||||
(video::E_MATERIAL_TYPE)depth_shader;
|
||||
|
||||
current_mat.setTexture(3, shadowMapTextureFinal);
|
||||
|
||||
BufferMaterialCullingList.emplace_back(
|
||||
(bool)current_mat.BackfaceCulling, (bool)current_mat.FrontfaceCulling);
|
||||
|
||||
current_mat.BackfaceCulling = true;
|
||||
current_mat.FrontfaceCulling = false;
|
||||
current_mat.PolygonOffsetFactor = 1.0f/2048.0f;
|
||||
current_mat.PolygonOffsetDirection = video::EPO_BACK;
|
||||
//current_mat.PolygonOffsetDepthBias = 1.0 * 2.8e-6;
|
||||
//current_mat.PolygonOffsetSlopeScale = -1.f;
|
||||
}
|
||||
|
||||
m_driver->setTransform(video::ETS_WORLD,
|
||||
shadow_node.node->getAbsoluteTransformation());
|
||||
shadow_node.node->render();
|
||||
|
||||
// restore the material.
|
||||
|
||||
for (u32 m = 0; m < n_node_materials; m++) {
|
||||
auto ¤t_mat = shadow_node.node->getMaterial(m);
|
||||
|
||||
current_mat.MaterialType = (video::E_MATERIAL_TYPE) BufferMaterialList[m];
|
||||
|
||||
current_mat.BackfaceCulling = BufferMaterialCullingList[m].first;
|
||||
current_mat.FrontfaceCulling = BufferMaterialCullingList[m].second;
|
||||
}
|
||||
|
||||
} // end for caster shadow nodes
|
||||
}
|
||||
|
||||
void ShadowRenderer::mixShadowsQuad()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* @Liso's disclaimer ;) This function loads the Shadow Mapping Shaders.
|
||||
* I used a custom loader because I couldn't figure out how to use the base
|
||||
* Shaders system with custom IShaderConstantSetCallBack without messing up the
|
||||
* code too much. If anyone knows how to integrate this with the standard MT
|
||||
* shaders, please feel free to change it.
|
||||
*/
|
||||
|
||||
void ShadowRenderer::createShaders()
|
||||
{
|
||||
video::IGPUProgrammingServices *gpu = m_driver->getGPUProgrammingServices();
|
||||
|
||||
if (depth_shader == -1) {
|
||||
std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_vertex.glsl");
|
||||
if (depth_shader_vs.empty()) {
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error shadow mapping vs shader not found." << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_fragment.glsl");
|
||||
if (depth_shader_fs.empty()) {
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error shadow mapping fs shader not found." << std::endl;
|
||||
return;
|
||||
}
|
||||
m_shadow_depth_cb = new ShadowDepthShaderCB();
|
||||
|
||||
depth_shader = gpu->addHighLevelShaderMaterial(
|
||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
||||
video::EVST_VS_1_1,
|
||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
||||
video::EPST_PS_1_2, m_shadow_depth_cb);
|
||||
|
||||
if (depth_shader == -1) {
|
||||
// upsi, something went wrong loading shader.
|
||||
delete m_shadow_depth_cb;
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error compiling shadow mapping shader." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// HACK, TODO: investigate this better
|
||||
// Grab the material renderer once more so minetest doesn't crash
|
||||
// on exit
|
||||
m_driver->getMaterialRenderer(depth_shader)->grab();
|
||||
}
|
||||
|
||||
if (mixcsm_shader == -1) {
|
||||
std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass2_vertex.glsl");
|
||||
if (depth_shader_vs.empty()) {
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error cascade shadow mapping fs shader not found." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass2_fragment.glsl");
|
||||
if (depth_shader_fs.empty()) {
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error cascade shadow mapping fs shader not found." << std::endl;
|
||||
return;
|
||||
}
|
||||
m_shadow_mix_cb = new shadowScreenQuadCB();
|
||||
m_screen_quad = new shadowScreenQuad();
|
||||
mixcsm_shader = gpu->addHighLevelShaderMaterial(
|
||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
||||
video::EVST_VS_1_1,
|
||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
||||
video::EPST_PS_1_2, m_shadow_mix_cb);
|
||||
|
||||
m_screen_quad->getMaterial().MaterialType =
|
||||
(video::E_MATERIAL_TYPE)mixcsm_shader;
|
||||
|
||||
if (mixcsm_shader == -1) {
|
||||
// upsi, something went wrong loading shader.
|
||||
delete m_shadow_mix_cb;
|
||||
delete m_screen_quad;
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error compiling cascade shadow mapping shader." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// HACK, TODO: investigate this better
|
||||
// Grab the material renderer once more so minetest doesn't crash
|
||||
// on exit
|
||||
m_driver->getMaterialRenderer(mixcsm_shader)->grab();
|
||||
}
|
||||
|
||||
if (m_shadow_map_colored && depth_shader_trans == -1) {
|
||||
std::string depth_shader_vs = getShaderPath("shadow_shaders", "pass1_trans_vertex.glsl");
|
||||
if (depth_shader_vs.empty()) {
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error shadow mapping vs shader not found." << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string depth_shader_fs = getShaderPath("shadow_shaders", "pass1_trans_fragment.glsl");
|
||||
if (depth_shader_fs.empty()) {
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error shadow mapping fs shader not found." << std::endl;
|
||||
return;
|
||||
}
|
||||
m_shadow_depth_trans_cb = new ShadowDepthShaderCB();
|
||||
|
||||
depth_shader_trans = gpu->addHighLevelShaderMaterial(
|
||||
readShaderFile(depth_shader_vs).c_str(), "vertexMain",
|
||||
video::EVST_VS_1_1,
|
||||
readShaderFile(depth_shader_fs).c_str(), "pixelMain",
|
||||
video::EPST_PS_1_2, m_shadow_depth_trans_cb);
|
||||
|
||||
if (depth_shader_trans == -1) {
|
||||
// upsi, something went wrong loading shader.
|
||||
delete m_shadow_depth_trans_cb;
|
||||
m_shadow_map_colored = false;
|
||||
m_shadows_enabled = false;
|
||||
errorstream << "Error compiling colored shadow mapping shader." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// HACK, TODO: investigate this better
|
||||
// Grab the material renderer once more so minetest doesn't crash
|
||||
// on exit
|
||||
m_driver->getMaterialRenderer(depth_shader_trans)->grab();
|
||||
}
|
||||
}
|
||||
|
||||
std::string ShadowRenderer::readShaderFile(const std::string &path)
|
||||
{
|
||||
std::string prefix;
|
||||
if (m_shadow_map_colored)
|
||||
prefix.append("#define COLORED_SHADOWS 1\n");
|
||||
|
||||
std::string content;
|
||||
fs::ReadFile(path, content);
|
||||
|
||||
return prefix + content;
|
||||
}
|
146
src/client/shadows/dynamicshadowsrender.h
Normal file
146
src/client/shadows/dynamicshadowsrender.h
Normal file
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include "client/shadows/dynamicshadows.h"
|
||||
|
||||
class ShadowDepthShaderCB;
|
||||
class shadowScreenQuad;
|
||||
class shadowScreenQuadCB;
|
||||
|
||||
enum E_SHADOW_MODE : u8
|
||||
{
|
||||
ESM_RECEIVE = 0,
|
||||
ESM_BOTH,
|
||||
};
|
||||
|
||||
struct NodeToApply
|
||||
{
|
||||
NodeToApply(scene::ISceneNode *n,
|
||||
E_SHADOW_MODE m = E_SHADOW_MODE::ESM_BOTH) :
|
||||
node(n),
|
||||
shadowMode(m){};
|
||||
bool operator<(const NodeToApply &other) const { return node < other.node; };
|
||||
|
||||
scene::ISceneNode *node;
|
||||
|
||||
E_SHADOW_MODE shadowMode{E_SHADOW_MODE::ESM_BOTH};
|
||||
bool dirty{false};
|
||||
};
|
||||
|
||||
class ShadowRenderer
|
||||
{
|
||||
public:
|
||||
ShadowRenderer(IrrlichtDevice *device, Client *client);
|
||||
|
||||
~ShadowRenderer();
|
||||
|
||||
void initialize();
|
||||
|
||||
/// Adds a directional light shadow map (Usually just one (the sun) except in
|
||||
/// Tattoine ).
|
||||
size_t addDirectionalLight();
|
||||
DirectionalLight &getDirectionalLight(u32 index = 0);
|
||||
size_t getDirectionalLightCount() const;
|
||||
f32 getMaxShadowFar() const;
|
||||
|
||||
float getUpdateDelta() const;
|
||||
/// Adds a shadow to the scene node.
|
||||
/// The shadow mode can be ESM_BOTH, or ESM_RECEIVE.
|
||||
/// ESM_BOTH casts and receives shadows
|
||||
/// ESM_RECEIVE only receives but does not cast shadows.
|
||||
///
|
||||
void addNodeToShadowList(scene::ISceneNode *node,
|
||||
E_SHADOW_MODE shadowMode = ESM_BOTH);
|
||||
void removeNodeFromShadowList(scene::ISceneNode *node);
|
||||
|
||||
void setClearColor(video::SColor ClearColor);
|
||||
|
||||
void update(video::ITexture *outputTarget = nullptr);
|
||||
|
||||
video::ITexture *get_texture()
|
||||
{
|
||||
return shadowMapTextureFinal;
|
||||
}
|
||||
|
||||
|
||||
bool is_active() const { return m_shadows_enabled; }
|
||||
void setTimeOfDay(float isDay) { m_time_day = isDay; };
|
||||
|
||||
s32 getShadowSamples() const { return m_shadow_samples; }
|
||||
float getShadowStrength() const { return m_shadow_strength; }
|
||||
float getTimeOfDay() const { return m_time_day; }
|
||||
|
||||
private:
|
||||
video::ITexture *getSMTexture(const std::string &shadow_map_name,
|
||||
video::ECOLOR_FORMAT texture_format,
|
||||
bool force_creation = false);
|
||||
|
||||
void renderShadowMap(video::ITexture *target, DirectionalLight &light,
|
||||
scene::E_SCENE_NODE_RENDER_PASS pass =
|
||||
scene::ESNRP_SOLID);
|
||||
void renderShadowObjects(video::ITexture *target, DirectionalLight &light);
|
||||
void mixShadowsQuad();
|
||||
|
||||
// a bunch of variables
|
||||
IrrlichtDevice *m_device{nullptr};
|
||||
scene::ISceneManager *m_smgr{nullptr};
|
||||
video::IVideoDriver *m_driver{nullptr};
|
||||
Client *m_client{nullptr};
|
||||
video::ITexture *shadowMapClientMap{nullptr};
|
||||
video::ITexture *shadowMapTextureFinal{nullptr};
|
||||
video::ITexture *shadowMapTextureDynamicObjects{nullptr};
|
||||
video::ITexture *shadowMapTextureColors{nullptr};
|
||||
video::SColor m_clear_color{0x0};
|
||||
|
||||
std::vector<DirectionalLight> m_light_list;
|
||||
std::vector<NodeToApply> m_shadow_node_array;
|
||||
|
||||
float m_shadow_strength;
|
||||
float m_shadow_map_max_distance;
|
||||
float m_shadow_map_texture_size;
|
||||
float m_time_day{0.0f};
|
||||
float m_update_delta;
|
||||
int m_shadow_samples;
|
||||
bool m_shadow_map_texture_32bit;
|
||||
bool m_shadows_enabled;
|
||||
bool m_shadow_map_colored;
|
||||
|
||||
video::ECOLOR_FORMAT m_texture_format{video::ECOLOR_FORMAT::ECF_R16F};
|
||||
video::ECOLOR_FORMAT m_texture_format_color{video::ECOLOR_FORMAT::ECF_R16G16};
|
||||
|
||||
// Shadow Shader stuff
|
||||
|
||||
void createShaders();
|
||||
std::string readShaderFile(const std::string &path);
|
||||
|
||||
s32 depth_shader{-1};
|
||||
s32 depth_shader_trans{-1};
|
||||
s32 mixcsm_shader{-1};
|
||||
|
||||
ShadowDepthShaderCB *m_shadow_depth_cb{nullptr};
|
||||
ShadowDepthShaderCB *m_shadow_depth_trans_cb{nullptr};
|
||||
|
||||
shadowScreenQuad *m_screen_quad{nullptr};
|
||||
shadowScreenQuadCB *m_shadow_mix_cb{nullptr};
|
||||
};
|
67
src/client/shadows/shadowsScreenQuad.cpp
Normal file
67
src/client/shadows/shadowsScreenQuad.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "shadowsScreenQuad.h"
|
||||
|
||||
shadowScreenQuad::shadowScreenQuad()
|
||||
{
|
||||
Material.Wireframe = false;
|
||||
Material.Lighting = false;
|
||||
|
||||
video::SColor color(0x0);
|
||||
Vertices[0] = video::S3DVertex(
|
||||
-1.0f, -1.0f, 0.0f, 0, 0, 1, color, 0.0f, 1.0f);
|
||||
Vertices[1] = video::S3DVertex(
|
||||
-1.0f, 1.0f, 0.0f, 0, 0, 1, color, 0.0f, 0.0f);
|
||||
Vertices[2] = video::S3DVertex(
|
||||
1.0f, 1.0f, 0.0f, 0, 0, 1, color, 1.0f, 0.0f);
|
||||
Vertices[3] = video::S3DVertex(
|
||||
1.0f, -1.0f, 0.0f, 0, 0, 1, color, 1.0f, 1.0f);
|
||||
Vertices[4] = video::S3DVertex(
|
||||
-1.0f, -1.0f, 0.0f, 0, 0, 1, color, 0.0f, 1.0f);
|
||||
Vertices[5] = video::S3DVertex(
|
||||
1.0f, 1.0f, 0.0f, 0, 0, 1, color, 1.0f, 0.0f);
|
||||
}
|
||||
|
||||
void shadowScreenQuad::render(video::IVideoDriver *driver)
|
||||
{
|
||||
u16 indices[6] = {0, 1, 2, 3, 4, 5};
|
||||
driver->setMaterial(Material);
|
||||
driver->setTransform(video::ETS_WORLD, core::matrix4());
|
||||
driver->drawIndexedTriangleList(&Vertices[0], 6, &indices[0], 2);
|
||||
}
|
||||
|
||||
void shadowScreenQuadCB::OnSetConstants(
|
||||
video::IMaterialRendererServices *services, s32 userData)
|
||||
{
|
||||
s32 TextureId = 0;
|
||||
services->setPixelShaderConstant(
|
||||
services->getPixelShaderConstantID("ShadowMapClientMap"),
|
||||
&TextureId, 1);
|
||||
|
||||
TextureId = 1;
|
||||
services->setPixelShaderConstant(
|
||||
services->getPixelShaderConstantID("ShadowMapClientMapTraslucent"),
|
||||
&TextureId, 1);
|
||||
|
||||
TextureId = 2;
|
||||
services->setPixelShaderConstant(
|
||||
services->getPixelShaderConstantID("ShadowMapSamplerdynamic"),
|
||||
&TextureId, 1);
|
||||
}
|
45
src/client/shadows/shadowsScreenQuad.h
Normal file
45
src/client/shadows/shadowsScreenQuad.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include <IMaterialRendererServices.h>
|
||||
#include <IShaderConstantSetCallBack.h>
|
||||
|
||||
class shadowScreenQuad
|
||||
{
|
||||
public:
|
||||
shadowScreenQuad();
|
||||
|
||||
void render(video::IVideoDriver *driver);
|
||||
video::SMaterial &getMaterial() { return Material; }
|
||||
|
||||
private:
|
||||
video::S3DVertex Vertices[6];
|
||||
video::SMaterial Material;
|
||||
};
|
||||
|
||||
class shadowScreenQuadCB : public video::IShaderConstantSetCallBack
|
||||
{
|
||||
public:
|
||||
shadowScreenQuadCB(){};
|
||||
|
||||
virtual void OnSetConstants(video::IMaterialRendererServices *services,
|
||||
s32 userData);
|
||||
};
|
44
src/client/shadows/shadowsshadercallbacks.cpp
Normal file
44
src/client/shadows/shadowsshadercallbacks.cpp
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "client/shadows/shadowsshadercallbacks.h"
|
||||
|
||||
void ShadowDepthShaderCB::OnSetConstants(
|
||||
video::IMaterialRendererServices *services, s32 userData)
|
||||
{
|
||||
video::IVideoDriver *driver = services->getVideoDriver();
|
||||
|
||||
core::matrix4 lightMVP = driver->getTransform(video::ETS_PROJECTION);
|
||||
lightMVP *= driver->getTransform(video::ETS_VIEW);
|
||||
lightMVP *= driver->getTransform(video::ETS_WORLD);
|
||||
|
||||
services->setVertexShaderConstant(
|
||||
services->getPixelShaderConstantID("LightMVP"),
|
||||
lightMVP.pointer(), 16);
|
||||
|
||||
services->setVertexShaderConstant(
|
||||
services->getPixelShaderConstantID("MapResolution"), &MapRes, 1);
|
||||
services->setVertexShaderConstant(
|
||||
services->getPixelShaderConstantID("MaxFar"), &MaxFar, 1);
|
||||
|
||||
s32 TextureId = 0;
|
||||
services->setPixelShaderConstant(
|
||||
services->getPixelShaderConstantID("ColorMapSampler"), &TextureId,
|
||||
1);
|
||||
}
|
34
src/client/shadows/shadowsshadercallbacks.h
Normal file
34
src/client/shadows/shadowsshadercallbacks.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
Minetest
|
||||
Copyright (C) 2021 Liso <anlismon@gmail.com>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "irrlichttypes_extrabloated.h"
|
||||
#include <IMaterialRendererServices.h>
|
||||
#include <IShaderConstantSetCallBack.h>
|
||||
|
||||
class ShadowDepthShaderCB : public video::IShaderConstantSetCallBack
|
||||
{
|
||||
public:
|
||||
void OnSetMaterial(const video::SMaterial &material) override {}
|
||||
|
||||
void OnSetConstants(video::IMaterialRendererServices *services,
|
||||
s32 userData) override;
|
||||
|
||||
f32 MaxFar{2048.0f}, MapRes{1024.0f};
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue