mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-28 07:37:28 +01:00
Vulkan ray tracing: trace only visible reflections, sun shadow from the shadow map, foliage switch and timings
This commit is contained in:
@@ -23,6 +23,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/utilities.h"
|
||||
#include "imgui/imgui.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@@ -323,7 +325,14 @@ void vulkan14_renderer::draw_debug_ui()
|
||||
{
|
||||
ImGui::Checkbox("ray traced reflections where the screen has none (gfx.raytracing)", &m_raytracingon);
|
||||
ImGui::SliderFloat("range of their rays and of the scenery, m (gfx.raytracing.range)", &Global.gfx_raytracing_range, 10.f, 5000.f, "%.0f", ImGuiSliderFlags_Logarithmic);
|
||||
ImGui::Checkbox("alpha tested geometry (foliage) in the traced reflections", &m_rtfoliage);
|
||||
raytracing = m_context->scene.raytracing->info();
|
||||
if (m_raytracingon)
|
||||
{
|
||||
char cpu[96];
|
||||
std::snprintf(cpu, sizeof(cpu), "\nprocessor: walk %.2f ms, build %.2f ms, %zu draws", m_rtwalkms, m_rtbuildms, m_rtdraws.size());
|
||||
raytracing += cpu;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -33,6 +33,8 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "utilities/utilities.h"
|
||||
#include "utilities/color.h"
|
||||
|
||||
#include <chrono>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
@@ -1351,7 +1353,7 @@ void vulkan14_renderer::render_viewport(std::size_t const Index)
|
||||
scene_ubs.shadow_fit = glm::vec4{0.f};
|
||||
// the reflections: the ground below the horizon of the environment map, and the screen space ones set up for the colour pass of
|
||||
// the main view only
|
||||
scene_ubs.env_params = glm::vec4{Global.gfx_ambient_groundalbedo, 0.f, 0.f, 0.f};
|
||||
scene_ubs.env_params = glm::vec4{Global.gfx_ambient_groundalbedo, (m_rtfoliage ? 0.f : 1.f), 0.f, 0.f};
|
||||
gfx::screen_reflections::clear(scene_ubs);
|
||||
|
||||
if (vp.main)
|
||||
@@ -1774,6 +1776,7 @@ void vulkan14_renderer::render_ray_scene(viewport_config &Viewport)
|
||||
{
|
||||
auto &ctx{*m_context};
|
||||
auto &scene{ctx.scene};
|
||||
auto const walkstart{std::chrono::steady_clock::now()};
|
||||
m_rtdraws.clear();
|
||||
m_rtinstances.clear();
|
||||
auto const skipvehicle{m_shadowskipvehicle};
|
||||
@@ -1797,9 +1800,13 @@ void vulkan14_renderer::render_ray_scene(viewport_config &Viewport)
|
||||
m_renderpass = colourpass;
|
||||
setup_matrices();
|
||||
|
||||
auto const buildstart{std::chrono::steady_clock::now()};
|
||||
ctx.passes.begin_pass("ray tracing scene");
|
||||
scene.raytracing->build(ctx.commands, ctx.slot, ctx.uploads.current_value(), m_framestamp, m_rtdraws, ctx.images);
|
||||
ctx.passes.end_pass();
|
||||
auto const buildend{std::chrono::steady_clock::now()};
|
||||
m_rtwalkms += (std::chrono::duration<double, std::milli>(buildstart - walkstart).count() - m_rtwalkms) * 0.05;
|
||||
m_rtbuildms += (std::chrono::duration<double, std::milli>(buildend - buildstart).count() - m_rtbuildms) * 0.05;
|
||||
}
|
||||
|
||||
// a draw of the walk noted for the ray tracing: the chunk with its data on the gpu, the transform, the texture and the colour of the
|
||||
|
||||
@@ -634,7 +634,8 @@ void ray_tracing::build(command_stream *Commands, std::uint32_t const Slot, std:
|
||||
}
|
||||
}
|
||||
instance.instanceCustomIndex = written;
|
||||
instance.mask = 0xFF;
|
||||
// the shaders tell the alpha tested ones by the mask (shaders/vk14/rt_reflections.glsl, RT_MASK_*)
|
||||
instance.mask = (alpha ? 0x02 : 0x01);
|
||||
instance.instanceShaderBindingTableRecordOffset = 0;
|
||||
// the models have faces of one side, seen from both in the reflections; an alpha tested texture leaves holes in its faces
|
||||
instance.flags = VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR | (alpha ? VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR : VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR);
|
||||
|
||||
@@ -281,6 +281,9 @@ class vulkan14_renderer : public gfx_renderer, public gfx::scene_walk
|
||||
void gather_ray_draw(gfx::geometry_handle const &Geometry);
|
||||
bool m_rtgather{false};
|
||||
bool m_raytracingon{true}; // switched off in the debug window
|
||||
bool m_rtfoliage{true}; // the alpha tested geometry in the traced reflections, switched off in the debug window
|
||||
double m_rtwalkms{0.0}; // the processor time of the walk and of the build of the ray tracing, averaged
|
||||
double m_rtbuildms{0.0};
|
||||
std::vector<vk14::ray_draw> m_rtdraws;
|
||||
std::vector<glm::mat4> m_rtinstances; // the modelviews of the instanced draws noted (walk_instances())
|
||||
void render_picking(rendermode const Mode);
|
||||
|
||||
@@ -696,18 +696,21 @@ vec3 reflection_surroundings(vec3 fragnormal, float roughness)
|
||||
#include "rt_reflections.glsl"
|
||||
#endif
|
||||
|
||||
// the least weight of the reflection of the surroundings (its specular colour times its share) a surface traces the scene for
|
||||
// the least weight of the reflection of the surroundings (its specular colour times its share) a surface traces the scene for,
|
||||
// and the least weight of what the screen left to the ray tracing (the weight times the share the screen didn't give) a ray is
|
||||
// traced for: below it the sky and the ground of the environment map do
|
||||
const float REFLECTION_SCENE_WEIGHT = 0.004;
|
||||
const float REFLECTION_RAY_WEIGHT = 0.012;
|
||||
|
||||
// the reflection of the scene in a surface of the given perceptual roughness: the colour times how much of the reflection the
|
||||
// scene gives (rgb), and that share (a), the rest is left to reflection_surroundings()
|
||||
vec4 reflection_scene(vec3 fragnormal, float roughness)
|
||||
vec4 reflection_scene(vec3 fragnormal, float roughness, float weight)
|
||||
{
|
||||
vec3 direction = normalize(reflect(f_pos.xyz, fragnormal));
|
||||
vec4 result = ssr_trace(f_pos.xyz, normalize(f_normal), direction, roughness);
|
||||
#ifdef REFLECTION_RAYS_ACTIVE
|
||||
// what the screen doesn't hold is traced through the scenery (shaders/vk14/rt_reflections.glsl)
|
||||
if ((result.a < 0.99) && (ssr_params2.z > 0.0) && (roughness <= ssr_params.z))
|
||||
if ((weight * (1.0 - result.a) > REFLECTION_RAY_WEIGHT) && (ssr_params2.z > 0.0) && (roughness <= ssr_params.z))
|
||||
{
|
||||
vec4 traced = rt_trace(f_pos.xyz, normalize(f_normal), direction, roughness);
|
||||
result.rgb += traced.rgb * (1.0 - result.a);
|
||||
@@ -801,8 +804,9 @@ vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float ref
|
||||
if (!matte)
|
||||
{
|
||||
envcolor = reflection_surroundings(fragnormal, env_roughness);
|
||||
if (((ssr_params.x > 0.0) || (ssr_params2.z > 0.0)) && (cubemap_share * dot(cubemap_spec, vec3(1.0 / 3.0)) > REFLECTION_SCENE_WEIGHT))
|
||||
scenecolor = reflection_scene(fragnormal, env_roughness);
|
||||
float sceneweight = cubemap_share * dot(cubemap_spec, vec3(1.0 / 3.0));
|
||||
if (((ssr_params.x > 0.0) || (ssr_params2.z > 0.0)) && (sceneweight > REFLECTION_SCENE_WEIGHT))
|
||||
scenecolor = reflection_scene(fragnormal, env_roughness, sceneweight);
|
||||
}
|
||||
|
||||
if (lights_count == 0U)
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
// the rays, GL_EXT_buffer_reference2 and _uvec2 for the vertices read by their device addresses, GL_EXT_nonuniform_qualifier for the
|
||||
// textures picked by the instance hit). what the screen space reflections don't find is traced through the scenery around the camera
|
||||
// the renderer gathered for the frame (the walk of the scene in its reflection mode: the sections, the models and the vehicles within
|
||||
// gfx.raytracing.range, as gfx.reflections.fidelity says), and the point hit is lit by the sky, the sun with a ray of its own towards
|
||||
// it and its own emission. the space of the rays is the world around the camera: the axes of the world, the camera at the origin
|
||||
// gfx.raytracing.range, as gfx.reflections.fidelity says), and the point hit is lit by the sky, the sun (its shadow map where it
|
||||
// holds the point, a ray of its own towards it elsewhere) and its own emission. the space of the rays is the world around the camera: the axes of the world, the camera at the origin
|
||||
|
||||
layout(set = RT_SET, binding = RT_SCENE) uniform accelerationStructureEXT rt_scene;
|
||||
|
||||
@@ -39,6 +39,12 @@ layout(buffer_reference, std430, buffer_reference_align = 4) readonly buffer rt_
|
||||
|
||||
const uint RT_FLAG_ALPHA = 1U;
|
||||
const uint RT_VERTEX_FLOATS = 12U;
|
||||
// the masks of the instances (vk14::ray_tracing): the opaque ones, the alpha tested ones (the foliage). the shadow rays take the
|
||||
// opaque ones only, and the reflections leave out the alpha tested ones when the renderer says so (env_params.y, 1)
|
||||
const uint RT_MASK_OPAQUE = 1U;
|
||||
const uint RT_MASK_ALPHA = 2U;
|
||||
// the longest ray towards the sun from a point hit, metres
|
||||
const float RT_SHADOW_REACH = 100.0;
|
||||
|
||||
// the vertices of a triangle of the record
|
||||
uvec3 rt_triangle(rt_record record, uint primitive)
|
||||
@@ -68,6 +74,49 @@ vec3 rt_normal(rt_record record, uvec3 triangle, vec2 weights)
|
||||
return a * (1.0 - weights.x - weights.y) + b * weights.x + c * weights.y;
|
||||
}
|
||||
|
||||
// the share of the sun reaching a point hit (Hit in the world around the camera, Normal facing the ray): the shadow map of the sun
|
||||
// where it holds the point, which costs no ray, otherwise a ray of its own towards the sun (Sun)
|
||||
float rt_sun_visible(vec3 hit, vec3 normal, vec3 sun, float distance)
|
||||
{
|
||||
if (SHADOWMAP_ENABLED)
|
||||
{
|
||||
mat3 toview = transpose(mat3(inv_view));
|
||||
vec3 position = toview * hit;
|
||||
vec3 viewnormal = toview * normal;
|
||||
float span = dot(position, position);
|
||||
uint cascade;
|
||||
for (cascade = 0U; cascade < MAX_CASCADES; cascade++)
|
||||
if (span <= cascade_end[cascade])
|
||||
break;
|
||||
for (; cascade < MAX_CASCADES; cascade++)
|
||||
{
|
||||
mat4 shadowview = lightview[cascade];
|
||||
// the point pushed off its surface by a texel and a half of the map, as calc_shadow_map() does
|
||||
float texelspermetre = min(length(vec3(shadowview[0][0], shadowview[1][0], shadowview[2][0])), length(vec3(shadowview[0][1], shadowview[1][1], shadowview[2][1]))) *
|
||||
float(textureSize(shadowmap, 0).x);
|
||||
vec4 lightpos = shadowview * vec4(position + viewnormal * (1.5 / max(texelspermetre, 1e-3)), 1.0);
|
||||
vec3 coords = lightpos.xyz / lightpos.w;
|
||||
if (all(greaterThanEqual(coords.xy, vec2(0.0))) && all(lessThanEqual(coords.xy, vec2(1.0))))
|
||||
{
|
||||
if (coords.z < 0.0)
|
||||
return 1.0;
|
||||
return 1.0 - texture(shadowmap, vec4(coords.xy, float(cascade), coords.z + 0.0001 * float(cascade + 1U)));
|
||||
}
|
||||
// the cascades fitted to the depth of the view (gfx.shadow.sdsm) cover the area of the surfaces seen only: a further one may
|
||||
// hold the point
|
||||
if (shadow_fit.x <= 0.0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
rayQueryEXT shadow;
|
||||
rayQueryInitializeEXT(shadow, rt_scene, gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT, RT_MASK_OPAQUE, hit + normal * (0.02 + distance * 0.0005), 0.0, sun,
|
||||
min(ssr_params2.w, RT_SHADOW_REACH));
|
||||
while (rayQueryProceedEXT(shadow))
|
||||
{
|
||||
}
|
||||
return (rayQueryGetIntersectionTypeEXT(shadow, true) == gl_RayQueryCommittedIntersectionNoneEXT ? 1.0 : 0.0);
|
||||
}
|
||||
|
||||
// the reflection the scenery gives, of a surface at Position (view space) with the geometric normal Normal (view space, either side),
|
||||
// for a ray along Direction (view space, normalized) and the perceptual roughness Roughness: the colour (rgb, times a) and whether
|
||||
// the ray hit something (a)
|
||||
@@ -83,7 +132,8 @@ vec4 rt_trace(vec3 position, vec3 normal, vec3 direction, float roughness)
|
||||
vec3 origin = point + face * (0.02 + length(point) * 0.0005);
|
||||
|
||||
rayQueryEXT query;
|
||||
rayQueryInitializeEXT(query, rt_scene, gl_RayFlagsNoneEXT, 0xFF, origin, 0.0, ray, ssr_params2.w);
|
||||
uint mask = ((uint(env_params.y) & 1U) != 0U ? RT_MASK_OPAQUE : (RT_MASK_OPAQUE | RT_MASK_ALPHA));
|
||||
rayQueryInitializeEXT(query, rt_scene, gl_RayFlagsNoneEXT, mask, origin, 0.0, ray, ssr_params2.w);
|
||||
while (rayQueryProceedEXT(query))
|
||||
{
|
||||
// the instances with alpha tested textures aren't opaque: the texture tells whether the triangle is hit there
|
||||
@@ -131,13 +181,9 @@ vec4 rt_trace(vec3 position, vec3 normal, vec3 direction, float roughness)
|
||||
float facing = dot(hitnormal, sun);
|
||||
if (facing > 0.0)
|
||||
{
|
||||
rayQueryEXT shadow;
|
||||
rayQueryInitializeEXT(shadow, rt_scene, gl_RayFlagsTerminateOnFirstHitEXT | gl_RayFlagsOpaqueEXT, 0xFF, hit + hitnormal * (0.02 + distance * 0.0005), 0.0, sun, ssr_params2.w);
|
||||
while (rayQueryProceedEXT(shadow))
|
||||
{
|
||||
}
|
||||
if (rayQueryGetIntersectionTypeEXT(shadow, true) == gl_RayQueryCommittedIntersectionNoneEXT)
|
||||
light += lights[0].color * (SUN_DIFFUSE_SCALE * lights[0].intensity * cloud_shadow(hit) * pow(facing, SUN_NDOTL_SHARPNESS));
|
||||
float visible = rt_sun_visible(hit, hitnormal, sun, distance);
|
||||
if (visible > 0.0)
|
||||
light += lights[0].color * (SUN_DIFFUSE_SCALE * lights[0].intensity * visible * cloud_shadow(hit) * pow(facing, SUN_NDOTL_SHARPNESS));
|
||||
}
|
||||
}
|
||||
vec3 color = albedo * (light + vec3(record.glow));
|
||||
|
||||
Reference in New Issue
Block a user