2020-08-11 12:07:21 -04:00
|
|
|
#include "renderer.hpp"
|
|
|
|
|
|
|
|
#include <array>
|
|
|
|
|
|
|
|
#include "gfx_commandbuffer.hpp"
|
|
|
|
#include "math.hpp"
|
|
|
|
#include "screen.hpp"
|
|
|
|
#include "file.hpp"
|
|
|
|
#include "scene.hpp"
|
|
|
|
#include "font.hpp"
|
|
|
|
#include "vector.hpp"
|
|
|
|
#include "engine.hpp"
|
|
|
|
#include "imguipass.hpp"
|
|
|
|
#include "gfx.hpp"
|
|
|
|
#include "log.hpp"
|
|
|
|
#include "pass.hpp"
|
|
|
|
#include "shadowpass.hpp"
|
|
|
|
#include "smaapass.hpp"
|
|
|
|
#include "scenecapture.hpp"
|
2020-08-15 20:09:16 -04:00
|
|
|
#include "materialcompiler.hpp"
|
2020-08-11 12:07:21 -04:00
|
|
|
#include "assertions.hpp"
|
|
|
|
#include "dofpass.hpp"
|
|
|
|
#include "frustum.hpp"
|
2020-08-15 20:09:16 -04:00
|
|
|
#include "shadercompiler.hpp"
|
2020-09-20 23:31:03 -04:00
|
|
|
#include "asset.hpp"
|
2021-02-16 17:10:37 -05:00
|
|
|
#include "debug.hpp"
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
struct ElementInstance {
|
|
|
|
Vector4 color;
|
|
|
|
uint32_t position = 0, size = 0;
|
|
|
|
uint32_t padding[2];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct GlyphInstance {
|
|
|
|
uint32_t position = 0, index = 0, instance = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct GylphMetric {
|
|
|
|
uint32_t x0_y0, x1_y1;
|
|
|
|
float xoff, yoff;
|
|
|
|
float xoff2, yoff2;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct StringInstance {
|
|
|
|
uint32_t xy;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SceneMaterial {
|
|
|
|
Vector4 color, info;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SceneLight {
|
|
|
|
Vector4 positionType;
|
|
|
|
Vector4 directionPower;
|
|
|
|
Vector4 colorSize;
|
|
|
|
Vector4 shadowsEnable;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SceneProbe {
|
|
|
|
Vector4 position, size;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SceneInformation {
|
|
|
|
Vector4 options;
|
|
|
|
Vector4 camPos;
|
|
|
|
Matrix4x4 vp, lightspace;
|
|
|
|
Matrix4x4 spotLightSpaces[max_spot_shadows];
|
|
|
|
SceneMaterial materials[max_scene_materials];
|
|
|
|
SceneLight lights[max_scene_lights];
|
|
|
|
SceneProbe probes[max_environment_probes];
|
|
|
|
int numLights;
|
|
|
|
int p[3];
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PostPushConstants {
|
2020-09-22 15:25:06 -04:00
|
|
|
Vector4 viewport, options, transform_ops;
|
2020-08-11 12:07:21 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct UIPushConstant {
|
|
|
|
Vector2 screenSize;
|
|
|
|
Matrix4x4 mvp;
|
|
|
|
};
|
|
|
|
|
2021-02-03 09:04:30 -05:00
|
|
|
struct SkyPushConstant {
|
|
|
|
Matrix4x4 view;
|
|
|
|
Vector4 sun_position_fov;
|
|
|
|
float aspect;
|
|
|
|
};
|
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
Renderer::Renderer(GFX* gfx, const bool enable_imgui) : gfx(gfx) {
|
|
|
|
Expects(gfx != nullptr);
|
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
shader_compiler.set_include_path(file::get_domain_path(file::Domain::Internal).string());
|
2021-04-20 13:25:59 -04:00
|
|
|
|
|
|
|
create_dummy_texture();
|
2020-09-22 15:39:20 -04:00
|
|
|
create_histogram_resources();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
shadow_pass = std::make_unique<ShadowPass>(gfx);
|
|
|
|
scene_capture = std::make_unique<SceneCapture>(gfx);
|
2021-04-20 13:25:59 -04:00
|
|
|
smaa_pass = std::make_unique<SMAAPass>(gfx, this);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
if(enable_imgui)
|
|
|
|
addPass<ImGuiPass>();
|
2021-04-19 11:40:10 -04:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
generate_brdf();
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
GFXRenderPassCreateInfo renderPassInfo = {};
|
|
|
|
renderPassInfo.label = "Offscreen";
|
|
|
|
renderPassInfo.attachments.push_back(GFXPixelFormat::RGBA_32F);
|
|
|
|
renderPassInfo.attachments.push_back(GFXPixelFormat::DEPTH_32F);
|
|
|
|
renderPassInfo.will_use_in_shader = true;
|
|
|
|
|
|
|
|
offscreenRenderPass = gfx->create_render_pass(renderPassInfo);
|
2021-04-19 11:40:10 -04:00
|
|
|
|
2021-04-19 23:39:34 -04:00
|
|
|
renderPassInfo.label = "Offscreen (UNORM)";
|
|
|
|
renderPassInfo.attachments = {GFXPixelFormat::R8G8B8A8_UNORM};
|
|
|
|
|
|
|
|
unormRenderPass = gfx->create_render_pass(renderPassInfo);
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
create_font_texture();
|
|
|
|
create_sky_pipeline();
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
Renderer::~Renderer() = default;
|
2020-09-21 09:37:52 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
RenderTarget* Renderer::allocate_render_target(const prism::Extent extent) {
|
2021-02-24 14:18:51 -05:00
|
|
|
auto target = new RenderTarget();
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
resize_render_target(*target, extent);
|
|
|
|
|
2021-02-24 14:18:51 -05:00
|
|
|
render_targets.push_back(target);
|
2021-02-17 00:15:59 -05:00
|
|
|
|
2021-02-24 14:18:51 -05:00
|
|
|
return target;
|
2021-02-16 19:22:32 -05:00
|
|
|
}
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
void Renderer::resize_render_target(RenderTarget& target, const prism::Extent extent) {
|
|
|
|
target.extent = extent;
|
2021-02-17 00:15:59 -05:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
create_render_target_resources(target);
|
2021-04-20 13:25:59 -04:00
|
|
|
smaa_pass->create_render_target_resources(target);
|
|
|
|
create_post_pipelines();
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
|
|
|
pipelineInfo.label = "Text";
|
|
|
|
|
|
|
|
pipelineInfo.shaders.vertex_src = file::Path("text.vert");
|
|
|
|
pipelineInfo.shaders.fragment_src = file::Path("text.frag");
|
|
|
|
|
|
|
|
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
|
|
|
|
|
|
|
pipelineInfo.blending.enable_blending = true;
|
|
|
|
pipelineInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha;
|
|
|
|
pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcColor;
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.bindings = {
|
|
|
|
{4, GFXBindingType::PushConstant},
|
|
|
|
{0, GFXBindingType::StorageBuffer},
|
|
|
|
{1, GFXBindingType::StorageBuffer},
|
|
|
|
{2, GFXBindingType::StorageBuffer},
|
|
|
|
{3, GFXBindingType::Texture}
|
|
|
|
};
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.push_constants = {
|
|
|
|
{sizeof(UIPushConstant), 0}
|
|
|
|
};
|
2021-04-20 13:25:59 -04:00
|
|
|
|
|
|
|
text_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2021-02-16 19:22:32 -05:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
if(world_text_pipeline == nullptr) {
|
2021-02-16 19:22:32 -05:00
|
|
|
pipelineInfo.render_pass = offscreenRenderPass;
|
|
|
|
pipelineInfo.label = "Text World";
|
|
|
|
pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual;
|
2021-04-20 13:25:59 -04:00
|
|
|
|
|
|
|
world_text_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
2021-04-19 11:40:10 -04:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
create_ui_pipelines();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
for(auto& pass : passes)
|
2021-02-17 01:32:46 -05:00
|
|
|
pass->create_render_target_resources(target);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
void Renderer::recreate_all_render_targets() {
|
2020-09-22 22:10:02 -04:00
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::set_screen(ui::Screen* screen) {
|
|
|
|
Expects(screen != nullptr);
|
|
|
|
|
|
|
|
current_screen = screen;
|
|
|
|
|
|
|
|
init_screen(screen);
|
|
|
|
|
|
|
|
update_screen();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::init_screen(ui::Screen* screen) {
|
|
|
|
Expects(screen != nullptr);
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
std::array<GylphMetric, numGlyphs> metrics = {};
|
2020-08-11 12:07:21 -04:00
|
|
|
for(int i = 0; i < numGlyphs; i++) {
|
|
|
|
GylphMetric& metric = metrics[i];
|
|
|
|
metric.x0_y0 = utility::pack_u32(font.sizes[fontSize][i].x0, font.sizes[fontSize][i].y0);
|
|
|
|
metric.x1_y1 = utility::pack_u32(font.sizes[fontSize][i].x1, font.sizes[fontSize][i].y1);
|
|
|
|
metric.xoff = font.sizes[fontSize][i].xoff;
|
|
|
|
metric.yoff = font.sizes[fontSize][i].yoff;
|
|
|
|
metric.xoff2 = font.sizes[fontSize][i].xoff2;
|
|
|
|
metric.yoff2 = font.sizes[fontSize][i].yoff2;
|
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
screen->glyph_buffer = gfx->create_buffer(nullptr, instance_alignment + (sizeof(GylphMetric) * numGlyphs), false, GFXBufferUsage::Storage);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
gfx->copy_buffer(screen->glyph_buffer, metrics.data(), instance_alignment, sizeof(GylphMetric) * numGlyphs);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
screen->elements_buffer = gfx->create_buffer(nullptr, sizeof(ElementInstance) * 50, true, GFXBufferUsage::Storage);
|
|
|
|
|
|
|
|
screen->instance_buffer = gfx->create_buffer(nullptr, sizeof(StringInstance) * 50, true, GFXBufferUsage::Storage);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::update_screen() {
|
|
|
|
if(current_screen != nullptr) {
|
|
|
|
for(auto& element : current_screen->elements) {
|
|
|
|
if(!element.background.image.empty())
|
|
|
|
element.background.texture = assetm->get<Texture>(file::app_domain / element.background.image);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
void Renderer::render(GFXCommandBuffer* commandbuffer, Scene* scene, RenderTarget& target, int index) {
|
|
|
|
const auto extent = target.extent;
|
|
|
|
const auto render_extent = target.get_render_extent();
|
2021-02-17 08:51:47 -05:00
|
|
|
|
2021-02-17 01:32:46 -05:00
|
|
|
if(index > 0) {
|
|
|
|
GFXRenderPassBeginInfo beginInfo = {};
|
|
|
|
beginInfo.render_area.extent = render_extent;
|
|
|
|
|
|
|
|
commandbuffer->set_render_pass(beginInfo);
|
|
|
|
|
|
|
|
Viewport viewport = {};
|
2021-04-19 11:40:10 -04:00
|
|
|
viewport.width = static_cast<float>(render_extent.width);
|
|
|
|
viewport.height = static_cast<float>(render_extent.height);
|
2021-02-17 01:32:46 -05:00
|
|
|
|
|
|
|
commandbuffer->set_viewport(viewport);
|
|
|
|
|
|
|
|
for(auto& pass : passes)
|
|
|
|
pass->render_post(commandbuffer, target, index);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
commandbuffer->push_group("Scene Rendering");
|
|
|
|
|
|
|
|
GFXRenderPassBeginInfo beginInfo = {};
|
|
|
|
beginInfo.framebuffer = target.offscreenFramebuffer;
|
|
|
|
beginInfo.render_pass = offscreenRenderPass;
|
|
|
|
beginInfo.render_area.extent = render_extent;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
ControllerContinuity continuity;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
if(scene != nullptr) {
|
|
|
|
commandbuffer->push_group("Shadow Rendering");
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
shadow_pass->render(commandbuffer, *scene);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
commandbuffer->pop_group();
|
|
|
|
|
|
|
|
if(render_options.enable_ibl) {
|
|
|
|
commandbuffer->push_group("Scene Capture");
|
|
|
|
scene_capture->render(commandbuffer, scene);
|
2020-08-11 12:07:21 -04:00
|
|
|
commandbuffer->pop_group();
|
2021-02-16 19:22:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commandbuffer->set_render_pass(beginInfo);
|
|
|
|
|
|
|
|
const auto& cameras = scene->get_all<Camera>();
|
2021-02-17 00:47:05 -05:00
|
|
|
for(auto& [obj, camera] : cameras) {
|
2021-02-16 19:22:32 -05:00
|
|
|
const bool requires_limited_perspective = render_options.enable_depth_of_field;
|
|
|
|
if(requires_limited_perspective) {
|
2021-04-19 11:40:10 -04:00
|
|
|
camera.perspective = transform::perspective(radians(camera.fov),
|
|
|
|
static_cast<float>(render_extent.width) / static_cast<float>(render_extent.height),
|
|
|
|
camera.near,
|
|
|
|
100.0f);
|
2021-02-16 19:22:32 -05:00
|
|
|
} else {
|
2021-04-19 11:40:10 -04:00
|
|
|
camera.perspective = transform::infinite_perspective(radians(camera.fov),
|
|
|
|
static_cast<float>(render_extent.width) / static_cast<float>(render_extent.height),
|
|
|
|
camera.near);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
camera.view = inverse(scene->get<Transform>(obj).model);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
Viewport viewport = {};
|
2021-04-19 11:40:10 -04:00
|
|
|
viewport.width = static_cast<float>(render_extent.width);
|
|
|
|
viewport.height = static_cast<float>(render_extent.height);
|
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
commandbuffer->set_viewport(viewport);
|
2020-09-22 22:45:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
commandbuffer->push_group("render camera");
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-17 00:47:05 -05:00
|
|
|
render_camera(commandbuffer, *scene, obj, camera, render_extent, target, continuity);
|
2020-09-22 21:47:11 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
commandbuffer->pop_group();
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
2021-02-16 19:22:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
commandbuffer->pop_group();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
commandbuffer->push_group("SMAA");
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
smaa_pass->render(commandbuffer, target);
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
commandbuffer->pop_group();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
if(render_options.enable_depth_of_field && dof_pass != nullptr)
|
|
|
|
dof_pass->render(commandbuffer, *scene);
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
beginInfo.framebuffer = nullptr;
|
|
|
|
beginInfo.render_pass = nullptr;
|
|
|
|
|
|
|
|
commandbuffer->set_render_pass(beginInfo);
|
|
|
|
|
|
|
|
Viewport viewport = {};
|
2021-04-19 11:40:10 -04:00
|
|
|
viewport.width = static_cast<float>(render_extent.width);
|
|
|
|
viewport.height = static_cast<float>(render_extent.height);
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
commandbuffer->set_viewport(viewport);
|
|
|
|
|
|
|
|
commandbuffer->push_group("Post Processing");
|
|
|
|
|
|
|
|
commandbuffer->set_compute_pipeline(histogram_pipeline);
|
|
|
|
|
|
|
|
commandbuffer->bind_texture(target.offscreenColorTexture, 0);
|
|
|
|
commandbuffer->bind_shader_buffer(histogram_buffer, 0, 1, sizeof(uint32_t) * 256);
|
|
|
|
|
|
|
|
const float lum_range = render_options.max_luminance - render_options.min_luminance;
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
Vector4 params = Vector4(render_options.min_luminance,
|
|
|
|
1.0f / lum_range,
|
|
|
|
static_cast<float>(render_extent.width),
|
|
|
|
static_cast<float>(render_extent.height));
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
commandbuffer->set_push_constant(¶ms, sizeof(Vector4));
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
commandbuffer->dispatch(static_cast<uint32_t>(std::ceil(static_cast<float>(render_extent.width) / 16.0f)),
|
|
|
|
static_cast<uint32_t>(std::ceil(static_cast<float>(render_extent.height) / 16.0f)), 1);
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
commandbuffer->set_compute_pipeline(histogram_average_pipeline);
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
params = Vector4(render_options.min_luminance,
|
|
|
|
lum_range,
|
|
|
|
std::clamp(1.0f - std::exp(-(1.0f / 60.0f) * 1.1f), 0.0f, 1.0f),
|
|
|
|
static_cast<float>(render_extent.width * render_extent.height));
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
commandbuffer->set_push_constant(¶ms, sizeof(Vector4));
|
|
|
|
|
|
|
|
commandbuffer->bind_texture(average_luminance_texture, 0);
|
|
|
|
|
|
|
|
commandbuffer->dispatch(1, 1, 1);
|
2020-09-22 20:05:51 -04:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->set_graphics_pipeline(post_pipeline);
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
if(render_options.enable_depth_of_field)
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->bind_texture(dof_pass->normal_field, 1);
|
2021-02-16 19:22:32 -05:00
|
|
|
else
|
|
|
|
commandbuffer->bind_texture(target.offscreenColorTexture, 1);
|
|
|
|
|
|
|
|
commandbuffer->bind_texture(target.blend_texture, 3);
|
|
|
|
|
|
|
|
if(auto texture = get_requested_texture(PassTextureType::SelectionSobel))
|
|
|
|
commandbuffer->bind_texture(texture, 5);
|
|
|
|
else
|
|
|
|
commandbuffer->bind_texture(dummyTexture, 5);
|
|
|
|
|
|
|
|
commandbuffer->bind_texture(average_luminance_texture, 6);
|
|
|
|
|
|
|
|
if(render_options.enable_depth_of_field)
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->bind_texture(dof_pass->far_field, 7);
|
2021-02-16 19:22:32 -05:00
|
|
|
else
|
|
|
|
commandbuffer->bind_texture(dummyTexture, 7);
|
2020-09-22 21:47:11 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
PostPushConstants pc;
|
|
|
|
pc.options.x = render_options.enable_aa;
|
|
|
|
pc.options.z = render_options.exposure;
|
|
|
|
|
|
|
|
if(render_options.enable_depth_of_field)
|
|
|
|
pc.options.w = 2;
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
pc.transform_ops.x = static_cast<float>(render_options.display_color_space);
|
|
|
|
pc.transform_ops.y = static_cast<float>(render_options.tonemapping);
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
const auto [width, height] = render_extent;
|
2021-04-19 11:40:10 -04:00
|
|
|
pc.viewport = Vector4(1.0f / static_cast<float>(width), 1.0f / static_cast<float>(height), static_cast<float>(width), static_cast<float>(height));
|
2021-02-16 19:22:32 -05:00
|
|
|
|
|
|
|
commandbuffer->set_push_constant(&pc, sizeof(PostPushConstants));
|
|
|
|
|
|
|
|
commandbuffer->draw(0, 4, 0, 1);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
commandbuffer->pop_group();
|
|
|
|
|
|
|
|
if(current_screen != nullptr)
|
|
|
|
render_screen(commandbuffer, current_screen, extent, continuity);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
commandbuffer->push_group("Extra Passes");
|
|
|
|
|
|
|
|
for(auto& pass : passes)
|
2021-02-17 01:32:46 -05:00
|
|
|
pass->render_post(commandbuffer, target, index);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
commandbuffer->pop_group();
|
2021-04-18 21:39:53 -04:00
|
|
|
|
|
|
|
target.current_frame = (target.current_frame + 1) % RT_MAX_FRAMES_IN_FLIGHT;
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-02-17 00:47:05 -05:00
|
|
|
void Renderer::render_camera(GFXCommandBuffer* command_buffer, Scene& scene, Object camera_object, Camera& camera, prism::Extent extent, RenderTarget& target, ControllerContinuity& continuity) {
|
2020-08-11 12:07:21 -04:00
|
|
|
// frustum test
|
|
|
|
const auto frustum = normalize_frustum(camera_extract_frustum(scene, camera_object));
|
2020-08-17 08:45:28 -04:00
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
SceneInformation sceneInfo = {};
|
|
|
|
sceneInfo.lightspace = scene.lightSpace;
|
|
|
|
sceneInfo.options = Vector4(1, 0, 0, 0);
|
|
|
|
sceneInfo.camPos = scene.get<Transform>(camera_object).get_world_position();
|
2021-02-15 15:06:13 -05:00
|
|
|
sceneInfo.camPos.w = 2.0f * camera.near * std::tan(camera.fov * 0.5f) * (static_cast<float>(extent.width) / static_cast<float>(extent.height));
|
2020-08-18 00:35:49 -04:00
|
|
|
sceneInfo.vp = camera.perspective * camera.view;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
for(const auto& [obj, light] : scene.get_all<Light>()) {
|
2020-08-11 12:07:21 -04:00
|
|
|
SceneLight sl;
|
2021-04-19 11:40:10 -04:00
|
|
|
sl.positionType = Vector4(scene.get<Transform>(obj).get_world_position(), static_cast<float>(light.type));
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
Vector3 front = Vector3(0.0f, 0.0f, 1.0f) * scene.get<Transform>(obj).rotation;
|
|
|
|
|
|
|
|
sl.directionPower = Vector4(-front, light.power);
|
2020-08-19 22:09:32 -04:00
|
|
|
sl.colorSize = Vector4(utility::from_srgb_to_linear(light.color), radians(light.spot_size));
|
2020-08-11 12:07:21 -04:00
|
|
|
sl.shadowsEnable = Vector4(light.enable_shadows, radians(light.size), 0, 0);
|
|
|
|
|
|
|
|
sceneInfo.lights[sceneInfo.numLights++] = sl;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(int i = 0; i < max_spot_shadows; i++)
|
|
|
|
sceneInfo.spotLightSpaces[i] = scene.spotLightSpaces[i];
|
|
|
|
|
|
|
|
int last_probe = 0;
|
2021-04-19 11:40:10 -04:00
|
|
|
for(const auto& [obj, probe] : scene.get_all<EnvironmentProbe>()) {
|
2020-08-11 12:07:21 -04:00
|
|
|
SceneProbe p;
|
|
|
|
p.position = Vector4(scene.get<Transform>(obj).position, probe.is_sized ? 1.0f : 2.0f);
|
|
|
|
p.size = Vector4(probe.size, probe.intensity);
|
|
|
|
|
|
|
|
sceneInfo.probes[last_probe++] = p;
|
|
|
|
}
|
|
|
|
|
|
|
|
int numMaterialsInBuffer = 0;
|
|
|
|
std::map<Material*, int> material_indices;
|
|
|
|
|
|
|
|
const auto& meshes = scene.get_all<Renderable>();
|
2021-04-19 11:40:10 -04:00
|
|
|
for(const auto& [obj, mesh] : meshes) {
|
2020-08-11 12:07:21 -04:00
|
|
|
if(!mesh.mesh)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(mesh.materials.empty())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
for(auto& material : mesh.materials) {
|
|
|
|
if(!material)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(material->static_pipeline == nullptr || material->skinned_pipeline == nullptr)
|
|
|
|
create_mesh_pipeline(*material.handle);
|
|
|
|
|
|
|
|
if(!material_indices.count(material.handle)) {
|
|
|
|
material_indices[material.handle] = numMaterialsInBuffer++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct PushConstant {
|
|
|
|
Matrix4x4 m;
|
|
|
|
} pc;
|
|
|
|
|
|
|
|
pc.m = scene.get<Transform>(obj).model;
|
|
|
|
|
|
|
|
command_buffer->set_vertex_buffer(mesh.mesh->position_buffer, 0, position_buffer_index);
|
|
|
|
command_buffer->set_vertex_buffer(mesh.mesh->normal_buffer, 0, normal_buffer_index);
|
|
|
|
command_buffer->set_vertex_buffer(mesh.mesh->texture_coord_buffer, 0, texcoord_buffer_index);
|
|
|
|
command_buffer->set_vertex_buffer(mesh.mesh->tangent_buffer, 0, tangent_buffer_index);
|
|
|
|
command_buffer->set_vertex_buffer(mesh.mesh->bitangent_buffer, 0, bitangent_buffer_index);
|
|
|
|
|
|
|
|
if(!mesh.mesh->bones.empty())
|
|
|
|
command_buffer->set_vertex_buffer(mesh.mesh->bone_buffer, 0, bone_buffer_index);
|
|
|
|
|
|
|
|
command_buffer->set_index_buffer(mesh.mesh->index_buffer, IndexType::UINT32);
|
|
|
|
|
|
|
|
for(const auto& part : mesh.mesh->parts) {
|
|
|
|
const int material_index = part.material_override == -1 ? 0 : part.material_override;
|
|
|
|
|
|
|
|
if(material_index >= mesh.materials.size())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(mesh.materials[material_index].handle == nullptr || mesh.materials[material_index]->static_pipeline == nullptr)
|
|
|
|
continue;
|
|
|
|
|
2020-08-17 10:11:58 -04:00
|
|
|
if(render_options.enable_frustum_culling && !test_aabb_frustum(frustum, get_aabb_for_part(scene.get<Transform>(obj), part)))
|
2020-08-11 12:07:21 -04:00
|
|
|
continue;
|
|
|
|
|
2020-09-22 16:09:25 -04:00
|
|
|
command_buffer->set_graphics_pipeline(mesh.mesh->bones.empty() ? mesh.materials[material_index]->static_pipeline : mesh.materials[material_index]->skinned_pipeline);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-17 00:47:05 -05:00
|
|
|
command_buffer->bind_shader_buffer(target.sceneBuffer, 0, 1, sizeof(SceneInformation));
|
2020-09-30 19:18:17 -04:00
|
|
|
|
|
|
|
command_buffer->bind_texture(scene.depthTexture, 2);
|
|
|
|
command_buffer->bind_texture(scene.pointLightArray, 3);
|
|
|
|
command_buffer->bind_texture(scene.spotLightArray, 6);
|
|
|
|
command_buffer->bind_texture(scene.irradianceCubeArray, 7);
|
|
|
|
command_buffer->bind_texture(scene.prefilteredCubeArray, 8);
|
2021-04-20 13:25:59 -04:00
|
|
|
command_buffer->bind_texture(brdf_texture, 9);
|
2020-09-30 19:18:17 -04:00
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
if(!mesh.mesh->bones.empty())
|
|
|
|
command_buffer->bind_shader_buffer(part.bone_batrix_buffer, 0, 14, sizeof(Matrix4x4) * 128);
|
|
|
|
|
|
|
|
command_buffer->set_push_constant(&pc, sizeof(PushConstant));
|
|
|
|
|
|
|
|
for(const auto& [index, texture] : mesh.materials[material_index]->bound_textures) {
|
|
|
|
GFXTexture* texture_to_bind = dummyTexture;
|
|
|
|
if(texture)
|
|
|
|
texture_to_bind = texture->handle;
|
|
|
|
|
|
|
|
command_buffer->bind_texture(texture_to_bind, index);
|
|
|
|
}
|
|
|
|
|
2020-09-23 09:53:45 -04:00
|
|
|
command_buffer->draw_indexed(part.index_count, part.index_offset, part.vertex_offset, 0);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const auto& screens = scene.get_all<UI>();
|
|
|
|
for(const auto& [obj, screen] : screens) {
|
|
|
|
if(!screen.screen)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
RenderScreenOptions options = {};
|
|
|
|
options.render_world = true;
|
2020-08-18 00:35:49 -04:00
|
|
|
options.mvp = camera.perspective * camera.view * scene.get<Transform>(obj).model;
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
render_screen(command_buffer, screen.screen, extent, continuity, options);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-02-03 09:04:30 -05:00
|
|
|
SkyPushConstant pc;
|
2020-08-18 00:35:49 -04:00
|
|
|
pc.view = matrix_from_quat(scene.get<Transform>(camera_object).rotation);
|
2020-08-14 23:32:02 -04:00
|
|
|
pc.aspect = static_cast<float>(extent.width) / static_cast<float>(extent.height);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
for(const auto& [obj, light] : scene.get_all<Light>()) {
|
|
|
|
if(light.type == Light::Type::Sun)
|
2020-08-14 23:32:02 -04:00
|
|
|
pc.sun_position_fov = Vector4(scene.get<Transform>(obj).get_world_position(), radians(camera.fov));
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
command_buffer->set_graphics_pipeline(sky_pipeline);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
command_buffer->set_push_constant(&pc, sizeof(SkyPushConstant));
|
|
|
|
|
|
|
|
command_buffer->draw(0, 4, 0, 1);
|
|
|
|
|
|
|
|
if(render_options.enable_extra_passes) {
|
|
|
|
for(auto& pass : passes)
|
|
|
|
pass->render_scene(scene, command_buffer);
|
|
|
|
}
|
|
|
|
|
2021-02-17 00:47:05 -05:00
|
|
|
gfx->copy_buffer(target.sceneBuffer, &sceneInfo, 0, sizeof(SceneInformation));
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
void Renderer::render_screen(GFXCommandBuffer *commandbuffer, ui::Screen* screen, prism::Extent extent, ControllerContinuity& continuity, RenderScreenOptions options) {
|
2020-08-11 12:07:21 -04:00
|
|
|
std::array<GlyphInstance, maxInstances> instances;
|
|
|
|
std::vector<ElementInstance> elementInstances;
|
2021-04-19 11:40:10 -04:00
|
|
|
std::array<StringInstance, 50> stringInstances = {};
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
int stringLen = 0;
|
|
|
|
int numElements = 0;
|
|
|
|
|
|
|
|
for(auto [i, element] : utility::enumerate(screen->elements)) {
|
|
|
|
if(!element.visible)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ElementInstance instance;
|
|
|
|
|
|
|
|
instance.position = utility::pack_u32(utility::to_fixed(element.absolute_x), utility::to_fixed(element.absolute_y));
|
|
|
|
instance.size = utility::pack_u32(utility::to_fixed(element.absolute_width), utility::to_fixed(element.absolute_height));
|
|
|
|
instance.color[0] = element.background.color.r;
|
|
|
|
instance.color[1] = element.background.color.g;
|
|
|
|
instance.color[2] = element.background.color.b;
|
|
|
|
instance.color[3] = element.background.color.a;
|
|
|
|
|
|
|
|
elementInstances.push_back(instance);
|
|
|
|
|
|
|
|
stringInstances[i].xy = utility::pack_u32(utility::to_fixed(element.absolute_x + element.text_x), utility::to_fixed(element.absolute_y + element.text_y));
|
|
|
|
|
|
|
|
float advance = 0.0f;
|
|
|
|
float yadvance = 0.0f;
|
|
|
|
|
|
|
|
bool do_y_advance = false; // so we can not advance the text by a space if we're wrapping per word
|
|
|
|
|
|
|
|
for(size_t j = 0; j < element.text.length(); j++) {
|
|
|
|
auto index = element.text[j] - 32;
|
|
|
|
|
|
|
|
if(do_y_advance) {
|
|
|
|
advance = 0.0f;
|
|
|
|
yadvance += font.ascentSizes[fontSize];
|
|
|
|
do_y_advance = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(element.wrap_text) {
|
|
|
|
if(element.text[j] == ' ') {
|
|
|
|
std::string t;
|
|
|
|
float temp_advance = 0.0f;
|
|
|
|
for(size_t k = j + 1; k < element.text.length() + j; k++) {
|
|
|
|
t += element.text[k];
|
|
|
|
auto index = element.text[k] - 32;
|
|
|
|
temp_advance += font.sizes[fontSize][index].xadvance;
|
|
|
|
|
|
|
|
if(element.text[k] == ' ')
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if((temp_advance + advance) >= element.absolute_width)
|
|
|
|
do_y_advance = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
GlyphInstance& instance = instances[stringLen + j];
|
|
|
|
instance.position = utility::pack_u32(utility::to_fixed(advance), utility::to_fixed(yadvance));
|
|
|
|
instance.index = utility::pack_u32(index, 0);
|
|
|
|
instance.instance = i;
|
|
|
|
|
|
|
|
advance += font.sizes[fontSize][index].xadvance;
|
|
|
|
|
|
|
|
if(element.text[j] == '\n') {
|
|
|
|
advance = 0.0f;
|
|
|
|
yadvance += font.ascentSizes[fontSize];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
stringLen += static_cast<int>(element.text.length());
|
|
|
|
numElements++;
|
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
gfx->copy_buffer(screen->glyph_buffer, instances.data(), 0, instance_alignment);
|
2020-08-11 12:07:21 -04:00
|
|
|
gfx->copy_buffer(screen->instance_buffer, stringInstances.data(), 0, sizeof(StringInstance) * 50);
|
|
|
|
gfx->copy_buffer(screen->elements_buffer, elementInstances.data(), sizeof(ElementInstance) * continuity.elementOffset, sizeof(ElementInstance) * elementInstances.size());
|
|
|
|
|
|
|
|
const Vector2 windowSize = {static_cast<float>(extent.width), static_cast<float>(extent.height)};
|
|
|
|
|
|
|
|
for(auto [i, element] : utility::enumerate(screen->elements)) {
|
|
|
|
if(!element.visible)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
UIPushConstant pc;
|
|
|
|
pc.screenSize = windowSize;
|
|
|
|
|
|
|
|
if(options.render_world) {
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->set_graphics_pipeline(world_general_pipeline);
|
2020-08-11 12:07:21 -04:00
|
|
|
pc.mvp = options.mvp;
|
|
|
|
} else {
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->set_graphics_pipeline(general_pipeline);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2020-09-30 19:18:17 -04:00
|
|
|
if (element.background.texture) {
|
|
|
|
commandbuffer->bind_texture(element.background.texture->handle, 2);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
commandbuffer->bind_texture(dummyTexture, 2);
|
|
|
|
}
|
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant));
|
|
|
|
|
|
|
|
commandbuffer->bind_shader_buffer(screen->elements_buffer, 0, 0, sizeof(ElementInstance) * 50);
|
|
|
|
commandbuffer->draw(0, 4, i + continuity.elementOffset, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
UIPushConstant pc;
|
|
|
|
pc.screenSize = windowSize;
|
|
|
|
|
|
|
|
if(options.render_world) {
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->set_graphics_pipeline(world_text_pipeline);
|
2020-08-11 12:07:21 -04:00
|
|
|
pc.mvp = options.mvp;
|
|
|
|
} else {
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->set_graphics_pipeline(text_pipeline);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
commandbuffer->set_push_constant(&pc, sizeof(UIPushConstant));
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->bind_shader_buffer(screen->glyph_buffer, 0, 0, instance_alignment);
|
|
|
|
commandbuffer->bind_shader_buffer(screen->glyph_buffer, instance_alignment, 1, sizeof(GylphMetric) * numGlyphs);
|
2020-08-11 12:07:21 -04:00
|
|
|
commandbuffer->bind_shader_buffer(screen->instance_buffer, 0, 2, sizeof(StringInstance) * 50);
|
2021-04-20 13:25:59 -04:00
|
|
|
commandbuffer->bind_texture(font_texture, 3);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
if(stringLen > 0)
|
|
|
|
commandbuffer->draw(0, 4, 0, stringLen);
|
|
|
|
|
|
|
|
continuity.elementOffset += numElements;
|
|
|
|
}
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
void Renderer::create_mesh_pipeline(Material& material) const {
|
2020-08-11 12:07:21 -04:00
|
|
|
GFXShaderConstant materials_constant = {};
|
|
|
|
materials_constant.type = GFXShaderConstant::Type::Integer;
|
|
|
|
materials_constant.value = max_scene_materials;
|
|
|
|
|
|
|
|
GFXShaderConstant lights_constant = {};
|
|
|
|
lights_constant.index = 1;
|
|
|
|
lights_constant.type = GFXShaderConstant::Type::Integer;
|
|
|
|
lights_constant.value = max_scene_lights;
|
|
|
|
|
|
|
|
GFXShaderConstant spot_lights_constant = {};
|
|
|
|
spot_lights_constant.index = 2;
|
|
|
|
spot_lights_constant.type = GFXShaderConstant::Type::Integer;
|
|
|
|
spot_lights_constant.value = max_spot_shadows;
|
|
|
|
|
|
|
|
GFXShaderConstant probes_constant = {};
|
|
|
|
probes_constant.index = 3;
|
|
|
|
probes_constant.type = GFXShaderConstant::Type::Integer;
|
|
|
|
probes_constant.value = max_environment_probes;
|
|
|
|
|
|
|
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
|
|
|
pipelineInfo.label = "Mesh";
|
2021-02-16 17:10:37 -05:00
|
|
|
pipelineInfo.shaders.vertex_src = file::Path("mesh.vert");
|
|
|
|
pipelineInfo.shaders.fragment_src = file::Path("mesh.frag");
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
pipelineInfo.shaders.vertex_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant};
|
|
|
|
pipelineInfo.shaders.fragment_constants = {materials_constant, lights_constant, spot_lights_constant, probes_constant};
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.push_constants = {
|
2020-09-23 11:54:59 -04:00
|
|
|
{sizeof(Matrix4x4), 0}
|
2020-08-11 12:07:21 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.bindings = {
|
|
|
|
{1, GFXBindingType::StorageBuffer},
|
|
|
|
{0, GFXBindingType::PushConstant},
|
2021-02-15 19:01:17 -05:00
|
|
|
{2, GFXBindingType::Texture},
|
|
|
|
{3, GFXBindingType::Texture},
|
|
|
|
{6, GFXBindingType::Texture},
|
2020-09-23 11:54:59 -04:00
|
|
|
{7, GFXBindingType::Texture},
|
|
|
|
{8, GFXBindingType::Texture},
|
|
|
|
{9, GFXBindingType::Texture}
|
2020-08-11 12:07:21 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
pipelineInfo.render_pass = offscreenRenderPass;
|
|
|
|
pipelineInfo.depth.depth_mode = GFXDepthMode::Less;
|
|
|
|
pipelineInfo.rasterization.culling_mode = GFXCullingMode::Backface;
|
|
|
|
pipelineInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha;
|
|
|
|
pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha;
|
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material);
|
2020-09-23 11:54:59 -04:00
|
|
|
|
|
|
|
for (auto [index, texture] : material.bound_textures) {
|
|
|
|
GFXShaderBinding binding;
|
|
|
|
binding.binding = index;
|
|
|
|
binding.type = GFXBindingType::Texture;
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.bindings.push_back(binding);
|
|
|
|
}
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
auto [static_pipeline, skinned_pipeline] = material_compiler.create_pipeline_permutations(pipelineInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
material.static_pipeline = static_pipeline;
|
|
|
|
material.skinned_pipeline = skinned_pipeline;
|
|
|
|
|
|
|
|
pipelineInfo.render_pass = scene_capture->renderPass;
|
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
pipelineInfo.shaders.fragment_src = material_compiler.compile_material_fragment(material, false); // scene capture does not use IBL
|
2020-08-16 23:31:00 -04:00
|
|
|
|
2020-09-23 11:54:59 -04:00
|
|
|
pipelineInfo.shader_input.push_constants[0].size += sizeof(Matrix4x4);
|
|
|
|
|
2020-08-15 20:09:16 -04:00
|
|
|
material.capture_pipeline = material_compiler.create_static_pipeline(pipelineInfo, false, true);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
void Renderer::create_dummy_texture() {
|
2020-08-11 12:07:21 -04:00
|
|
|
GFXTextureCreateInfo createInfo = {};
|
2021-02-04 08:21:40 -05:00
|
|
|
createInfo.label = "Dummy";
|
2020-08-11 12:07:21 -04:00
|
|
|
createInfo.width = 1;
|
|
|
|
createInfo.height = 1;
|
|
|
|
createInfo.format = GFXPixelFormat::R8G8B8A8_UNORM;
|
|
|
|
createInfo.usage = GFXTextureUsage::Sampled;
|
|
|
|
|
|
|
|
dummyTexture = gfx->create_texture(createInfo);
|
|
|
|
|
|
|
|
uint8_t tex[4] = {0, 0, 0, 0};
|
|
|
|
|
|
|
|
gfx->copy_texture(dummyTexture, tex, sizeof(tex));
|
|
|
|
}
|
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
void Renderer::create_render_target_resources(RenderTarget& target) {
|
|
|
|
const auto extent = target.get_render_extent();
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
GFXTextureCreateInfo textureInfo = {};
|
2021-02-04 08:21:40 -05:00
|
|
|
textureInfo.label = "Offscreen Color";
|
2020-08-11 12:07:21 -04:00
|
|
|
textureInfo.width = extent.width;
|
|
|
|
textureInfo.height = extent.height;
|
|
|
|
textureInfo.format = GFXPixelFormat::RGBA_32F;
|
|
|
|
textureInfo.usage = GFXTextureUsage::Attachment | GFXTextureUsage::Sampled;
|
|
|
|
textureInfo.samplingMode = SamplingMode::ClampToEdge;
|
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
target.offscreenColorTexture = gfx->create_texture(textureInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-04 08:21:40 -05:00
|
|
|
textureInfo.label = "Offscreen Depth";
|
2020-08-11 12:07:21 -04:00
|
|
|
textureInfo.format = GFXPixelFormat::DEPTH_32F;
|
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
target.offscreenDepthTexture = gfx->create_texture(textureInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
GFXFramebufferCreateInfo framebufferInfo = {};
|
|
|
|
framebufferInfo.render_pass = offscreenRenderPass;
|
2021-02-16 19:22:32 -05:00
|
|
|
framebufferInfo.attachments.push_back(target.offscreenColorTexture);
|
|
|
|
framebufferInfo.attachments.push_back(target.offscreenDepthTexture);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-02-16 19:22:32 -05:00
|
|
|
target.offscreenFramebuffer = gfx->create_framebuffer(framebufferInfo);
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
if(post_pipeline == nullptr) {
|
2021-02-17 00:15:59 -05:00
|
|
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
|
|
|
pipelineInfo.label = "Post";
|
|
|
|
|
|
|
|
pipelineInfo.shaders.vertex_src = file::Path("post.vert");
|
|
|
|
pipelineInfo.shaders.fragment_src = file::Path("post.frag");
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.bindings = {
|
|
|
|
{4, GFXBindingType::PushConstant},
|
|
|
|
{1, GFXBindingType::Texture},
|
|
|
|
{2, GFXBindingType::Texture},
|
|
|
|
{3, GFXBindingType::Texture},
|
|
|
|
{5, GFXBindingType::Texture},
|
|
|
|
{6, GFXBindingType::Texture},
|
|
|
|
{7, GFXBindingType::Texture}
|
|
|
|
};
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.push_constants = {
|
|
|
|
{sizeof(PostPushConstants), 0}
|
|
|
|
};
|
2021-04-20 13:25:59 -04:00
|
|
|
|
|
|
|
post_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
2021-02-17 00:47:05 -05:00
|
|
|
|
|
|
|
target.sceneBuffer = gfx->create_buffer(nullptr, sizeof(SceneInformation), true, GFXBufferUsage::Storage);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
void Renderer::create_post_pipelines() {
|
2020-08-11 12:07:21 -04:00
|
|
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
|
|
|
pipelineInfo.label = "Post";
|
2021-02-16 19:22:32 -05:00
|
|
|
|
2021-02-16 17:10:37 -05:00
|
|
|
pipelineInfo.shaders.vertex_src = file::Path("post.vert");
|
|
|
|
pipelineInfo.shaders.fragment_src = file::Path("post.frag");
|
2021-02-16 19:22:32 -05:00
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
pipelineInfo.shader_input.bindings = {
|
|
|
|
{4, GFXBindingType::PushConstant},
|
|
|
|
{1, GFXBindingType::Texture},
|
|
|
|
{2, GFXBindingType::Texture},
|
2020-09-23 11:54:59 -04:00
|
|
|
{3, GFXBindingType::Texture},
|
|
|
|
{5, GFXBindingType::Texture},
|
|
|
|
{6, GFXBindingType::Texture},
|
|
|
|
{7, GFXBindingType::Texture}
|
2020-08-11 12:07:21 -04:00
|
|
|
};
|
2021-02-16 19:22:32 -05:00
|
|
|
|
2020-08-11 12:07:21 -04:00
|
|
|
pipelineInfo.shader_input.push_constants = {
|
|
|
|
{sizeof(PostPushConstants), 0}
|
|
|
|
};
|
2021-04-20 13:25:59 -04:00
|
|
|
|
|
|
|
post_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
void Renderer::create_font_texture() {
|
2020-08-11 12:07:21 -04:00
|
|
|
auto file = file::open(file::app_domain / "font.fp", true);
|
|
|
|
if(file == std::nullopt) {
|
2021-04-20 11:23:53 -04:00
|
|
|
prism::log::error(System::Renderer, "Failed to load font file!");
|
2020-08-11 12:07:21 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
file->read(&font);
|
|
|
|
|
|
|
|
std::vector<unsigned char> bitmap(font.width * font.height);
|
|
|
|
file->read(bitmap.data(), font.width * font.height);
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
instance_alignment = (int)gfx->get_alignment(sizeof(GlyphInstance) * maxInstances);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
GFXTextureCreateInfo textureInfo = {};
|
2021-02-04 08:21:40 -05:00
|
|
|
textureInfo.label = "UI Font";
|
2020-08-11 12:07:21 -04:00
|
|
|
textureInfo.width = font.width;
|
|
|
|
textureInfo.height = font.height;
|
|
|
|
textureInfo.format = GFXPixelFormat::R8_UNORM;
|
|
|
|
textureInfo.usage = GFXTextureUsage::Sampled;
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
font_texture = gfx->create_texture(textureInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
gfx->copy_texture(font_texture, bitmap.data(), font.width * font.height);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
void Renderer::create_sky_pipeline() {
|
2020-08-11 12:07:21 -04:00
|
|
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
|
|
|
pipelineInfo.label = "Sky";
|
|
|
|
pipelineInfo.render_pass = offscreenRenderPass;
|
|
|
|
|
2021-02-16 17:10:37 -05:00
|
|
|
pipelineInfo.shaders.vertex_src = register_shader("sky.vert");
|
|
|
|
pipelineInfo.shaders.fragment_src = register_shader("sky.frag");
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
pipelineInfo.shader_input.bindings = {
|
|
|
|
{1, GFXBindingType::PushConstant}
|
|
|
|
};
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.push_constants = {
|
2021-02-03 09:04:30 -05:00
|
|
|
{sizeof(SkyPushConstant), 0}
|
2020-08-11 12:07:21 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual;
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
sky_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2021-02-16 17:10:37 -05:00
|
|
|
|
|
|
|
associate_shader_reload("sky.vert", [this] {
|
2021-04-20 13:25:59 -04:00
|
|
|
create_sky_pipeline();
|
2021-02-16 17:10:37 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
associate_shader_reload("sky.frag", [this] {
|
2021-04-20 13:25:59 -04:00
|
|
|
create_sky_pipeline();
|
2021-02-16 17:10:37 -05:00
|
|
|
});
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
void Renderer::create_ui_pipelines() {
|
2020-08-11 12:07:21 -04:00
|
|
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
|
|
|
pipelineInfo.label = "UI";
|
|
|
|
|
2021-02-16 17:10:37 -05:00
|
|
|
pipelineInfo.shaders.vertex_src = file::Path("ui.vert");
|
|
|
|
pipelineInfo.shaders.fragment_src = file::Path("ui.frag");
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
pipelineInfo.rasterization.primitive_type = GFXPrimitiveType::TriangleStrip;
|
|
|
|
|
|
|
|
pipelineInfo.blending.enable_blending = true;
|
|
|
|
pipelineInfo.blending.src_rgb = GFXBlendFactor::SrcAlpha;
|
|
|
|
pipelineInfo.blending.dst_rgb = GFXBlendFactor::OneMinusSrcAlpha;
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.bindings = {
|
|
|
|
{1, GFXBindingType::PushConstant},
|
|
|
|
{0, GFXBindingType::StorageBuffer},
|
|
|
|
{2, GFXBindingType::Texture}
|
|
|
|
};
|
|
|
|
|
|
|
|
pipelineInfo.shader_input.push_constants = {
|
|
|
|
{sizeof(UIPushConstant), 0}
|
|
|
|
};
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
general_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
pipelineInfo.label = "UI World";
|
|
|
|
pipelineInfo.render_pass = offscreenRenderPass;
|
|
|
|
pipelineInfo.depth.depth_mode = GFXDepthMode::LessOrEqual;
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
world_general_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
}
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
void Renderer::generate_brdf() {
|
2020-08-11 12:07:21 -04:00
|
|
|
GFXRenderPassCreateInfo renderPassInfo = {};
|
2020-09-23 10:17:24 -04:00
|
|
|
renderPassInfo.label = "BRDF Gen";
|
2020-08-11 12:07:21 -04:00
|
|
|
renderPassInfo.attachments.push_back(GFXPixelFormat::R8G8_SFLOAT);
|
2021-02-15 19:01:17 -05:00
|
|
|
renderPassInfo.will_use_in_shader = true;
|
2021-04-20 13:25:59 -04:00
|
|
|
|
|
|
|
brdf_render_pass = gfx->create_render_pass(renderPassInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
GFXGraphicsPipelineCreateInfo pipelineInfo = {};
|
|
|
|
pipelineInfo.label = "BRDF";
|
|
|
|
|
2021-02-16 17:10:37 -05:00
|
|
|
pipelineInfo.shaders.vertex_src = file::Path("brdf.vert");
|
|
|
|
pipelineInfo.shaders.fragment_src = file::Path("brdf.frag");
|
2020-08-11 12:07:21 -04:00
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
pipelineInfo.render_pass = brdf_render_pass;
|
|
|
|
|
|
|
|
brdf_pipeline = gfx->create_graphics_pipeline(pipelineInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
GFXTextureCreateInfo textureInfo = {};
|
2021-02-04 08:21:40 -05:00
|
|
|
textureInfo.label = "BRDF LUT";
|
2020-08-11 12:07:21 -04:00
|
|
|
textureInfo.format = GFXPixelFormat::R8G8_SFLOAT;
|
|
|
|
textureInfo.width = brdf_resolution;
|
|
|
|
textureInfo.height = brdf_resolution;
|
|
|
|
textureInfo.usage = GFXTextureUsage::Sampled | GFXTextureUsage::Attachment;
|
2021-04-20 13:25:59 -04:00
|
|
|
|
|
|
|
brdf_texture = gfx->create_texture(textureInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
GFXFramebufferCreateInfo framebufferInfo = {};
|
2021-04-20 13:25:59 -04:00
|
|
|
framebufferInfo.attachments = {brdf_texture};
|
|
|
|
framebufferInfo.render_pass = brdf_render_pass;
|
|
|
|
|
|
|
|
brdf_framebuffer = gfx->create_framebuffer(framebufferInfo);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
// render
|
|
|
|
GFXCommandBuffer* command_buffer = gfx->acquire_command_buffer();
|
|
|
|
|
|
|
|
GFXRenderPassBeginInfo beginInfo = {};
|
2021-04-20 13:25:59 -04:00
|
|
|
beginInfo.render_pass = brdf_render_pass;
|
|
|
|
beginInfo.framebuffer = brdf_framebuffer;
|
2020-08-11 12:07:21 -04:00
|
|
|
beginInfo.render_area.extent = {brdf_resolution, brdf_resolution};
|
|
|
|
|
|
|
|
command_buffer->set_render_pass(beginInfo);
|
|
|
|
|
2021-04-20 13:25:59 -04:00
|
|
|
command_buffer->set_graphics_pipeline(brdf_pipeline);
|
2020-08-11 12:07:21 -04:00
|
|
|
|
|
|
|
Viewport viewport = {};
|
|
|
|
viewport.width = brdf_resolution;
|
|
|
|
viewport.height = brdf_resolution;
|
|
|
|
|
|
|
|
command_buffer->set_viewport(viewport);
|
|
|
|
|
|
|
|
command_buffer->draw(0, 4, 0, 1);
|
|
|
|
|
|
|
|
gfx->submit(command_buffer);
|
|
|
|
}
|
2020-09-22 15:39:20 -04:00
|
|
|
|
|
|
|
void Renderer::create_histogram_resources() {
|
|
|
|
GFXComputePipelineCreateInfo create_info = {};
|
|
|
|
create_info.shaders.compute_path = "histogram.comp";
|
2020-09-22 17:27:10 -04:00
|
|
|
create_info.workgroup_size_x = 16;
|
|
|
|
create_info.workgroup_size_y = 16;
|
2020-09-22 15:39:20 -04:00
|
|
|
|
2020-09-22 20:05:51 -04:00
|
|
|
create_info.shader_input.bindings = {
|
|
|
|
{2, GFXBindingType::PushConstant}
|
|
|
|
};
|
|
|
|
|
2020-09-22 15:39:20 -04:00
|
|
|
histogram_pipeline = gfx->create_compute_pipeline(create_info);
|
2020-09-22 17:27:10 -04:00
|
|
|
|
2020-09-22 20:05:51 -04:00
|
|
|
create_info.shaders.compute_path = "histogram-average.comp";
|
|
|
|
create_info.workgroup_size_x = 256;
|
|
|
|
create_info.workgroup_size_y = 1;
|
|
|
|
|
|
|
|
histogram_average_pipeline = gfx->create_compute_pipeline(create_info);
|
|
|
|
|
|
|
|
histogram_buffer = gfx->create_buffer(nullptr, sizeof(uint32_t) * 256, false, GFXBufferUsage::Storage);
|
|
|
|
|
|
|
|
GFXTextureCreateInfo texture_info = {};
|
2021-02-04 08:21:40 -05:00
|
|
|
texture_info.label = "Average Luminance Store";
|
2020-09-22 20:05:51 -04:00
|
|
|
texture_info.width = 1;
|
|
|
|
texture_info.height = 1;
|
|
|
|
texture_info.format = GFXPixelFormat::R_16F;
|
|
|
|
texture_info.usage = GFXTextureUsage::Sampled | GFXTextureUsage::ShaderWrite;
|
|
|
|
|
|
|
|
average_luminance_texture = gfx->create_texture(texture_info);
|
2020-09-22 15:39:20 -04:00
|
|
|
}
|
2021-02-16 17:10:37 -05:00
|
|
|
|
|
|
|
ShaderSource Renderer::register_shader(const std::string_view shader_file) {
|
|
|
|
if(!reloading_shader) {
|
|
|
|
RegisteredShader shader;
|
|
|
|
shader.filename = shader_file;
|
|
|
|
|
|
|
|
registered_shaders.push_back(shader);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string found_shader_source;
|
|
|
|
for(auto& shader : registered_shaders) {
|
|
|
|
if(shader.filename == shader_file) {
|
|
|
|
found_shader_source = shader.injected_shader_source;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
file::Path base_shader_path = get_shader_source_directory();
|
|
|
|
|
|
|
|
// if shader editor system is not initialized, use prebuilt shaders
|
|
|
|
if(base_shader_path.empty())
|
|
|
|
return file::Path(shader_file);
|
|
|
|
|
|
|
|
shader_compiler.set_include_path(base_shader_path.string());
|
|
|
|
|
|
|
|
file::Path shader_path = file::Path(shader_file);
|
|
|
|
|
2021-02-18 08:31:36 -05:00
|
|
|
ShaderStage stage = ShaderStage::Vertex;
|
2021-02-16 17:10:37 -05:00
|
|
|
if(shader_path.extension() == ".vert")
|
|
|
|
stage = ShaderStage::Vertex;
|
|
|
|
else if(shader_path.extension() == ".frag")
|
|
|
|
stage = ShaderStage::Fragment;
|
|
|
|
|
|
|
|
if(found_shader_source.empty()) {
|
|
|
|
auto file = file::open(base_shader_path / shader_path.replace_extension(shader_path.extension().string() + ".glsl"));
|
|
|
|
|
2021-04-18 22:27:05 -04:00
|
|
|
return shader_compiler.compile(ShaderLanguage::GLSL, stage, file->read_as_string(), gfx->accepted_shader_language()).value();
|
2021-02-16 17:10:37 -05:00
|
|
|
} else {
|
2021-04-18 22:27:05 -04:00
|
|
|
return shader_compiler.compile(ShaderLanguage::GLSL, stage, found_shader_source, gfx->accepted_shader_language()).value();
|
2021-02-16 17:10:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-19 11:40:10 -04:00
|
|
|
void Renderer::associate_shader_reload(const std::string_view shader_file, const std::function<void()>& reload_function) {
|
2021-02-16 17:10:37 -05:00
|
|
|
if(reloading_shader)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for(auto& shader : registered_shaders) {
|
|
|
|
if(shader.filename == shader_file)
|
|
|
|
shader.reload_function = reload_function;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Renderer::reload_shader(const std::string_view shader_file, const std::string_view shader_source) {
|
|
|
|
for(auto& shader : registered_shaders) {
|
|
|
|
if(shader.filename == shader_file) {
|
|
|
|
shader.injected_shader_source = shader_source;
|
|
|
|
reloading_shader = true;
|
|
|
|
shader.reload_function();
|
|
|
|
reloading_shader = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|