mirror of
https://github.com/harfang3d/harfang3d.git
synced 2024-07-16 15:02:19 +00:00
487 lines
19 KiB
C++
487 lines
19 KiB
C++
// HARFANG(R) Copyright (C) 2021 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
|
|
|
|
#include "engine/forward_pipeline.h"
|
|
#include "engine/assets_rw_interface.h"
|
|
#include "engine/render_pipeline.h"
|
|
#include "engine/scene.h"
|
|
#include "engine/taa.h"
|
|
|
|
#include "foundation/clock.h"
|
|
#include "foundation/file_rw_interface.h"
|
|
#include "foundation/format.h"
|
|
#include "foundation/math.h"
|
|
#include "foundation/path_tools.h"
|
|
#include "foundation/projection.h"
|
|
|
|
#include <bgfx/bgfx.h>
|
|
#include <math.h>
|
|
#include <vector>
|
|
|
|
namespace hg {
|
|
|
|
enum ForwardPipelineUniformValue {
|
|
UV_Clock,
|
|
|
|
UV_FogColor,
|
|
UV_FogState,
|
|
|
|
UV_AmbientColor,
|
|
|
|
UV_LightPos,
|
|
UV_LightDir,
|
|
UV_LightDiffuse,
|
|
UV_LightSpecular,
|
|
|
|
UV_LinearShadowMatrix,
|
|
UV_LinearShadowSlice,
|
|
UV_SpotShadowMatrix,
|
|
UV_ShadowState,
|
|
|
|
UV_Resolution,
|
|
UV_Projection,
|
|
UV_MainProjection,
|
|
UV_MainInvProjection,
|
|
|
|
UV_PreviousViewProjection,
|
|
UV_ViewProjUnjittered, // for TAA
|
|
UV_AAAParams, // [0].x: ssgi ratio, [0].y: ssr ratio, [0].z: temporal AA weight, [0].w: motion blur strength, [1].x: exposure, [1].y: 1/gamma
|
|
|
|
UV_MainInvView,
|
|
|
|
UV_Count
|
|
};
|
|
|
|
enum ForwardPipelineUniformTexture {
|
|
UT_IrradianceMap,
|
|
UT_RadianceMap,
|
|
UT_BrdfMap,
|
|
UT_NoiseMap,
|
|
|
|
UT_AmbientOcclusion,
|
|
UT_LinearShadowMap,
|
|
UT_SpotShadowMap,
|
|
|
|
UT_Count
|
|
};
|
|
|
|
//
|
|
ForwardPipelineLight MakeForwardPipelinePointLight(const hg::Mat4 &world, const hg::Color &diffuse, const hg::Color &specular, float radius, float priority,
|
|
ForwardPipelineShadowType shadow_type, float shadow_bias) {
|
|
return {FPLT_Point, shadow_type, world, diffuse, specular, radius, 0.f, 0.f, hg::Vec4::Zero, priority, shadow_bias};
|
|
}
|
|
|
|
ForwardPipelineLight MakeForwardPipelineSpotLight(const hg::Mat4 &world, const hg::Color &diffuse, const hg::Color &specular, float radius, float inner_angle,
|
|
float outer_angle, float priority, ForwardPipelineShadowType shadow_type, float shadow_bias) {
|
|
return {FPLT_Spot, shadow_type, world, diffuse, specular, radius, inner_angle, outer_angle, hg::Vec4::Zero, priority, shadow_bias};
|
|
}
|
|
|
|
ForwardPipelineLight MakeForwardPipelineLinearLight(const hg::Mat4 &world, const hg::Color &diffuse, const hg::Color &specular, const hg::Vec4 &pssm_split,
|
|
float priority, ForwardPipelineShadowType shadow_type, float shadow_bias) {
|
|
return {FPLT_Linear, shadow_type, world, diffuse, specular, 0.f, 0.f, 0.f, pssm_split, priority, shadow_bias};
|
|
}
|
|
|
|
//
|
|
ForwardPipelineLights PrepareForwardPipelineLights(const std::vector<ForwardPipelineLight> &lights) {
|
|
ForwardPipelineLights ls{};
|
|
|
|
// separate lights per type
|
|
std::vector<int> i_linear, i_point;
|
|
i_linear.reserve(8);
|
|
i_point.reserve(64);
|
|
|
|
for (size_t i = 0; i < lights.size(); ++i)
|
|
if (lights[i].type == FPLT_Linear)
|
|
i_linear.push_back(int(i));
|
|
else
|
|
i_point.push_back(int(i));
|
|
|
|
// slot 0: single linear light
|
|
std::sort(std::begin(i_linear), std::end(i_linear), [&](const auto &a, const auto &b) { return lights[a].priority > lights[b].priority; });
|
|
|
|
if (!i_linear.empty()) {
|
|
const auto &l = lights[i_linear.front()];
|
|
|
|
ls.pos[0] = Vec4(GetT(l.world), 0.f);
|
|
ls.dir[0] = Vec4(GetZ(l.world), 0.f);
|
|
ls.diff[0] = {l.diffuse.r, l.diffuse.g, l.diffuse.b, 0.f};
|
|
ls.spec[0] = {l.specular.r, l.specular.g, l.specular.b, 0.f};
|
|
ls.lights[0] = l;
|
|
}
|
|
|
|
// slot 1-n: point/spot
|
|
std::sort(std::begin(i_point), std::end(i_point), [&](const auto &a, const auto &b) { return lights[a].priority > lights[b].priority; });
|
|
|
|
size_t slot_idx = 1;
|
|
for (auto i : i_point) {
|
|
const auto &l = lights[i];
|
|
|
|
ls.pos[slot_idx] = Vec4(GetT(l.world), l.radius ? 1.f / l.radius : 0.f);
|
|
ls.dir[slot_idx] = Vec4(GetZ(l.world), l.type == FPLT_Spot ? Cos(l.inner_angle) : 0.f);
|
|
ls.diff[slot_idx] = {l.diffuse.r, l.diffuse.g, l.diffuse.b, l.type == FPLT_Spot ? Cos(l.outer_angle) : 0.f};
|
|
ls.spec[slot_idx] = {l.specular.r, l.specular.g, l.specular.b, 0.f};
|
|
ls.lights[slot_idx] = l;
|
|
|
|
if (++slot_idx == forward_light_count)
|
|
break; // all slots filled
|
|
}
|
|
|
|
return ls;
|
|
}
|
|
|
|
//
|
|
void UpdateForwardPipeline(ForwardPipeline &pipeline, const ForwardPipelineShadowData &shadow_data, const Color &ambient, const ForwardPipelineLights &lights,
|
|
const ForwardPipelineFog &fog) {
|
|
pipeline.uniform_values[UV_Clock].value[0] = time_to_sec_f(get_clock());
|
|
|
|
pipeline.uniform_values[UV_FogColor].value = {fog.color.r, fog.color.g, fog.color.b, fog.color.a};
|
|
pipeline.uniform_values[UV_FogState].value = {fog.near, (fog.far - fog.near) ? 1.f / (fog.far - fog.near) : 0.f, 0.f, 0.f};
|
|
|
|
pipeline.uniform_values[UV_AmbientColor].value = {ambient.r, ambient.g, ambient.b, ambient.a};
|
|
|
|
for (size_t i = 0; i < forward_light_count; ++i) {
|
|
memcpy(pipeline.uniform_values[UV_LightPos].value.data() + i * 4, &lights.pos[i].x, sizeof(float) * 4);
|
|
memcpy(pipeline.uniform_values[UV_LightDir].value.data() + i * 4, &lights.dir[i].x, sizeof(float) * 4);
|
|
memcpy(pipeline.uniform_values[UV_LightDiffuse].value.data() + i * 4, &lights.diff[i].x, sizeof(float) * 4);
|
|
memcpy(pipeline.uniform_values[UV_LightSpecular].value.data() + i * 4, &lights.spec[i].x, sizeof(float) * 4);
|
|
}
|
|
|
|
for (size_t i = 0; i < 4; ++i)
|
|
memcpy(pipeline.uniform_values[UV_LinearShadowMatrix].value.data() + i * 16, to_bgfx(shadow_data.linear_shadow_mtx[i]).data(), sizeof(float) * 16);
|
|
memcpy(pipeline.uniform_values[UV_LinearShadowSlice].value.data(), &shadow_data.linear_shadow_slice.x, sizeof(float) * 4);
|
|
|
|
memcpy(pipeline.uniform_values[UV_SpotShadowMatrix].value.data(), to_bgfx(shadow_data.spot_shadow_mtx).data(), sizeof(float) * 16);
|
|
|
|
pipeline.uniform_values[UV_ShadowState].value = {
|
|
1.f / pipeline.shadow_map_resolution, 1.f / pipeline.shadow_map_resolution, lights.lights[0].shadow_bias, lights.lights[1].shadow_bias};
|
|
|
|
const auto stats = bgfx::getStats();
|
|
pipeline.uniform_values[UV_Resolution].value = {float(stats->width), float(stats->height), -1, -1};
|
|
}
|
|
|
|
void UpdateForwardPipelinePBRProbe(ForwardPipeline &pipeline, Texture irradiance, Texture radiance, Texture brdf) {
|
|
pipeline.uniform_textures[UT_IrradianceMap].texture = irradiance;
|
|
pipeline.uniform_textures[UT_RadianceMap].texture = radiance;
|
|
pipeline.uniform_textures[UT_BrdfMap].texture = brdf;
|
|
}
|
|
|
|
void UpdateForwardPipelineNoise(ForwardPipeline &pipeline, Texture noise) { pipeline.uniform_textures[UT_NoiseMap].texture = noise; }
|
|
void UpdateForwardPipelineAO(ForwardPipeline &pipeline, Texture ao) { pipeline.uniform_textures[UT_AmbientOcclusion].texture = ao; }
|
|
|
|
//
|
|
static float backbuffer_ratio[bgfx::BackbufferRatio::Count] = {1.f, 2.f, 4.f, 8.f, 16.f, 0.5f};
|
|
|
|
void UpdateForwardPipelineAAA(ForwardPipeline &pipeline, const iRect &rect, const Mat4 &view, const Mat44 &proj, const Mat4 &prv_view, const Mat44 &prv_proj,
|
|
const Vec2 &jitter, bgfx::BackbufferRatio::Enum ssgi_ratio, bgfx::BackbufferRatio::Enum ssr_ratio, float temporal_aa_weight, float motion_blur_strength,
|
|
float exposure, float gamma, int sample_count, float max_distance) {
|
|
pipeline.uniform_values[UV_Projection].value = {1.f / proj.m[0][0], 1.f / proj.m[1][1], proj.m[2][2], proj.m[2][3]};
|
|
|
|
memcpy(pipeline.uniform_values[UV_ViewProjUnjittered].value.data(), to_bgfx(proj * view).data(), sizeof(float) * 16);
|
|
memcpy(pipeline.uniform_values[UV_PreviousViewProjection].value.data(), to_bgfx(prv_proj * prv_view).data(), sizeof(float) * 16);
|
|
|
|
memcpy(pipeline.uniform_values[UV_MainProjection].value.data(), to_bgfx(proj).data(), sizeof(float) * 16);
|
|
memcpy(pipeline.uniform_values[UV_MainInvProjection].value.data(), to_bgfx(Inverse(proj)).data(), sizeof(float) * 16);
|
|
|
|
pipeline.uniform_values[UV_AAAParams].value = {backbuffer_ratio[ssgi_ratio], backbuffer_ratio[ssr_ratio], temporal_aa_weight, motion_blur_strength,
|
|
exposure, 1.f / gamma, float(sample_count), max_distance};
|
|
|
|
memcpy(pipeline.uniform_values[UV_MainInvView].value.data(), to_bgfx(InverseFast(view)).data(), sizeof(float) * 16);
|
|
}
|
|
|
|
//
|
|
void SubmitModelToForwardPipeline(bgfx::ViewId view_id, const Model &mdl, const ForwardPipeline &pipeline, const PipelineProgram &prg, uint32_t prg_variant,
|
|
uint8_t pipeline_stage, const Color &ambient, const ForwardPipelineLights &lights, const ForwardPipelineFog &fog, const Mat4 &mtx) {
|
|
const auto _mtx = to_bgfx(mtx);
|
|
/*
|
|
const auto pipeline_set_draw_env = [&](int mat_idx) {
|
|
UpdateForwardPipelineUniforms(pipeline.uniforms, ambient, lights, fog);
|
|
set_draw_env(mat_idx);
|
|
};
|
|
|
|
RenderModel(view_id, mdl, prg.variants[prg_variant][pipeline_stage], pipeline_set_draw_env, mtx);
|
|
*/
|
|
}
|
|
|
|
static hg::Mat4 ComputeCropMatrix() {
|
|
const bgfx::Caps *caps = bgfx::getCaps();
|
|
const float sy = caps->originBottomLeft ? 0.5f : -0.5f;
|
|
const float sz = caps->homogeneousDepth ? 0.5f : 1.0f;
|
|
const float tz = caps->homogeneousDepth ? 0.5f : 0.0f;
|
|
return TranslationMat4({0.5, 0.5, tz}) * ScaleMat4({0.5, sy, sz});
|
|
}
|
|
|
|
static const hg::Vec4 frustum_corners[8] = {{-1.f, 1.f, 0.f, 1.f}, {1.f, 1.f, 0.f, 1.f}, {1.f, -1.f, 0.f, 1.f}, {-1.f, -1.f, 0.f, 1.f}, {-1.f, 1.f, 1.f, 1.f},
|
|
{1.f, 1.f, 1.f, 1.f}, {1.f, -1.f, 1.f, 1.f}, {-1.f, -1.f, 1.f, 1.f}};
|
|
|
|
void GenerateLinearShadowMapForForwardPipeline(bgfx::ViewId &view_id, const ViewState &view_state, const std::vector<ModelDisplayList> &display_lists,
|
|
const std::vector<SkinnedModelDisplayList> &skinned_display_lists, const std::vector<Mat4> &mtxs, const ForwardPipelineLights &lights,
|
|
const ForwardPipeline &pipeline, const PipelineResources &res, ForwardPipelineShadowPassViewId &views, ForwardPipelineShadowData &shadow_data,
|
|
const char *debug_name) {
|
|
const bgfx::Caps *caps = bgfx::getCaps();
|
|
|
|
std::fill(std::begin(views), std::end(views), 65535);
|
|
const auto &framebuffers_end = std::end(pipeline.framebuffers);
|
|
|
|
const auto &light = lights.lights[0];
|
|
if (light.type == FPLT_None)
|
|
return;
|
|
|
|
if (light.shadow_type == FPST_None)
|
|
return;
|
|
|
|
// SLOT 0: linear light
|
|
const auto &linear_buffer = pipeline.framebuffers.find("linear_shadow_map");
|
|
if (linear_buffer != framebuffers_end) {
|
|
const int resolution = pipeline.shadow_map_resolution;
|
|
|
|
float near, far;
|
|
ExtractZRangeFromProjectionMatrix(view_state.proj, near, far);
|
|
|
|
Mat4 offset = {0.5f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f};
|
|
|
|
const Mat4 world = InverseFast(view_state.view);
|
|
bool inv_result;
|
|
const Mat44 inv_proj = Inverse(view_state.proj, inv_result);
|
|
|
|
if (inv_result) {
|
|
Vec3 view_dir = GetZ(world);
|
|
Vec3 view_orig = GetT(world);
|
|
Vec3 light_up = GetY(light.world);
|
|
Vec3 light_dir = GetZ(light.world);
|
|
Mat4 inv_light_base = InverseFast(light.world);
|
|
|
|
// project frustum corners back to view space.
|
|
Vec3 corners[8];
|
|
for (int i = 0; i < 8; i++) {
|
|
Vec4 tmp = inv_proj * frustum_corners[i];
|
|
corners[i] = MakeVec3(tmp) / tmp.w;
|
|
}
|
|
// adjust to shadow range
|
|
float scale = light.pssm_split[3] / (corners[4].z - corners[0].z);
|
|
for (int i = 0; i < 4; i++)
|
|
corners[i + 4] = (corners[i + 4] - corners[i]) * scale;
|
|
|
|
// project back to world space
|
|
for (int i = 0; i < 8; i++)
|
|
corners[i] = world * corners[i];
|
|
|
|
const bgfx::Caps *caps = bgfx::getCaps();
|
|
|
|
float c0 = near;
|
|
for (int i = 0; i < 4; i++) {
|
|
const float c1 = light.pssm_split[i];
|
|
|
|
// compute split frustum and its center
|
|
Vec3 s[8], center = Vec3::Zero;
|
|
for (int j = 0; j < 4; j++) {
|
|
s[j] = corners[j] + (corners[j + 4] - corners[j]) * (c0 - near) / (light.pssm_split[3] - near);
|
|
s[j + 4] = corners[j] + (corners[j + 4] - corners[j]) * (c1 - near) / (light.pssm_split[3] - near);
|
|
center += s[j] + s[j + 4];
|
|
}
|
|
center /= 8.f;
|
|
|
|
// compute split radius
|
|
float radius = 0.f;
|
|
for (const auto v : s)
|
|
radius = Max(radius, Dist(center, v));
|
|
|
|
// [todo] find the most distant shadow caster for this slice
|
|
const float backup_dist = Mtr(200.f); // 4.f * radius;
|
|
|
|
Vec3 light_position = inv_light_base * (center - backup_dist * light_dir);
|
|
|
|
// stabilization (snap to shadow map texels)
|
|
light_position.x -= fmod(light_position.x, 2.f * radius / (float)resolution);
|
|
light_position.y -= fmod(light_position.y, 2.f * radius / (float)resolution);
|
|
|
|
Mat4 light_view = light.world;
|
|
SetTranslation(light_view, light.world * light_position);
|
|
const Mat4 inv_light = InverseFast(light_view);
|
|
const Mat44 light_projection = ComputeOrthographicProjectionMatrix(0.f, backup_dist + radius, 2.f * radius, Vec2::One);
|
|
const Mat4 crop_mtx = ComputeCropMatrix();
|
|
|
|
const Mat44 light_viewproj = light_projection * inv_light;
|
|
|
|
// select which part of the shadow map we will render to
|
|
offset.m[0][3] = (i & 1) ? 0.5f : 0.0f;
|
|
offset.m[1][3] = (i & 2) ? 0.5f : 0.0f;
|
|
shadow_data.linear_shadow_mtx[i] = offset * crop_mtx * light_viewproj;
|
|
shadow_data.linear_shadow_slice[i] = c1;
|
|
const auto frustum = MakeFrustum(light_projection, light_view);
|
|
|
|
c0 = c1;
|
|
|
|
if (debug_name)
|
|
bgfx::setViewName(view_id, format("Shadow map slot 0 (slice %1) for %2").arg(i).arg(debug_name));
|
|
|
|
uint16_t view_x = (i & 1) * resolution;
|
|
uint16_t view_y = ((i >> 1) & 1) * resolution;
|
|
|
|
if (caps->originBottomLeft)
|
|
view_y = resolution - view_y;
|
|
|
|
bgfx::touch(view_id);
|
|
bgfx::setViewMode(bgfx::ViewMode::Default);
|
|
bgfx::setViewRect(view_id, view_x, view_y, resolution, resolution);
|
|
bgfx::setViewClear(view_id, BGFX_CLEAR_DEPTH, 0x0, 1.f, 0);
|
|
bgfx::setViewTransform(view_id, to_bgfx(inv_light).data(), to_bgfx(light_projection).data());
|
|
bgfx::setViewFrameBuffer(view_id, linear_buffer->second);
|
|
|
|
std::vector<ModelDisplayList> culled_display_lists = display_lists;
|
|
CullModelDisplayLists(frustum, culled_display_lists, mtxs, res);
|
|
|
|
DrawModelDisplayLists(view_id, culled_display_lists, 0, pipeline.uniform_values, pipeline.uniform_textures, mtxs, res);
|
|
|
|
// FIXME cull skinned models!
|
|
DrawSkinnedModelDisplayLists(view_id, skinned_display_lists, 0, pipeline.uniform_values, pipeline.uniform_textures, mtxs, res);
|
|
|
|
views[FPSP_Slot0LinearSplit0 + i] = view_id++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
void GenerateSpotShadowMapForForwardPipeline(bgfx::ViewId &view_id, const std::vector<ModelDisplayList> &display_lists,
|
|
const std::vector<SkinnedModelDisplayList> &skinned_display_lists, const std::vector<Mat4> &mtxs, const ForwardPipelineLights &lights,
|
|
const ForwardPipeline &pipeline, const PipelineResources &res, ForwardPipelineShadowPassViewId &views, ForwardPipelineShadowData &shadow_data,
|
|
const char *debug_name) {
|
|
const bgfx::Caps *caps = bgfx::getCaps();
|
|
|
|
std::fill(std::begin(views), std::end(views), 65535);
|
|
const auto &framebuffers_end = std::end(pipeline.framebuffers);
|
|
|
|
const auto &light = lights.lights[1];
|
|
if (light.type == FPLT_None)
|
|
return;
|
|
|
|
// SLOT 1: spot light
|
|
const auto &spot_buffer = pipeline.framebuffers.find("spot_shadow_map");
|
|
if (spot_buffer != framebuffers_end) {
|
|
const auto view = InverseFast(light.world);
|
|
const auto proj = ComputePerspectiveProjectionMatrix(0.1f, 100.f, FovToZoomFactor(2.f * light.outer_angle), {1.f, 1.f});
|
|
const auto frustum = MakeFrustum(proj, light.world);
|
|
const auto crop_mtx = ComputeCropMatrix();
|
|
shadow_data.spot_shadow_mtx = crop_mtx * (proj * view);
|
|
|
|
if (debug_name)
|
|
bgfx::setViewName(view_id, format("Shadow map slot 1 for %1").arg(debug_name));
|
|
|
|
bgfx::touch(view_id);
|
|
bgfx::setViewMode(bgfx::ViewMode::Default);
|
|
bgfx::setViewRect(view_id, 0, 0, pipeline.shadow_map_resolution, pipeline.shadow_map_resolution);
|
|
bgfx::setViewClear(view_id, BGFX_CLEAR_DEPTH, 0x0, 1.f, 0);
|
|
bgfx::setViewTransform(view_id, to_bgfx(view).data(), to_bgfx(proj).data());
|
|
bgfx::setViewFrameBuffer(view_id, spot_buffer->second);
|
|
|
|
std::vector<ModelDisplayList> culled_display_lists = display_lists;
|
|
CullModelDisplayLists(frustum, culled_display_lists, mtxs, res);
|
|
|
|
DrawModelDisplayLists(view_id, culled_display_lists, 0, pipeline.uniform_values, pipeline.uniform_textures, mtxs, res);
|
|
|
|
// FIXME cull skinned models!
|
|
DrawSkinnedModelDisplayLists(view_id, skinned_display_lists, 0, pipeline.uniform_values, pipeline.uniform_textures, mtxs, res);
|
|
|
|
views[FPSP_Slot1Spot] = view_id++;
|
|
}
|
|
}
|
|
|
|
// Forward pipeline configurations
|
|
static const PipelineInfo forward_pipeline_info = {
|
|
"forward",
|
|
{
|
|
// AAA rendering prepass
|
|
{"FORWARD_PIPELINE_AAA_PREPASS=1", "FORWARD_PIPELINE_AAA=1", "FORWARD_PIPELINE=1"},
|
|
|
|
// basic rendering
|
|
{"FORWARD_PIPELINE=1"},
|
|
{"FORWARD_PIPELINE=1", "SLOT0_SHADOWS=1"},
|
|
{"FORWARD_PIPELINE=1", "SLOT1_SHADOWS=1"},
|
|
{"FORWARD_PIPELINE=1", "SLOT0_SHADOWS=1", "SLOT1_SHADOWS=1"},
|
|
|
|
// AAA rendering
|
|
{"FORWARD_PIPELINE_AAA=1", "FORWARD_PIPELINE=1"},
|
|
{"FORWARD_PIPELINE_AAA=1", "FORWARD_PIPELINE=1", "SLOT0_SHADOWS=1"},
|
|
{"FORWARD_PIPELINE_AAA=1", "FORWARD_PIPELINE=1", "SLOT1_SHADOWS=1"},
|
|
{"FORWARD_PIPELINE_AAA=1", "FORWARD_PIPELINE=1", "SLOT0_SHADOWS=1", "SLOT1_SHADOWS=1"},
|
|
},
|
|
};
|
|
|
|
const PipelineInfo &GetForwardPipelineInfo() { return forward_pipeline_info; }
|
|
|
|
//
|
|
ForwardPipeline CreateForwardPipeline(int shadow_map_resolution, bool spot_16bit_shadow_map) {
|
|
ForwardPipeline pipeline;
|
|
|
|
pipeline.shadow_map_resolution = shadow_map_resolution;
|
|
pipeline.textures = {
|
|
{"linear_shadow_map", bgfx::createTexture2D(pipeline.shadow_map_resolution * 2, pipeline.shadow_map_resolution * 2, false, 1, bgfx::TextureFormat::D32,
|
|
BGFX_TEXTURE_RT | BGFX_SAMPLER_COMPARE_LEQUAL)}, // this map is an atlas of 4 splits
|
|
{"spot_shadow_map", bgfx::createTexture2D(pipeline.shadow_map_resolution, pipeline.shadow_map_resolution, false, 1,
|
|
spot_16bit_shadow_map ? bgfx::TextureFormat::D16 : bgfx::TextureFormat::D32, BGFX_TEXTURE_RT | BGFX_SAMPLER_COMPARE_LEQUAL)},
|
|
};
|
|
|
|
for (auto &i : pipeline.textures)
|
|
bgfx::setName(i.second, i.first.c_str());
|
|
|
|
bgfx::TextureHandle linear_shadow_map_texs[] = {pipeline.textures["linear_shadow_map"]};
|
|
bgfx::TextureHandle spot_shadow_map_texs[] = {pipeline.textures["spot_shadow_map"]};
|
|
|
|
pipeline.framebuffers = {
|
|
{"linear_shadow_map", bgfx::createFrameBuffer(1, linear_shadow_map_texs)},
|
|
{"spot_shadow_map", bgfx::createFrameBuffer(1, spot_shadow_map_texs)},
|
|
};
|
|
|
|
for (auto &i : pipeline.framebuffers)
|
|
bgfx::setName(i.second, i.first.c_str());
|
|
|
|
pipeline.uniform_values = {
|
|
MakeUniformSetValue("uClock", Vec4{}),
|
|
|
|
MakeUniformSetValue("uFogColor", Vec4{}),
|
|
MakeUniformSetValue("uFogState", Vec4{}),
|
|
|
|
MakeUniformSetValue("uAmbientColor", Vec4{}),
|
|
|
|
MakeUniformSetValue("uLightPos", Vec4{}, 8),
|
|
MakeUniformSetValue("uLightDir", Vec4{}, 8),
|
|
MakeUniformSetValue("uLightDiffuse", Vec4{}, 8),
|
|
MakeUniformSetValue("uLightSpecular", Vec4{}, 8),
|
|
|
|
MakeUniformSetValue("uLinearShadowMatrix", Mat4{}, 4),
|
|
MakeUniformSetValue("uLinearShadowSlice", Vec4{}),
|
|
MakeUniformSetValue("uSpotShadowMatrix", Mat4{}),
|
|
MakeUniformSetValue("uShadowState", Vec4{}),
|
|
|
|
// advanced
|
|
MakeUniformSetValue("uResolution", Vec4{}),
|
|
MakeUniformSetValue("uProjection", Vec4{}),
|
|
MakeUniformSetValue("uMainProjection", Mat4{}),
|
|
MakeUniformSetValue("uMainInvProjection", Mat4{}),
|
|
|
|
MakeUniformSetValue("uPreviousViewProjection", Mat4{}),
|
|
MakeUniformSetValue("uViewProjUnjittered", Mat4{}),
|
|
MakeUniformSetValue("uAAAParams", Vec4{}, 2), // [2]
|
|
|
|
MakeUniformSetValue("uMainInvView", Mat4{}),
|
|
};
|
|
|
|
__ASSERT__(pipeline.uniform_values.size() == UV_Count);
|
|
|
|
pipeline.uniform_textures = {
|
|
MakeUniformSetTexture("uIrradianceMap", {}, 8),
|
|
MakeUniformSetTexture("uRadianceMap", {}, 9),
|
|
MakeUniformSetTexture("uBrdfMap", {}, 10),
|
|
MakeUniformSetTexture("uNoiseMap", {}, 11),
|
|
|
|
MakeUniformSetTexture("uAmbientOcclusion", {}, 13),
|
|
MakeUniformSetTexture("uLinearShadowMap", {BGFX_TEXTURE_RT | BGFX_SAMPLER_COMPARE_LEQUAL, pipeline.textures["linear_shadow_map"]}, 14),
|
|
MakeUniformSetTexture("uSpotShadowMap", {BGFX_TEXTURE_RT | BGFX_SAMPLER_COMPARE_LEQUAL, pipeline.textures["spot_shadow_map"]}, 15),
|
|
};
|
|
|
|
__ASSERT__(pipeline.uniform_textures.size() == UT_Count);
|
|
|
|
return pipeline;
|
|
}
|
|
|
|
} // namespace hg
|