harfang3d/harfang/engine/scene_forward_pipeline.cpp

989 lines
42 KiB
C++

// HARFANG(R) Copyright (C) 2021 Emmanuel Julien, NWNC HARFANG. Released under GPL/LGPL/Commercial Licence, see licence.txt for details.
#include "engine/scene_forward_pipeline.h"
#include "engine/assets_rw_interface.h"
#include "engine/scene.h"
#include "foundation/file_rw_interface.h"
#include "foundation/format.h"
#include "foundation/log.h"
#include "foundation/projection.h"
#include "fabgen.h"
#include <json/json.hpp>
namespace bgfx {
void getTextureSizeFromRatio(BackbufferRatio::Enum _ratio, uint16_t &_width, uint16_t &_height);
} // namespace bgfx
namespace hg {
void UpdateForwardPipeline(ForwardPipeline &pipeline, const ForwardPipelineShadowData &shadow_data, const Color &ambient, const ForwardPipelineLights &lights,
const ForwardPipelineFog &fog, const hg::iVec2 &fb_size);
void UpdateForwardPipelineNoise(ForwardPipeline &pipeline, Texture noise);
void UpdateForwardPipelineProbe(
ForwardPipeline &pipeline, Texture irradiance, Texture radiance, Texture brdf, ProbeType type, const Mat4 &world, float parallax);
void UpdateForwardPipelineAO(ForwardPipeline &pipeline, Texture ao);
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, float specular_weight, float sharpen);
void UpdateForwardPipelineAAA(ForwardPipeline &pipeline, Texture ssgi, Texture ssr);
static const uint64_t attribute_texture_flags = 0 | BGFX_TEXTURE_RT | BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP;
//
void ForwardPipelineAAA::Flip(const ViewState &view_state) {
std::swap(prv_frame_hdr_fb, next_frame_hdr_fb);
prv_view_state = view_state;
}
//
bool LoadForwardPipelineAAAConfig(const json &js, ForwardPipelineAAAConfig &config) {
config.temporal_aa_weight = js["taa_weight"];
config.sample_count = js["sample_count"];
config.max_distance = js["max_distance"];
config.z_thickness = js["z_thickness"];
config.bloom_threshold = js["bloom_threshold"];
config.bloom_bias = js["bloom_bias"];
config.bloom_intensity = js["bloom_intensity"];
config.motion_blur = js["motion_blur"];
config.exposure = js["exposure"];
config.gamma = js["gamma"];
return true;
}
void SaveForwardPipelineAAAConfig(json &js, const ForwardPipelineAAAConfig &config) {
js["taa_weight"] = config.temporal_aa_weight;
js["sample_count"] = config.sample_count;
js["max_distance"] = config.max_distance;
js["z_thickness"] = config.z_thickness;
js["bloom_threshold"] = config.bloom_threshold;
js["bloom_bias"] = config.bloom_bias;
js["bloom_intensity"] = config.bloom_intensity;
js["motion_blur"] = config.motion_blur;
js["exposure"] = config.exposure;
js["gamma"] = config.gamma;
}
bool LoadForwardPipelineAAAConfigFromFile(const char *path, ForwardPipelineAAAConfig &config) {
bool result;
const auto js = LoadJsonFromFile(path, &result);
return result ? LoadForwardPipelineAAAConfig(js, config) : false;
}
bool LoadForwardPipelineAAAConfigFromAssets(const char *name, ForwardPipelineAAAConfig &config) {
bool result;
const auto js = LoadJsonFromAssets(name, &result);
return result ? LoadForwardPipelineAAAConfig(js, config) : false;
}
bool SaveForwardPipelineAAAConfigToFile(const char *path, const ForwardPipelineAAAConfig &config) {
json js;
SaveForwardPipelineAAAConfig(js, config);
return SaveJsonToFile(js, path);
}
//
bool IsValid(const ForwardPipelineAAA &aaa) {
for (auto &tex : aaa.noise) {
if (!bgfx::isValid(tex.handle)) {
return false;
}
}
if (!(bgfx::isValid(aaa.depth.handle) && bgfx::isValid(aaa.attr0.handle) && bgfx::isValid(aaa.attr1.handle))) {
return false;
}
if (!bgfx::isValid(aaa.attributes_fb)) {
return false;
}
if (!(IsValid(aaa.downsample) && IsValid(aaa.upsample) && IsValid(aaa.ssgi) && IsValid(aaa.ssr) && IsValid(aaa.temporal_acc) && IsValid(aaa.hiz) &&
IsValid(aaa.taa) && IsValid(aaa.blur) && IsValid(aaa.motion_blur) && IsValid(aaa.bloom))) {
return false;
}
for (int i = 0; i < 2; i++) {
if (!(bgfx::isValid(aaa.ssgi_history[i].handle) && bgfx::isValid(aaa.ssgi_history_fb[i]) && bgfx::isValid(aaa.ssr_history[i].handle) &&
bgfx::isValid(aaa.ssr_history_fb[i]))) {
return false;
}
}
if (aaa.ssgi_ratio != bgfx::BackbufferRatio::Equal) {
if (!(bgfx::isValid(aaa.ssgi_output.handle) && bgfx::isValid(aaa.ssgi_output_fb))) {
return false;
}
}
if (aaa.ssr_ratio != bgfx::BackbufferRatio::Equal) {
if (!(bgfx::isValid(aaa.ssr_output.handle) && bgfx::isValid(aaa.ssr_output_fb))) {
return false;
}
}
if (!(bgfx::isValid(aaa.work[0].handle) && bgfx::isValid(aaa.work_fb[0]))) {
return false;
}
if (aaa.ssgi_ratio != aaa.ssr_ratio) {
if (!(bgfx::isValid(aaa.work[1].handle) && bgfx::isValid(aaa.work_fb[1]))) {
return false;
}
}
return bgfx::isValid(aaa.frame_hdr.handle) && bgfx::isValid(aaa.frame_hdr_fb) && bgfx::isValid(aaa.work_frame_hdr_fb) &&
bgfx::isValid(aaa.prv_frame_hdr_fb) && bgfx::isValid(aaa.next_frame_hdr_fb) && bgfx::isValid(aaa.u_color) && bgfx::isValid(aaa.u_depth) &&
bgfx::isValid(aaa.compositing_prg);
}
static ForwardPipelineAAA _CreateForwardPipelineAAA(const Reader &ir, const ReadProvider &ip, const char *path, const ForwardPipelineAAAConfig &config,
const RenderBufferResourceFactory &rb_factory, bgfx::BackbufferRatio::Enum ssgi_ratio, bgfx::BackbufferRatio::Enum ssr_ratio) {
ForwardPipelineAAA aaa;
const uint64_t flags = attribute_texture_flags;
for (size_t i = 0; i < aaa.noise.size(); ++i)
aaa.noise[i] = LoadTexture(ir, ip, format("%1/noise/LDR_RGBA_%2.png").arg(path).arg(i), 0);
{
// depth texture
aaa.depth = {flags, rb_factory.create_texture2d(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::D24, flags)};
// w: linear depth, xyz: view normal
aaa.attr0 = {flags, rb_factory.create_texture2d(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
// yz: velocity
aaa.attr1 = {flags, rb_factory.create_texture2d(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
bgfx::TextureHandle texs[] = {aaa.depth.handle, aaa.attr0.handle, aaa.attr1.handle};
aaa.attributes_fb = bgfx::createFrameBuffer(3, texs, true);
}
{
aaa.work[0] = {flags, rb_factory.create_texture2d(ssgi_ratio, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
aaa.work_fb[0] = bgfx::createFrameBuffer(1, &aaa.work[0].handle, true);
if (ssgi_ratio != ssr_ratio) {
aaa.work[1] = {flags, rb_factory.create_texture2d(ssr_ratio, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
aaa.work_fb[1] = bgfx::createFrameBuffer(1, &aaa.work[1].handle, true);
} else {
aaa.work[1] = aaa.work[0];
aaa.work_fb[1] = aaa.work_fb[0];
}
}
{
aaa.ssgi_ratio = ssgi_ratio;
if (ssgi_ratio != bgfx::BackbufferRatio::Equal) {
aaa.ssgi_output = {flags, rb_factory.create_texture2d(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
bgfx::TextureHandle texs[] = {aaa.ssgi_output.handle};
aaa.ssgi_output_fb = bgfx::createFrameBuffer(1, texs, true);
} else {
aaa.ssgi_output_fb = BGFX_INVALID_HANDLE;
aaa.ssgi_output = {};
}
aaa.ssgi = CreateSSGIFromAssets(path);
aaa.ssgi_history[0] = {flags, rb_factory.create_texture2d(aaa.ssgi_ratio, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
aaa.ssgi_history[1] = {flags, rb_factory.create_texture2d(aaa.ssgi_ratio, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
aaa.ssgi_history_fb[0] = bgfx::createFrameBuffer(1, &aaa.ssgi_history[0].handle, true);
aaa.ssgi_history_fb[1] = bgfx::createFrameBuffer(1, &aaa.ssgi_history[1].handle, true);
}
{
aaa.ssr_ratio = ssr_ratio;
if (ssr_ratio != bgfx::BackbufferRatio::Equal) {
aaa.ssr_output = {flags, rb_factory.create_texture2d(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
bgfx::TextureHandle texs[] = {aaa.ssr_output.handle};
aaa.ssr_output_fb = bgfx::createFrameBuffer(1, texs, true);
} else {
aaa.ssr_output_fb = BGFX_INVALID_HANDLE;
aaa.ssr_output = {};
}
aaa.ssr = CreateSSRFromAssets(path);
aaa.ssr_history[0] = {flags, rb_factory.create_texture2d(aaa.ssr_ratio, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
aaa.ssr_history[1] = {flags, rb_factory.create_texture2d(aaa.ssr_ratio, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
aaa.ssr_history_fb[0] = bgfx::createFrameBuffer(1, &aaa.ssr_history[0].handle, true);
aaa.ssr_history_fb[1] = bgfx::createFrameBuffer(1, &aaa.ssr_history[1].handle, true);
}
aaa.blur = CreateAAABlurFromAssets(path);
aaa.hiz = CreateHiZFromAssets(path, rb_factory, hg::Min(ssgi_ratio, ssr_ratio));
aaa.downsample = CreateDownsampleFromAssets(path, rb_factory);
aaa.upsample = CreateUpsampleFromAssets(path);
aaa.temporal_acc = CreateTemporalAccumulationFromAssets(path);
aaa.motion_blur = CreateMotionBlurFromAssets(path);
{
// RGBA16F
aaa.frame_hdr = {flags, rb_factory.create_texture2d(bgfx::BackbufferRatio::Equal, false, 1, bgfx::TextureFormat::RGBA16F, flags)};
bgfx::TextureHandle texs[] = {aaa.depth.handle, aaa.frame_hdr.handle};
aaa.frame_hdr_fb = bgfx::createFrameBuffer(2, texs, false);
aaa.work_frame_hdr_fb = rb_factory.create_framebuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::RGBA16F, flags);
aaa.prv_frame_hdr_fb =
rb_factory.create_framebuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::RGBA16F, flags); // (reprojected) input to SSR/SSGI
aaa.next_frame_hdr_fb = rb_factory.create_framebuffer(bgfx::BackbufferRatio::Equal, bgfx::TextureFormat::RGBA16F, flags); // current frame with SSR/SSGI
}
{
aaa.compositing_prg = LoadProgram(ir, ip, format("%1/shader/compositing").arg(path).c_str());
aaa.u_color = bgfx::createUniform("u_color", bgfx::UniformType::Sampler);
aaa.u_depth = bgfx::createUniform("u_depth", bgfx::UniformType::Sampler);
}
{
aaa.copy_prg = LoadProgram(ir, ip, format("%1/shader/copy").arg(path).c_str());
aaa.u_copyColor = bgfx::createUniform("u_copyColor", bgfx::UniformType::Sampler);
aaa.u_copyDepth = bgfx::createUniform("u_copyDepth", bgfx::UniformType::Sampler);
}
aaa.taa = CreateTAAFromAssets(path);
aaa.dof = CreateDofFromAssets(path);
aaa.bloom = CreateBloomFromAssets(hg::format("%1/shader").arg(path), rb_factory, bgfx::BackbufferRatio::Equal);
if (!IsValid(aaa)) {
DestroyForwardPipelineAAA(aaa);
return aaa;
}
bgfx::setName(aaa.depth.handle, "aaa.depth");
bgfx::setName(aaa.attr0.handle, "aaa.attr0");
bgfx::setName(aaa.attr1.handle, "aaa.attr1");
bgfx::setName(aaa.attributes_fb, "Attributes FB");
bgfx::setName(aaa.work[0].handle, "aaa.work[0]");
bgfx::setName(aaa.work_fb[0], "Work FB #0");
bgfx::setName(aaa.ssgi_history[0].handle, "aaa.ssgi_history_0");
bgfx::setName(aaa.ssgi_history[1].handle, "aaa.ssgi_history_1");
bgfx::setName(aaa.ssr_history[0].handle, "aaa.ssr_history_0");
bgfx::setName(aaa.ssr_history[1].handle, "aaa.ssr_history_1");
bgfx::setName(aaa.frame_hdr_fb, "Frame HDR FB");
bgfx::setName(aaa.work_frame_hdr_fb, "Work HDR frame FB");
bgfx::setName(aaa.prv_frame_hdr_fb, "Previous HDR frame FB");
bgfx::setName(aaa.next_frame_hdr_fb, "Next HDR frame FB");
if (ssgi_ratio != bgfx::BackbufferRatio::Equal)
bgfx::setName(aaa.ssgi_output.handle, "aaa.ssgi_output");
if (ssr_ratio != bgfx::BackbufferRatio::Equal)
bgfx::setName(aaa.ssr_output.handle, "aaa.ssr_output");
if (ssgi_ratio != ssr_ratio) {
bgfx::setName(aaa.work[1].handle, "aaa.work[1]");
bgfx::setName(aaa.work_fb[1], "Work FB #1");
}
return aaa;
}
ForwardPipelineAAA CreateForwardPipelineAAAFromFile(
const char *path, const ForwardPipelineAAAConfig &config, bgfx::BackbufferRatio::Enum ssgi_ratio, bgfx::BackbufferRatio::Enum ssr_ratio) {
auto rb_factory = RenderBufferResourceFactory::Backbuffer();
return _CreateForwardPipelineAAA(g_file_reader, g_file_read_provider, path, config, rb_factory, ssgi_ratio, ssr_ratio);
}
ForwardPipelineAAA CreateForwardPipelineAAAFromAssets(
const char *path, const ForwardPipelineAAAConfig &config, bgfx::BackbufferRatio::Enum ssgi_ratio, bgfx::BackbufferRatio::Enum ssr_ratio) {
auto rb_factory = RenderBufferResourceFactory::Backbuffer();
return _CreateForwardPipelineAAA(g_assets_reader, g_assets_read_provider, path, config, rb_factory, ssgi_ratio, ssr_ratio);
}
ForwardPipelineAAA CreateForwardPipelineAAAFromFile(const char *path, const ForwardPipelineAAAConfig &config, uint16_t rb_width, uint16_t rb_height,
bgfx::BackbufferRatio::Enum ssgi_ratio, bgfx::BackbufferRatio::Enum ssr_ratio) {
auto rb_factory = RenderBufferResourceFactory::Custom(rb_width, rb_height);
return _CreateForwardPipelineAAA(g_file_reader, g_file_read_provider, path, config, rb_factory, ssgi_ratio, ssr_ratio);
}
ForwardPipelineAAA CreateForwardPipelineAAAFromAssets(const char *path, const ForwardPipelineAAAConfig &config, uint16_t rb_width, uint16_t rb_height,
bgfx::BackbufferRatio::Enum ssgi_ratio, bgfx::BackbufferRatio::Enum ssr_ratio) {
auto rb_factory = RenderBufferResourceFactory::Custom(rb_width, rb_height);
return _CreateForwardPipelineAAA(g_assets_reader, g_assets_read_provider, path, config, rb_factory, ssgi_ratio, ssr_ratio);
}
void DestroyForwardPipelineAAA(ForwardPipelineAAA &aaa) {
for (size_t i = 0; i < aaa.noise.size(); ++i)
Destroy(aaa.noise[i]);
//
if (aaa.work_fb[1].idx != aaa.work_fb[0].idx) {
bgfx_Destroy(aaa.work_fb[1]);
}
aaa.work_fb[1] = BGFX_INVALID_HANDLE;
bgfx_Destroy(aaa.work_fb[0])
//
bgfx_Destroy(aaa.attributes_fb); // destroys depth, attr0, attr1
//
bgfx_Destroy(aaa.ssgi_output_fb);
DestroySSGI(aaa.ssgi);
bgfx_Destroy(aaa.ssr_output_fb);
DestroySSR(aaa.ssr);
for (int i = 0; i < 2; i++) {
bgfx_Destroy(aaa.ssgi_history_fb[i]);
bgfx_Destroy(aaa.ssr_history_fb[i]);
}
//
DestroyAAABlur(aaa.blur);
//
#if 0
DestroySAO(aaa.sao);
#endif
DestroyMotionBlur(aaa.motion_blur);
//
Destroy(aaa.frame_hdr);
bgfx_Destroy(aaa.frame_hdr_fb);
bgfx_Destroy(aaa.work_frame_hdr_fb);
bgfx_Destroy(aaa.prv_frame_hdr_fb);
bgfx_Destroy(aaa.next_frame_hdr_fb);
//
bgfx_Destroy(aaa.compositing_prg);
bgfx_Destroy(aaa.u_color);
bgfx_Destroy(aaa.u_depth);
//
bgfx_Destroy(aaa.copy_prg);
bgfx_Destroy(aaa.u_copyColor);
bgfx_Destroy(aaa.u_copyDepth);
//
DestroyTAA(aaa.taa);
DestroyDof(aaa.dof);
DestroyBloom(aaa.bloom);
DestroyHiZ(aaa.hiz);
//
DestroyDownsample(aaa.downsample);
DestroyUpsample(aaa.upsample);
DestroyTemporalAccumulation(aaa.temporal_acc);
}
//
void GetSceneForwardPipelineLights(const Scene &scene, std::vector<ForwardPipelineLight> &out_lights) {
out_lights.clear();
const auto lights = scene.GetLights();
out_lights.reserve(lights.size());
for (const auto &light : lights) {
if (!light.IsEnabled())
continue;
const auto trs = light.GetTransform();
const auto lgt = light.GetLight();
ForwardPipelineLight lgt_;
lgt_.world = scene.GetTransformWorldMatrix(trs.ref.idx);
lgt_.diffuse = lgt.GetDiffuseColor() * lgt.GetDiffuseIntensity();
lgt_.specular = lgt.GetSpecularColor() * lgt.GetSpecularIntensity();
const auto light_type = lgt.GetType();
if (light_type == LT_Linear) {
lgt_.type = FPLT_Linear;
lgt_.pssm_split = lgt.GetPSSMSplit();
lgt_.radius = 0.f;
lgt_.inner_angle = 0.f;
lgt_.outer_angle = 0.f;
} else if (light_type == LT_Spot) {
lgt_.type = FPLT_Spot;
lgt_.pssm_split = Vec4::Zero;
lgt_.radius = lgt.GetRadius();
lgt_.inner_angle = lgt.GetInnerAngle();
lgt_.outer_angle = lgt.GetOuterAngle();
} else { // fall back to point
lgt_.type = FPLT_Point;
lgt_.pssm_split = Vec4::Zero;
lgt_.radius = lgt.GetRadius();
lgt_.inner_angle = 0.f;
lgt_.outer_angle = 0.f;
}
const auto shadow_type = lgt.GetShadowType();
if (shadow_type == LST_Map)
lgt_.shadow_type = FPST_Map;
else
lgt_.shadow_type = FPST_None;
lgt_.priority = lgt.GetPriority();
lgt_.shadow_bias = lgt.GetShadowBias();
out_lights.push_back(lgt_);
}
}
//
std::vector<uint32_t> ComputeModelDisplayListSortKeys(
const Scene &scene, const ViewState &view_state, const std::vector<ModelDisplayList> &dls, const PipelineResources &res) {
std::vector<uint32_t> sort_keys;
sort_keys.reserve(dls.size());
const auto &mtxs = scene.GetTransformWorldMatrices();
for (const auto &dl : dls) {
const auto &mdl_mtx = mtxs[dl.mtx_idx]; // model matrix
const auto &mdl_view_mtx = view_state.view * mdl_mtx; // TODO cache based on dl.mtx_idx
const auto &mdl = res.models.Get_unsafe_(dl.mdl_idx);
#if 0
const auto &dl_center = GetCenter(mdl.bounds[dl.lst_idx]); // display list bounding volume center
const auto &dl_center_in_view = dl_center * mdl_view_mtx;
sort_keys.push_back(uint32_t(dl_center_in_view.z * 1000.f)); // sort to mm precision
#else
const auto &bound = mdl.bounds[dl.lst_idx];
const Vec3 vtx[8] = {
{bound.mn.x, bound.mn.y, bound.mn.z},
{bound.mx.x, bound.mn.y, bound.mn.z},
{bound.mx.x, bound.mx.y, bound.mn.z},
{bound.mn.x, bound.mx.y, bound.mn.z},
{bound.mn.x, bound.mn.y, bound.mx.z},
{bound.mx.x, bound.mn.y, bound.mx.z},
{bound.mx.x, bound.mx.y, bound.mx.z},
{bound.mn.x, bound.mx.y, bound.mx.z},
};
float closest = std::numeric_limits<float>::max();
for (auto &v : vtx) {
const auto &in_view = mdl_view_mtx * v;
if (in_view.z < closest)
closest = in_view.z;
}
if (closest < 0.f)
closest = 0.f;
sort_keys.push_back(ComputeSortKey(closest)); // sort to mm precision
#endif
}
return sort_keys;
}
std::vector<uint32_t> ComputeSkinnedModelDisplayListSortKeys(
const Scene &scene, const ViewState &view_state, const std::vector<SkinnedModelDisplayList> &dls, const PipelineResources &res) {
std::vector<uint32_t> sort_keys;
sort_keys.reserve(dls.size());
const auto &mtxs = scene.GetTransformWorldMatrices();
for (const auto &dl : dls) {
// TODO
sort_keys.push_back(0);
}
return sort_keys;
}
static int ComputeForwardPipelineConfigurationIdx(ForwardPipelineStage pipeline_stage, const ForwardPipelineLights &lights) {
if (pipeline_stage == FPS_AttributeBuffers)
return 0;
if (pipeline_stage == FPS_DepthOnly)
return 9;
int light_config_idx = 0;
if (lights.lights[0].shadow_type == FPST_Map)
light_config_idx |= 0b01;
if (lights.lights[1].shadow_type == FPST_Map)
light_config_idx |= 0b10;
if (pipeline_stage == FPS_Basic)
return light_config_idx + 1;
if (pipeline_stage == FPS_Advanced)
return 4 + light_config_idx + 1;
return -1;
}
//
void PrepareSceneForwardPipelineCommonRenderData(bgfx::ViewId &view_id, const Scene &scene, SceneForwardPipelineRenderData &render_data,
const ForwardPipeline &pipeline, const PipelineResources &resources, SceneForwardPipelinePassViewId &views, const char *debug_name) {
scene.GetModelDisplayLists(
render_data.all_opaque, render_data.all_transparent, render_data.all_opaque_skinned, render_data.all_transparent_skinned, resources);
std::vector<ForwardPipelineLight> lights;
GetSceneForwardPipelineLights(scene, lights);
render_data.pipe_lights = PrepareForwardPipelineLights(lights);
ForwardPipelineShadowPassViewId sp_views;
GenerateSpotShadowMapForForwardPipeline(view_id, render_data.all_opaque, render_data.all_opaque_skinned, scene.GetTransformWorldMatrices(),
render_data.pipe_lights, pipeline, resources, sp_views, render_data.shadow_data, debug_name);
views[FPSP_Slot1Spot] = sp_views[FPSP_Slot1Spot];
}
//
void PrepareSceneForwardPipelineViewDependentRenderData(bgfx::ViewId &view_id, const ViewState &view_state, const Scene &scene,
SceneForwardPipelineRenderData &render_data, const ForwardPipeline &pipeline, const PipelineResources &resources, SceneForwardPipelinePassViewId &views,
const char *debug_name) {
ForwardPipelineShadowPassViewId sp_views;
GenerateLinearShadowMapForForwardPipeline(view_id, view_state, render_data.all_opaque, render_data.all_opaque_skinned, scene.GetTransformWorldMatrices(),
render_data.pipe_lights, pipeline, resources, sp_views, render_data.shadow_data, debug_name);
views[SFPP_Slot0LinearSplit0] = sp_views[FPSP_Slot0LinearSplit0];
views[SFPP_Slot0LinearSplit1] = sp_views[FPSP_Slot0LinearSplit1];
views[SFPP_Slot0LinearSplit2] = sp_views[FPSP_Slot0LinearSplit2];
views[SFPP_Slot0LinearSplit3] = sp_views[FPSP_Slot0LinearSplit3];
render_data.view_opaque = render_data.all_opaque;
CullModelDisplayLists(view_state.frustum, render_data.view_opaque, scene.GetTransformWorldMatrices(), resources);
render_data.view_transparent = render_data.all_transparent;
CullModelDisplayLists(view_state.frustum, render_data.view_transparent, scene.GetTransformWorldMatrices(), resources);
// FIXME cull skinned models !!!
render_data.view_opaque_skinned = render_data.all_opaque_skinned;
render_data.view_transparent_skinned = render_data.all_transparent_skinned;
render_data.fog = GetSceneForwardPipelineFog(scene);
}
//
ForwardPipelineFog GetSceneForwardPipelineFog(const Scene &scene) {
return {scene.environment.fog_near, scene.environment.fog_far, scene.environment.fog_color};
}
//
static iRect ScreenSpaceRect(const iRect &rect, bgfx::BackbufferRatio::Enum ratio) {
if (ratio == bgfx::BackbufferRatio::Half)
return rect / 2;
if (ratio == bgfx::BackbufferRatio::Quarter)
return rect / 4;
if (ratio == bgfx::BackbufferRatio::Eighth)
return rect / 8;
if (ratio == bgfx::BackbufferRatio::Sixteenth)
return rect / 16;
if (ratio == bgfx::BackbufferRatio::Double)
return rect * 2;
return rect;
}
static void UpdateForwardPipelineProbe(ForwardPipeline &pipeline, const Probe &probe, TextureRef brdf_map_ref, const PipelineResources &resources) {
auto &brdf_map = resources.textures.Get(brdf_map_ref);
auto &irradiance_map = resources.textures.Get(probe.irradiance_map);
auto &radiance_map = resources.textures.Get(probe.radiance_map);
Mat4 world;
if (probe.type == PT_Cube)
world = TransformationMat4(probe.trs.pos, probe.trs.rot, probe.trs.scl);
else if (probe.type == PT_Sphere)
world = TransformationMat4(probe.trs.pos, probe.trs.rot, {probe.trs.scl.x, probe.trs.scl.x, probe.trs.scl.x});
UpdateForwardPipelineProbe(pipeline, irradiance_map, radiance_map, brdf_map, probe.type, world, unpack_float(probe.parallax));
}
void SubmitSceneToForwardPipeline(bgfx::ViewId &view_id, const Scene &scene, const Rect<int> &rect, const ViewState &view_state, ForwardPipeline &pipeline,
const SceneForwardPipelineRenderData &render_data, const PipelineResources &resources, SceneForwardPipelinePassViewId &views, ForwardPipelineAAA &aaa,
const ForwardPipelineAAAConfig &aaa_config, int frame, uint16_t rb_width, uint16_t rb_height, bgfx::FrameBufferHandle fb, const char *debug_name) {
__ASSERT__(bgfx::getCaps()->supported & BGFX_CAPS_TEXTURE_BLIT);
hg::iVec2 fb_size(rb_width, rb_width);
if (fb_size.x <= 0 || fb_size.y <= 0) {
const bgfx::Stats *stats = bgfx::getStats();
fb_size.x = stats->width;
fb_size.y = stats->height;
}
// reset pass views
std::fill(std::begin(views), std::end(views), 65535);
// update pipeline
UpdateForwardPipeline(pipeline, render_data.shadow_data, scene.environment.ambient, render_data.pipe_lights, render_data.fog, fb_size);
UpdateForwardPipelineAAA(pipeline, rect, view_state.view, view_state.proj, aaa.prv_view_state.view, aaa.prv_view_state.proj, TAAHaltonJitter8(frame),
aaa.ssgi_ratio, aaa.ssr_ratio, aaa_config.temporal_aa_weight, aaa_config.motion_blur, aaa_config.exposure, aaa_config.gamma, aaa_config.sample_count,
aaa_config.max_distance, aaa_config.specular_weight, aaa_config.sharpen); // [todo] ssgi_ratio/ssr_ratio ([EJ] what is wrong with ssgi_ratio/ssr_ratio)
UpdateForwardPipelineProbe(pipeline, scene.environment.probe, scene.environment.brdf_map, resources);
// TAA jittered projection matrix
const auto jitter = TAAHaltonJitter8(frame) / Vec2(float(GetWidth(rect)), float(GetHeight(rect)));
auto proj_jittered = to_bgfx(view_state.proj);
proj_jittered[8] += jitter.x;
proj_jittered[9] += jitter.y;
// fill attribute buffers (linear depth/normal/velocity)
{
bgfx::touch(view_id);
bgfx::setViewName(view_id, format("Attribute buffers: %1").arg(debug_name).c_str());
bgfx::setViewRect(view_id, rect.sx, rect.sy, GetWidth(rect), GetHeight(rect));
bgfx::setViewFrameBuffer(view_id, aaa.attributes_fb);
bgfx::setViewClear(view_id, BGFX_CLEAR_DEPTH | BGFX_CLEAR_COLOR, 0, 1.f, 0);
bgfx::setViewMode(bgfx::ViewMode::Default);
bgfx::setViewTransform(view_id, to_bgfx(view_state.view).data(), proj_jittered.data());
const int pipeline_config_idx = ComputeForwardPipelineConfigurationIdx(FPS_AttributeBuffers, render_data.pipe_lights);
DrawModelDisplayLists(view_id, render_data.view_opaque, pipeline_config_idx, pipeline.uniform_values, pipeline.uniform_textures,
scene.GetTransformWorldMatrices(), scene.GetPreviousTransformWorldMatrices(), resources);
DrawSkinnedModelDisplayLists(view_id, render_data.view_opaque_skinned, pipeline_config_idx, pipeline.uniform_values, pipeline.uniform_textures,
scene.GetTransformWorldMatrices(), scene.GetPreviousTransformWorldMatrices(), resources);
views[SFPP_DepthPrepass] = view_id++;
}
// animated blue noise texture
const Texture &noise = aaa.noise[frame % aaa.noise.size()];
UpdateForwardPipelineNoise(pipeline, noise);
// Downsample
if ((aaa.ssgi_ratio != bgfx::BackbufferRatio::Equal) || (aaa.ssr_ratio != bgfx::BackbufferRatio::Equal)) {
ComputeDownsample(view_id, ScreenSpaceRect(rect, bgfx::BackbufferRatio::Half), {attribute_texture_flags, bgfx::getTexture(aaa.prv_frame_hdr_fb)},
aaa.attr0, aaa.depth, aaa.downsample);
}
// HiZ
{
if ((aaa.ssgi_ratio != bgfx::BackbufferRatio::Equal) && (aaa.ssr_ratio != bgfx::BackbufferRatio::Equal)) {
ComputeHiZ(
view_id, fb_size, ScreenSpaceRect(rect, bgfx::BackbufferRatio::Half), view_state.proj, aaa_config.z_thickness, aaa.downsample.attr0, aaa.hiz);
} else {
ComputeHiZ(view_id, fb_size, rect, view_state.proj, aaa_config.z_thickness, aaa.attr0, aaa.hiz);
}
}
int current = frame & 1;
int previous = current ^ 1;
Texture ssgi_output;
Texture ssr_output;
// SSGI
{
auto &probe_map = resources.textures.Get(scene.environment.probe.irradiance_map);
if (aaa.ssgi_ratio != bgfx::BackbufferRatio::Equal) {
ComputeSSGI(view_id, ScreenSpaceRect(rect, aaa.ssgi_ratio), aaa.ssgi_ratio, aaa.downsample.color, aaa.downsample.attr0,
aaa.attr1, // [todo] downsample attr1 ?!
probe_map, noise, aaa.hiz, aaa.work_fb[0], aaa.ssgi);
ComputeTemporalAccumulation(view_id, ScreenSpaceRect(rect, aaa.ssgi_ratio), aaa.work[0], aaa.ssgi_history[previous], aaa.attr1,
aaa.ssgi_history_fb[current], aaa.temporal_acc);
ComputeAAABlur(view_id, ScreenSpaceRect(rect, aaa.ssgi_ratio), aaa.downsample.attr0, aaa.ssgi_history_fb[current], aaa.work_fb[0], aaa.blur);
ComputeUpsample(view_id, rect, aaa.ssgi_history[current], aaa.downsample.attr0, aaa.attr0, aaa.ssgi_output_fb, aaa.upsample);
ssgi_output = aaa.ssgi_output;
} else {
ComputeSSGI(view_id, rect, aaa.ssgi_ratio, {attribute_texture_flags, bgfx::getTexture(aaa.prv_frame_hdr_fb)}, aaa.attr0, aaa.attr1, probe_map,
noise, aaa.hiz, aaa.work_fb[0], aaa.ssgi);
ComputeTemporalAccumulation(view_id, rect, aaa.work[0], aaa.ssgi_history[previous], aaa.attr1, aaa.ssgi_history_fb[current], aaa.temporal_acc);
ComputeAAABlur(view_id, ScreenSpaceRect(rect, aaa.ssgi_ratio), aaa.attr0, aaa.ssgi_history_fb[current], aaa.work_fb[0], aaa.blur);
ssgi_output = aaa.ssgi_history[current];
}
}
// SSR
{
auto &probe_map = resources.textures.Get(scene.environment.probe.radiance_map);
if (aaa.ssr_ratio != bgfx::BackbufferRatio::Equal) {
ComputeSSR(view_id, ScreenSpaceRect(rect, aaa.ssr_ratio), aaa.ssr_ratio, aaa.downsample.color, aaa.downsample.attr0,
aaa.attr1, // [todo] downsample attr1 ?!
probe_map, noise, aaa.hiz, aaa.work_fb[1], aaa.ssr);
ComputeTemporalAccumulation(view_id, ScreenSpaceRect(rect, aaa.ssr_ratio), aaa.work[1], aaa.ssr_history[previous], aaa.attr1,
aaa.ssr_history_fb[current], aaa.temporal_acc);
ComputeUpsample(view_id, rect, aaa.ssr_history[current], aaa.downsample.attr0, aaa.attr0, aaa.ssr_output_fb, aaa.upsample);
ssr_output = aaa.ssr_output;
} else {
ComputeSSR(view_id, rect, aaa.ssr_ratio, {attribute_texture_flags, bgfx::getTexture(aaa.prv_frame_hdr_fb)}, aaa.attr0, aaa.attr1, probe_map, noise,
aaa.hiz, aaa.work_fb[1], aaa.ssr);
ComputeTemporalAccumulation(view_id, rect, aaa.work[1], aaa.ssr_history[previous], aaa.attr1, aaa.ssr_history_fb[current], aaa.temporal_acc);
ssr_output = aaa.ssr_history[current];
}
}
#if 0
// SAO [todo] move to forward pipeline
{
ComputeSAO(view_id, ScreenSpaceRect(rect, aaa.ssgi_ratio), aaa.attr0, aaa.attr1, noise, aaa.sao_output_fb, aaa.sao, view_state.proj, aaa.sao_bias, // [todo] aaa.ssgi_ratio : add ratio to SAO struct
aaa.sao_radius,
aaa.sao_sample_count, aaa.sao_sharpness);
UpdateForwardPipelineAO(pipeline, aaa.sao_output);
}
#endif
// setup environment for AAA pipeline
UpdateForwardPipelineAAA(pipeline, ssgi_output, ssr_output);
// opaque pass
{
bgfx::touch(view_id);
bgfx::setViewName(view_id, format("Opaque pass: %1").arg(debug_name).c_str());
bgfx::setViewRect(view_id, rect.sx, rect.sy, GetWidth(rect), GetHeight(rect));
bgfx::setViewFrameBuffer(view_id, aaa.frame_hdr_fb);
if (scene.canvas.clear_z || scene.canvas.clear_color) {
const uint16_t flags = (scene.canvas.clear_z ? BGFX_CLEAR_DEPTH : 0) | (scene.canvas.clear_color ? BGFX_CLEAR_COLOR : 0);
const uint32_t color = ColorToABGR32(scene.canvas.color);
bgfx::setViewClear(view_id, flags, color, 1.f, 0);
} else {
bgfx::setViewClear(view_id, BGFX_CLEAR_NONE, 0, 1.f, UINT8_MAX);
}
bgfx::setViewMode(bgfx::ViewMode::Default);
bgfx::setViewTransform(view_id, to_bgfx(view_state.view).data(), proj_jittered.data());
const int pipeline_config_idx = ComputeForwardPipelineConfigurationIdx(FPS_Advanced, render_data.pipe_lights);
DrawModelDisplayLists(view_id, render_data.view_opaque, pipeline_config_idx, pipeline.uniform_values, pipeline.uniform_textures,
scene.GetTransformWorldMatrices(), resources);
DrawSkinnedModelDisplayLists(view_id, render_data.view_opaque_skinned, pipeline_config_idx, pipeline.uniform_values, pipeline.uniform_textures,
scene.GetTransformWorldMatrices(), resources);
views[SFPP_Opaque] = view_id++;
}
// setup environment for non AAA pipeline
// UpdateForwardPipelineProbe(pipeline, scene.environment.probe, scene.environment.brdf_map, resources);
// transparent pass
{
bgfx::touch(view_id);
bgfx::setViewName(view_id, format("Transparent pass: %1").arg(debug_name).c_str());
bgfx::setViewRect(view_id, rect.sx, rect.sy, GetWidth(rect), GetHeight(rect));
bgfx::setViewFrameBuffer(view_id, aaa.frame_hdr_fb);
bgfx::setViewClear(view_id, BGFX_CLEAR_NONE, 0, 1.f, UINT8_MAX);
bgfx::setViewMode(view_id, bgfx::ViewMode::DepthDescending);
bgfx::setViewTransform(view_id, to_bgfx(view_state.view).data(), proj_jittered.data());
const int pipeline_config_idx = ComputeForwardPipelineConfigurationIdx(FPS_Basic, render_data.pipe_lights);
const auto view_transparent_sort_keys = ComputeModelDisplayListSortKeys(scene, view_state, render_data.view_transparent, resources);
DrawModelDisplayLists(view_id, render_data.view_transparent, view_transparent_sort_keys, pipeline_config_idx, pipeline.uniform_values,
pipeline.uniform_textures, scene.GetTransformWorldMatrices(), resources);
const auto view_transparent_skinned_sort_keys =
ComputeSkinnedModelDisplayListSortKeys(scene, view_state, render_data.view_transparent_skinned, resources);
DrawSkinnedModelDisplayLists(view_id, render_data.view_transparent_skinned, view_transparent_skinned_sort_keys, pipeline_config_idx,
pipeline.uniform_values, pipeline.uniform_textures, scene.GetTransformWorldMatrices(), resources);
views[SFPP_Transparent] = view_id++;
}
// TAA
ApplyTAA(
view_id, rect, aaa.frame_hdr, {attribute_texture_flags, bgfx::getTexture(aaa.prv_frame_hdr_fb)}, aaa.attr0, aaa.attr1, aaa.next_frame_hdr_fb, aaa.taa);
// motion blur
ApplyMotionBlur(
view_id, rect, {attribute_texture_flags, bgfx::getTexture(aaa.next_frame_hdr_fb)}, aaa.attr0, aaa.attr1, noise, aaa.work_frame_hdr_fb, aaa.motion_blur);
// bloom
if (aaa_config.dof_focus_length == 0.f) { // TODO proper ping-pong, bloom should be optional as well...
ApplyBloom(view_id, rect, {attribute_texture_flags, bgfx::getTexture(aaa.work_frame_hdr_fb)}, fb_size, aaa.frame_hdr_fb, aaa.bloom,
aaa_config.bloom_threshold, aaa_config.bloom_bias, aaa_config.bloom_intensity);
} else {
ApplyBloom(view_id, rect, {attribute_texture_flags, bgfx::getTexture(aaa.work_frame_hdr_fb)}, fb_size, aaa.next_frame_hdr_fb, aaa.bloom,
aaa_config.bloom_threshold, aaa_config.bloom_bias, aaa_config.bloom_intensity);
// dof
ApplyDof(view_id, rect, bgfx::BackbufferRatio::Equal, {attribute_texture_flags, bgfx::getTexture(aaa.next_frame_hdr_fb)}, aaa.attr0, aaa.frame_hdr_fb, aaa.dof, aaa_config.dof_focus_point, aaa_config.dof_focus_length);
}
// final compositing for presentation (exposure/gamma correction)
if (aaa_config.use_tonemapping) {
if (bgfx::isValid(fb))
bgfx::setViewName(view_id, "Final compositing to target framebuffer");
else
bgfx::setViewName(view_id, "Final compositing to back buffer");
bgfx::setViewRect(view_id, 0, 0, fb_size.x, fb_size.y);
bgfx::setViewFrameBuffer(view_id, fb);
bgfx::setViewClear(view_id, BGFX_CLEAR_NONE, 0, 1.f, UINT8_MAX);
bgfx::setViewTransform(view_id, nullptr, nullptr);
if (aaa_config.debug_buffer == FPAAADB_None)
bgfx::setTexture(0, aaa.u_color, aaa.frame_hdr.handle, uint32_t(attribute_texture_flags));
else if (aaa_config.debug_buffer == FPAAADB_SSGI)
bgfx::setTexture(0, aaa.u_color, ssgi_output.handle, uint32_t(attribute_texture_flags));
else if (aaa_config.debug_buffer == FPAAADB_SSR)
bgfx::setTexture(0, aaa.u_color, ssr_output.handle, uint32_t(attribute_texture_flags));
bgfx::setTexture(1, aaa.u_depth, aaa.depth.handle, uint32_t(aaa.depth.flags));
bgfx::VertexLayout decl;
decl.begin().add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float).add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float).end();
const float k_y = bgfx::getCaps()->originBottomLeft ? 0.f : 1.f;
Vertices vtx(decl, 4);
vtx.Begin(0).SetPos({-1, -1, 0}).SetTexCoord0({0, k_y}).End();
vtx.Begin(1).SetPos({1, -1, 0}).SetTexCoord0({1, k_y}).End();
vtx.Begin(2).SetPos({1, 1, 0}).SetTexCoord0({1, 1.f - k_y}).End();
vtx.Begin(3).SetPos({-1, 1, 0}).SetTexCoord0({0, 1.f - k_y}).End();
DrawTriangles(view_id, {0, 1, 2, 0, 2, 3}, vtx, aaa.compositing_prg, {}, {}, ComputeRenderState(BM_Opaque, DT_Always));
++view_id;
} else {
bgfx::setViewName(view_id, "Copying to back buffer");
bgfx::setViewRect(view_id, 0, 0, fb_size.x, fb_size.y);
bgfx::setViewFrameBuffer(view_id, fb);
bgfx::setViewClear(view_id, BGFX_CLEAR_NONE, 0, 1.f);
bgfx::setViewTransform(view_id, nullptr, nullptr);
bgfx::setTexture(0, aaa.u_copyColor, aaa.frame_hdr.handle, BGFX_SAMPLER_U_CLAMP | BGFX_SAMPLER_V_CLAMP);
bgfx::setTexture(1, aaa.u_copyDepth, aaa.depth.handle, uint32_t(aaa.depth.flags));
bgfx::VertexLayout decl;
decl.begin().add(bgfx::Attrib::Position, 3, bgfx::AttribType::Float).add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float).end();
const float k_y = bgfx::getCaps()->originBottomLeft ? 0.f : 1.f;
Vertices vtx(decl, 4);
vtx.Begin(0).SetPos({-1, -1, 0}).SetTexCoord0({0, k_y}).End();
vtx.Begin(1).SetPos({1, -1, 0}).SetTexCoord0({1, k_y}).End();
vtx.Begin(2).SetPos({1, 1, 0}).SetTexCoord0({1, 1.f - k_y}).End();
vtx.Begin(3).SetPos({-1, 1, 0}).SetTexCoord0({0, 1.f - k_y}).End();
DrawTriangles(view_id, {0, 1, 2, 0, 2, 3}, vtx, aaa.copy_prg, {}, {}, ComputeRenderState(BM_Opaque, DT_Always));
++view_id;
}
}
void SubmitSceneToForwardPipeline(bgfx::ViewId &view_id, const Scene &scene, const Rect<int> &rect, const ViewState &view_state, ForwardPipeline &pipeline,
const SceneForwardPipelineRenderData &render_data, const PipelineResources &resources, SceneForwardPipelinePassViewId &views, ForwardPipelineAAA &aaa,
const ForwardPipelineAAAConfig &aaa_config, int frame, bgfx::FrameBufferHandle fb, const char *debug_name) {
SubmitSceneToForwardPipeline(view_id, scene, rect, view_state, pipeline, render_data, resources, views, aaa, aaa_config, frame, 0, 0, fb, debug_name);
}
// basic rendering path
void SubmitSceneToForwardPipeline(bgfx::ViewId &view_id, const Scene &scene, const Rect<int> &rect, const ViewState &view_state, ForwardPipeline &pipeline,
const SceneForwardPipelineRenderData &render_data, const PipelineResources &resources, SceneForwardPipelinePassViewId &views, bgfx::FrameBufferHandle fb,
const char *debug_name) {
std::fill(std::begin(views), std::end(views), 65535);
// update pipeline
UpdateForwardPipeline(
pipeline, render_data.shadow_data, scene.environment.ambient, render_data.pipe_lights, render_data.fog, hg::iVec2(GetWidth(rect), GetHeight(rect)));
// UpdateForwardPipelineAAA(pipeline, rect, view_state.view, view_state.proj, view_state.view, view_state.proj, {});
UpdateForwardPipelineProbe(pipeline, scene.environment.probe, scene.environment.brdf_map, resources);
const int pipeline_config_idx = ComputeForwardPipelineConfigurationIdx(FPS_Basic, render_data.pipe_lights);
// opaque pass
{
bgfx::touch(view_id);
bgfx::setViewName(view_id, format("Opaque pass: %1").arg(debug_name).c_str());
bgfx::setViewRect(view_id, rect.sx, rect.sy, GetWidth(rect), GetHeight(rect));
bgfx::setViewFrameBuffer(view_id, fb);
if (scene.canvas.clear_z || scene.canvas.clear_color) {
const uint16_t flags = (scene.canvas.clear_z ? BGFX_CLEAR_DEPTH : 0) | (scene.canvas.clear_color ? BGFX_CLEAR_COLOR : 0);
const uint32_t color = ColorToABGR32(scene.canvas.color);
bgfx::setViewClear(view_id, flags, color, 1.f, 0);
} else {
bgfx::setViewClear(view_id, BGFX_CLEAR_NONE, 0, 1.f, UINT8_MAX);
}
bgfx::setViewMode(bgfx::ViewMode::Default);
bgfx::setViewTransform(view_id, to_bgfx(view_state.view).data(), to_bgfx(view_state.proj).data());
DrawModelDisplayLists(view_id, render_data.view_opaque, pipeline_config_idx, pipeline.uniform_values, pipeline.uniform_textures,
scene.GetTransformWorldMatrices(), resources);
DrawSkinnedModelDisplayLists(view_id, render_data.view_opaque_skinned, pipeline_config_idx, pipeline.uniform_values, pipeline.uniform_textures,
scene.GetTransformWorldMatrices(), resources);
views[SFPP_Opaque] = view_id++;
}
// transparent pass
{
bgfx::touch(view_id);
bgfx::setViewName(view_id, format("Transparent pass: %1").arg(debug_name).c_str());
bgfx::setViewRect(view_id, rect.sx, rect.sy, GetWidth(rect), GetHeight(rect));
bgfx::setViewFrameBuffer(view_id, fb);
bgfx::setViewClear(view_id, BGFX_CLEAR_NONE, 0, 1.f, UINT8_MAX);
bgfx::setViewMode(view_id, bgfx::ViewMode::DepthDescending);
bgfx::setViewTransform(view_id, to_bgfx(view_state.view).data(), to_bgfx(view_state.proj).data());
const auto view_transparent_sort_keys = ComputeModelDisplayListSortKeys(scene, view_state, render_data.view_transparent, resources);
DrawModelDisplayLists(view_id, render_data.view_transparent, view_transparent_sort_keys, pipeline_config_idx, pipeline.uniform_values,
pipeline.uniform_textures, scene.GetTransformWorldMatrices(), resources);
const auto view_transparent_skinned_sort_keys =
ComputeSkinnedModelDisplayListSortKeys(scene, view_state, render_data.view_transparent_skinned, resources);
DrawSkinnedModelDisplayLists(view_id, render_data.view_transparent_skinned, view_transparent_skinned_sort_keys, pipeline_config_idx,
pipeline.uniform_values, pipeline.uniform_textures, scene.GetTransformWorldMatrices(), resources);
views[SFPP_Transparent] = view_id++;
}
}
//
void SubmitSceneToPipeline(bgfx::ViewId &view_id, const Scene &scene, const Rect<int> &rect, const ViewState &view_state, ForwardPipeline &pipeline,
const PipelineResources &resources, SceneForwardPipelinePassViewId &views, bgfx::FrameBufferHandle fb, const char *debug_name) {
SceneForwardPipelineRenderData render_data;
PrepareSceneForwardPipelineCommonRenderData(view_id, scene, render_data, pipeline, resources, views, debug_name);
PrepareSceneForwardPipelineViewDependentRenderData(view_id, view_state, scene, render_data, pipeline, resources, views, debug_name);
SubmitSceneToForwardPipeline(view_id, scene, rect, view_state, pipeline, render_data, resources, views, fb, debug_name);
}
void SubmitSceneToPipeline(bgfx::ViewId &view_id, const Scene &scene, const Rect<int> &rect, bool fov_axis_is_horizontal, ForwardPipeline &pipeline,
const PipelineResources &resources, SceneForwardPipelinePassViewId &views, bgfx::FrameBufferHandle fb, const char *debug_name) {
const auto w = float(GetWidth(rect)), h = float(GetHeight(rect));
const auto ar = fov_axis_is_horizontal ? ComputeAspectRatioX(w, h) : ComputeAspectRatioY(w, h);
const auto view_state = scene.ComputeCurrentCameraViewState(ar);
SubmitSceneToPipeline(view_id, scene, rect, view_state, pipeline, resources, views, fb, debug_name);
}
//
void SubmitSceneToPipeline(bgfx::ViewId &view_id, const Scene &scene, const Rect<int> &rect, const ViewState &view_state, ForwardPipeline &pipeline,
const PipelineResources &resources, SceneForwardPipelinePassViewId &views, ForwardPipelineAAA &aaa, const ForwardPipelineAAAConfig &aaa_config, int frame,
bgfx::FrameBufferHandle fb, const char *debug_name) {
SceneForwardPipelineRenderData render_data;
PrepareSceneForwardPipelineCommonRenderData(view_id, scene, render_data, pipeline, resources, views, debug_name);
PrepareSceneForwardPipelineViewDependentRenderData(view_id, view_state, scene, render_data, pipeline, resources, views, debug_name);
SubmitSceneToForwardPipeline(view_id, scene, rect, view_state, pipeline, render_data, resources, views, aaa, aaa_config, frame, fb, debug_name);
aaa.Flip(view_state);
}
void SubmitSceneToPipeline(bgfx::ViewId &view_id, const Scene &scene, const Rect<int> &rect, bool fov_axis_is_horizontal, ForwardPipeline &pipeline,
const PipelineResources &resources, SceneForwardPipelinePassViewId &views, ForwardPipelineAAA &aaa, const ForwardPipelineAAAConfig &aaa_config, int frame,
bgfx::FrameBufferHandle fb, const char *debug_name) {
const auto w = float(GetWidth(rect)), h = float(GetHeight(rect));
const auto ar = fov_axis_is_horizontal ? ComputeAspectRatioX(w, h) : ComputeAspectRatioY(w, h);
const auto view_state = scene.ComputeCurrentCameraViewState(ar);
SubmitSceneToPipeline(view_id, scene, rect, view_state, pipeline, resources, views, aaa, aaa_config, frame, fb, debug_name);
}
} // namespace hg