commit x64 compilation from lulu cause the other branch dont seems to compile properly at home
This commit is contained in:
376
include/engine/gpu/gpu_shadow_map.cpp
Normal file
376
include/engine/gpu/gpu_shadow_map.cpp
Normal file
@ -0,0 +1,376 @@
|
||||
/* -----------------------------------------------------------------------------
|
||||
GSFramework
|
||||
Copyright 2001-2013 Emmanuel Julien. All Rights Reserved.
|
||||
----------------------------------------------------------------------------- */
|
||||
|
||||
|
||||
#include <cmath>
|
||||
#include "gpu/gpu_renderer.h"
|
||||
#include "core/light.h"
|
||||
#include "log/log.h"
|
||||
|
||||
using namespace GS::Core;
|
||||
using namespace GS::GPU;
|
||||
|
||||
|
||||
struct UVOffset
|
||||
{ float x, y; };
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Renderer::CreateShadowMaps()
|
||||
{
|
||||
gpu_config.enable_shadow = registry.GetBool("ShadowMapping:Enable", true);
|
||||
gpu_config.shadow_size = registry.GetInteger("ShadowMapping:Size", 1024);
|
||||
|
||||
__LOG__ << "Creating shadow maps (" << gpu_config.shadow_size << "x" << gpu_config.shadow_size << ").\n";
|
||||
|
||||
if (gpu_config.enable_shadow)
|
||||
{
|
||||
shadow_map = NewTexture("shadow_map");
|
||||
shadow_map->Create(NULL, gpu_config.shadow_size, gpu_config.shadow_size, Render::Texture::FormatDepth, Render::Texture::NoAA, Render::Texture::Usage(Render::Texture::IsRenderTarget | Render::Texture::IsShaderResource));
|
||||
shadow_map->ConfigureAsShadowMap();
|
||||
|
||||
shadow_map_fbo->SetDepthTexture(shadow_map);
|
||||
}
|
||||
}
|
||||
void Renderer::FreeShadowMaps()
|
||||
{
|
||||
shadow_map = NULL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
struct ShadowRenderData : public Light::RenderData::ShadowRenderData
|
||||
{
|
||||
Renderer::ShadowMapSplit split;
|
||||
};
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
static float ComputeSplitZBoundary(const Camera &lod_view, const Light &light, int index, int count)
|
||||
{
|
||||
if (index <= 0)
|
||||
return lod_view.GetNearClippingPlane();
|
||||
|
||||
float k = float(index) / count;
|
||||
|
||||
float z_log = lod_view.GetNearClippingPlane() * powf(light.shadow_range / lod_view.GetNearClippingPlane(), k);
|
||||
float z_lin = lod_view.GetNearClippingPlane() + (light.shadow_range - lod_view.GetNearClippingPlane()) * k;
|
||||
|
||||
return z_log * light.shadow_distribution + z_lin * (1.f - light.shadow_distribution);
|
||||
}
|
||||
static void FitViewToFrustum(Camera &view, const GS::Frustum &slice, float d)
|
||||
{
|
||||
using namespace GS;
|
||||
|
||||
/*
|
||||
Compute split view item properties so that the split view frustum act as
|
||||
a perfect fit for the split frustum.
|
||||
*/
|
||||
const Vector4 *fv = slice.GetVertices();
|
||||
|
||||
Vector4 vfv[8];
|
||||
view.GetInverseMatrix().Apply(vfv, fv, 8);
|
||||
const Matrix4 &m = view.GetMatrix();
|
||||
|
||||
Vector4 mm[2];
|
||||
mm[0] = mm[1] = vfv[0];
|
||||
for (int n = 1; n < 8; ++n)
|
||||
{
|
||||
mm[0] = Vector4::Minimum(mm[0], vfv[n]);
|
||||
mm[1] = Vector4::Maximum(mm[1], vfv[n]);
|
||||
}
|
||||
Vector4 focus = ((mm[0] + mm[1]) * 0.5) * m;
|
||||
|
||||
// Position the shadow map light item,
|
||||
view.SetPosition(focus - m.GetRow(2) * d);
|
||||
|
||||
// View clipping planes.
|
||||
Vector4 view_front = m.GetRow(2);
|
||||
view.z_far = view_front.Dot(fv[0] - view.GetPosition());
|
||||
for (int n = 1; n < 8; ++n)
|
||||
view.z_far = GS::Types::Max(view.z_far, view_front.Dot(fv[n] - view.GetPosition()));
|
||||
|
||||
// View dimensions.
|
||||
Vector4 view_left = view.GetMatrix().GetRow(0),
|
||||
view_top = view.GetMatrix().GetRow(1);
|
||||
|
||||
Vector4 dt = fv[0] - view.GetPosition();
|
||||
float h_width = std::fabs(view_left.Dot(dt)),
|
||||
h_height = std::fabs(view_top.Dot(dt));
|
||||
|
||||
for (int n = 1; n < 8; ++n)
|
||||
{
|
||||
dt = fv[n] - view.GetPosition();
|
||||
h_width = GS::Types::Max <float> (h_width, std::fabs(view_left.Dot(dt)));
|
||||
h_height = GS::Types::Max <float> (h_height, std::fabs(view_top.Dot(dt)));
|
||||
}
|
||||
view.ortho_w = h_width * 2.f;
|
||||
view.ortho_h = h_height * 2.f;
|
||||
}
|
||||
bool Renderer::LightPreparePSSM(const Light &l, bool build_dlist) const
|
||||
{
|
||||
Light::RenderData *light_render_data = (Light::RenderData *)l.render_data.c_ptr();
|
||||
if (!light_render_data || !light_render_data->shadow_data.Allocate(4))
|
||||
return false;
|
||||
|
||||
int split_count = registry.GetInteger("ShadowMapping:PSSM:Split", 3);
|
||||
|
||||
for (int n = 0; n < split_count; ++n)
|
||||
{
|
||||
Light::RenderData::ShadowData &data = light_render_data->shadow_data[n];
|
||||
|
||||
if (data.render_data.IsNull())
|
||||
data.render_data = new ShadowRenderData;
|
||||
ShadowRenderData *pssm_data = (ShadowRenderData *)data.render_data.c_ptr();
|
||||
|
||||
ShadowMapSplit &split = pssm_data->split;
|
||||
|
||||
static UVOffset split_offset[] = { { 0.0, 0.0 }, { 0.5, 0.0 }, { 0.0, 0.5 }, { 0.5, 0.5 } };
|
||||
split.rect = fRect::FromWidthHeight(split_offset[n].x * gpu_config.shadow_size, split_offset[n].y * gpu_config.shadow_size, gpu_config.shadow_size / 2.f, gpu_config.shadow_size / 2.f);
|
||||
|
||||
// Compute frustum slice.
|
||||
Frustum slice;
|
||||
float znear = ComputeSplitZBoundary(*view_item, l, n, split_count), zfar = ComputeSplitZBoundary(*view_item, l, n + 1, split_count);
|
||||
view_item->ComputeFrustum(slice, GetViewport(), znear, zfar);
|
||||
|
||||
// Adjust view item.
|
||||
split.view.is_orthographic = true;
|
||||
split.view.aspect_ratio = 1;
|
||||
split.view.SnapshotTransformation(l.GetMatrix());
|
||||
|
||||
FitViewToFrustum(split.view, slice, l.shadow_range * 4.f);
|
||||
split.view.ComputeFrustum(split.view.frustum, split.rect);
|
||||
|
||||
// Cull.
|
||||
if (build_dlist)
|
||||
{
|
||||
BuildRenderablePrimitiveList(split.view, *view_item, split.list.primitive_list, Renderable::Context_Shadow);
|
||||
BuildDisplayLists(split.list.primitive_list, split.list.display_lists);
|
||||
}
|
||||
|
||||
// Store slice view to light matrix.
|
||||
data.slice_distance = zfar;
|
||||
data.imatrix = split.view.GetInverseMatrix();
|
||||
split.view.ComputeProjectionMatrix(split.rect, data.pmatrix);
|
||||
if (!gpu_config.tex_origin_is_top_left)
|
||||
data.pmatrix = Matrix4::ScaleMatrix(Vector4(1.0, -1.0, 1.0)) * data.pmatrix;
|
||||
data.pmatrix = Matrix4::ScaleMatrix(Vector4(0.5, 0.5, 0.5)) * Matrix4::TranslationMatrix(Vector4(1, 1, 1)) * data.pmatrix;
|
||||
|
||||
// Crop on PSSM region.
|
||||
data.pmatrix = Matrix4::TranslationMatrix(Vector4(split_offset[n].x, split_offset[n].y, 0.0)) * Matrix4::ScaleMatrix(Vector4(0.5, 0.5, 1.0)) * data.pmatrix;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Renderer::LightRenderPSSM(Light &l)
|
||||
{
|
||||
Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr();
|
||||
ViewConfig view = BackupView();
|
||||
|
||||
SetViewport(fRect(0, 0, (float)gpu_config.shadow_size, (float)gpu_config.shadow_size));
|
||||
Clear(0, 0, 0, 0, 1, ClearDepth);
|
||||
|
||||
int split_count = registry.GetInteger("ShadowMapping:PSSM:Split", 3);
|
||||
for (int n = 0; n < split_count; ++n)
|
||||
{
|
||||
ShadowRenderData *shd_data = (ShadowRenderData *)data->shadow_data[n].render_data.c_ptr();
|
||||
|
||||
SetViewport(shd_data->split.rect);
|
||||
SetClippingRect(&shd_data->split.rect);
|
||||
|
||||
DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::Depth);
|
||||
|
||||
view_item = &shd_data->split.view;
|
||||
ApplyCamera();
|
||||
DrawList(shd_data->split.list.display_lists[0], dc);
|
||||
DrawList(shd_data->split.list.display_lists[2], dc);
|
||||
shd_data->split.list.Clear(false); // limit dynamic allocations
|
||||
}
|
||||
RestoreView(view);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Renderer::LightPreparePSM(const Light &l, bool build_dlist) const
|
||||
{
|
||||
Light::RenderData *light_render_data = (Light::RenderData *)l.render_data.c_ptr();
|
||||
if (!light_render_data || !light_render_data->shadow_data.Allocate(6))
|
||||
return false;
|
||||
|
||||
for (uint n = 0; n < 6; ++n)
|
||||
{
|
||||
Light::RenderData::ShadowData &data = light_render_data->shadow_data[n];
|
||||
|
||||
if (data.render_data.IsNull())
|
||||
data.render_data = new ShadowRenderData;
|
||||
ShadowRenderData *shd_data = (ShadowRenderData *)data.render_data.c_ptr();
|
||||
|
||||
ShadowMapSplit &split = shd_data->split;
|
||||
|
||||
static Vector4 view_angle[6] = { Vector4(0, 0, 0), Vector4(0, Units::Deg(90.f), 0), Vector4(0, Units::Deg(180.f), 0), Vector4(0, Units::Deg(270.f), 0), Vector4(Units::Deg(90.f), 0, 0), Vector4(Units::Deg(270.f), 0, 0) };
|
||||
static UVOffset split_offset[] = { { 0, 0 }, { 0.33f, 0 }, { 0.66f, 0 }, { 0, 0.5f }, { 0.33f, 0.5f }, { 0.66f, 0.5f } };
|
||||
|
||||
split.view.aspect_ratio = 1;
|
||||
split.view.SetFov(Units::Deg(95.f)); // Add a 5<> safe area to avoid artifacts at transition.
|
||||
split.view.SnapshotTransformation(l.GetMatrix() * Matrix4::FromMatrix3(Matrix3::FromEuler(view_angle[n])));
|
||||
|
||||
split.rect = fRect::FromWidthHeight(split_offset[n].x * gpu_config.shadow_size, split_offset[n].y * gpu_config.shadow_size, gpu_config.shadow_size / 3.f, gpu_config.shadow_size / 2.f);
|
||||
|
||||
if (build_dlist)
|
||||
{
|
||||
BuildRenderablePrimitiveList(split.view, *view_item, split.list.primitive_list, Renderable::Context_Shadow);
|
||||
BuildDisplayLists(split.list.primitive_list, split.list.display_lists);
|
||||
}
|
||||
|
||||
// Store cube view to light matrix.
|
||||
data.imatrix = split.view.GetInverseMatrix();
|
||||
split.view.ComputeProjectionMatrix(split.rect, data.pmatrix); // FIXME watch out, do we need the split viewport (split.rect) or the complete viewport???
|
||||
if (!gpu_config.tex_origin_is_top_left)
|
||||
data.pmatrix = Matrix4::ScaleMatrix(Vector4(1, -1, 1)) * data.pmatrix;
|
||||
data.pmatrix = Matrix4::ScaleMatrix(Vector4(0.5f, 0.5f, 0.5f)) * Matrix4::TranslationMatrix(Vector4(1, 1, 1)) * data.pmatrix;
|
||||
|
||||
// Crop on view region.
|
||||
data.pmatrix = Matrix4::TranslationMatrix(Vector4(split_offset[n].x, split_offset[n].y, 0.f)) * Matrix4::ScaleMatrix(Vector4(0.33f, 0.5f, 1)) * data.pmatrix;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Renderer::LightRenderPSM(Light &l)
|
||||
{
|
||||
Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr();
|
||||
ViewConfig view = BackupView();
|
||||
|
||||
SetViewport(fRect(0, 0, (float)gpu_config.shadow_size, (float)gpu_config.shadow_size));
|
||||
Clear(0, 0, 0, 0, 1, ClearDepth);
|
||||
|
||||
for (uint n = 0; n < 6; ++n)
|
||||
{
|
||||
ShadowRenderData *psm_data = (ShadowRenderData *)data->shadow_data[n].render_data.c_ptr();
|
||||
|
||||
SetViewport(psm_data->split.rect);
|
||||
SetClippingRect(&psm_data->split.rect);
|
||||
|
||||
view_item = &psm_data->split.view;
|
||||
ApplyCamera();
|
||||
|
||||
DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::Depth);
|
||||
DrawList(psm_data->split.list.display_lists[0], dc);
|
||||
DrawList(psm_data->split.list.display_lists[2], dc);
|
||||
psm_data->split.list.Clear(false); // limit dynamic allocations
|
||||
}
|
||||
RestoreView(view);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Renderer::LightPrepareSSM(const Light &l, bool build_dlist) const
|
||||
{
|
||||
Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr();
|
||||
if (!data || !data->shadow_data.Allocate(1))
|
||||
return false;
|
||||
|
||||
if (data->shadow_data[0].render_data.IsNull())
|
||||
data->shadow_data[0].render_data = new ShadowRenderData;
|
||||
ShadowRenderData *shd_data = (ShadowRenderData *)data->shadow_data[0].render_data.c_ptr();
|
||||
|
||||
Renderer::ShadowMapSplit &split = shd_data->split;
|
||||
split.view.AlignTo(l);
|
||||
|
||||
if (build_dlist)
|
||||
{
|
||||
BuildRenderablePrimitiveList(split.view, *view_item, split.list.primitive_list, Renderable::Context_Shadow);
|
||||
BuildDisplayLists(split.list.primitive_list, split.list.display_lists);
|
||||
}
|
||||
|
||||
// Store shadow matrices.
|
||||
data->shadow_data[0].imatrix = split.view.GetInverseMatrix();
|
||||
l.ComputeProjectionMatrix(data->shadow_data[0].pmatrix);
|
||||
if (!gpu_config.tex_origin_is_top_left)
|
||||
data->shadow_data[0].pmatrix = Matrix4::ScaleMatrix(Vector4(1.0, -1.0, 1.0)) * data->shadow_data[0].pmatrix;
|
||||
data->shadow_data[0].pmatrix = Matrix4::ScaleMatrix(Vector4(0.5, 0.5, 0.5)) * Matrix4::TranslationMatrix(Vector4(1, 1, 1)) * data->shadow_data[0].pmatrix;
|
||||
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
void Renderer::LightRenderSSM(Light &l)
|
||||
{
|
||||
Light::RenderData *data = (Light::RenderData *)l.render_data.c_ptr();
|
||||
ViewConfig view = BackupView();
|
||||
|
||||
SetViewport(fRect(0, 0, (float)gpu_config.shadow_size, (float)gpu_config.shadow_size));
|
||||
Clear(0, 0, 0, 0, 1, ClearDepth);
|
||||
|
||||
ShadowRenderData *render_data = (ShadowRenderData *)data->shadow_data[0].render_data.c_ptr();
|
||||
|
||||
view_item = &render_data->split.view;
|
||||
ApplyCamera();
|
||||
|
||||
DrawContext dc(DrawContext::Opaque, DrawContext::Base, MaterialShader::Depth);
|
||||
DrawList(render_data->split.list.display_lists[0], dc);
|
||||
DrawList(render_data->split.list.display_lists[2], dc);
|
||||
render_data->split.list.Clear(false); // limit dynamic allocations
|
||||
|
||||
RestoreView(view);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
Renderer::ViewConfig Renderer::BackupView() const
|
||||
{
|
||||
return ViewConfig(view_item, viewport);
|
||||
}
|
||||
void Renderer::RestoreViewport(const ViewConfig &config)
|
||||
{
|
||||
SetViewport(config.viewport);
|
||||
}
|
||||
void Renderer::RestoreView(const ViewConfig &config)
|
||||
{
|
||||
RestoreViewport(config);
|
||||
view_item = config.camera;
|
||||
ApplyCamera();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
bool Renderer::PrepareShadowMap(const Light &l, bool build_dlist) const
|
||||
{
|
||||
switch (l.model)
|
||||
{
|
||||
case Light::Model_Spot: return LightPrepareSSM(l, build_dlist);
|
||||
case Light::Model_Point: return LightPreparePSM(l, build_dlist);
|
||||
case Light::Model_Linear: return LightPreparePSSM(l, build_dlist);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void Renderer::RenderShadowMap(Light &l)
|
||||
{
|
||||
PerfBeginEvent(__FUNCTION__, Color::Blue);
|
||||
|
||||
SetCurrentFBO(shadow_map_fbo);
|
||||
SetCullFunc(CullBack);
|
||||
|
||||
fRect old_clipping = GetClippingRect();
|
||||
SetClippingRect(NULL);
|
||||
|
||||
switch (l.model)
|
||||
{
|
||||
case Light::Model_Spot: LightRenderSSM(l); break;
|
||||
case Light::Model_Point: LightRenderPSM(l); break;
|
||||
case Light::Model_Linear: LightRenderPSSM(l); break;
|
||||
}
|
||||
|
||||
SetClippingRect(&old_clipping);
|
||||
|
||||
SetCullFunc(CullFront);
|
||||
SetCurrentFBO(NULL);
|
||||
|
||||
PerfEndEvent();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
Reference in New Issue
Block a user