rtx: sample mip levels based on ray cone width

this is mostly copied from ray tracing gems 2 chapter 7 (Texture Coordinate Gradients Estimation for Ray Cones, by Wessam Bahnassi).
There's a weird bit about radians vs degrees. We'll figure it out later when the book becomes available.
This commit is contained in:
Ivan Avdeev 2021-08-04 18:36:53 -07:00
parent 71bf85d4f8
commit 94ac51a527
9 changed files with 69 additions and 9 deletions

View File

@ -1,5 +1,7 @@
## 2021-08-02..04, E122-123
- [x] mipmaps
# Next
- [ ] mipmaps
- [ ] rtx: split ray tracing into modules: pipeline mgmt, buffer mgmt
- [ ] rtx: better light culling: normal, bsp visibility, light volumes and intensity, sort by intensity, etc
- [ ] rtx: cluster dlights
@ -10,6 +12,8 @@
- [ ] studio models: fix lighting: should have white texture instead of lightmap OR we could write nearest surface lightmap coords to fake light
# Planned
- [ ] rtx: better mip lods: there's a weird math that operates on fov degrees (not radians) that we copypasted from ray tracing gems 2 chapter 7. When the book is available, get through the math and figure this out.
- [ ] sane texture memory management: do not allocate VKDeviceMemory for every texture
- [ ] rtx: transparency layering issue, possible approaches:
- [ ] trace a special transparent-only ray separately from opaque. This can at least be used to remove black texture areas
- [ ] rtx: sky light/emissive skybox:

View File

@ -17,6 +17,32 @@ vec3 hashUintToVec3(uint i) { return vec3(hash(float(i)), hash(float(i)+15.43),
const float normal_offset_fudge = .01;
// Taken from Ray Tracing Gems II, Chapter 7. Texture Coordinate Gradients Estimation for Ray Cones, by Wessam Bahnassi
// https://www.realtimerendering.com/raytracinggems/rtg2/index.html
// https://github.com/Apress/Ray-Tracing-Gems-II/blob/main/Chapter_07/Raytracing.hlsl
vec4 UVDerivsFromRayCone(vec3 vRayDir, vec3 vWorldNormal, float vRayConeWidth, vec2 aUV[3], vec3 aPos[3], mat3 matWorld)
{
vec2 vUV10 = aUV[1]-aUV[0];
vec2 vUV20 = aUV[2]-aUV[0];
float fQuadUVArea = abs(vUV10.x*vUV20.y - vUV20.x*vUV10.y);
// Since the ray cone's width is in world-space, we need to compute the quad
// area in world-space as well to enable proper ratio calculation
vec3 vEdge10 = (aPos[1]-aPos[0]) * matWorld;
vec3 vEdge20 = (aPos[2]-aPos[0]) * matWorld;
vec3 vFaceNrm = cross(vEdge10, vEdge20);
float fQuadArea = length(vFaceNrm);
float fDistTerm = abs(vRayConeWidth);
float fNormalTerm = abs(dot(vRayDir,vWorldNormal));
float fProjectedConeWidth = vRayConeWidth/fNormalTerm;
float fVisibleAreaRatio = (fProjectedConeWidth*fProjectedConeWidth) / fQuadArea;
float fVisibleUVArea = fQuadUVArea*fVisibleAreaRatio;
float fULength = sqrt(fVisibleUVArea);
return vec4(fULength,0,0,fULength);
}
void main() {
//const float l = gl_HitTEXT;
//ray_result.color = vec3(fract(l / 10.));
@ -25,6 +51,8 @@ void main() {
//ray_result.color = vec3(.5);
vec3 hit_pos = gl_WorldRayOriginEXT + gl_WorldRayDirectionEXT * gl_HitTEXT;
payload.t_offset += gl_HitTEXT;
// ray_result.color = fract((hit_pos + .5) / 10.);
//ray_result.color = vec3(1.);
//return;
@ -43,14 +71,28 @@ void main() {
const vec3 n3 = vertices[vi3].normal;
// TODO use already inverse gl_WorldToObject ?
const vec3 normal = normalize(transpose(inverse(mat3(gl_ObjectToWorldEXT))) * (n1 * (1. - bary.x - bary.y) + n2 * bary.x + n3 * bary.y));
const mat3 matWorld = mat3(gl_ObjectToWorldEXT);
const vec3 normal = normalize(transpose(inverse(matWorld)) * (n1 * (1. - bary.x - bary.y) + n2 * bary.x + n3 * bary.y));
hit_pos += normal * normal_offset_fudge;
// //C = normal * .5 + .5; break;
const vec2 uvs[3] = {
vertices[vi1].gl_tc,
vertices[vi2].gl_tc,
vertices[vi3].gl_tc,
};
const vec3 pos[3] = {
vertices[vi1].pos,
vertices[vi2].pos,
vertices[vi3].pos,
};
const vec2 texture_uv = vertices[vi1].gl_tc * (1. - bary.x - bary.y) + vertices[vi2].gl_tc * bary.x + vertices[vi3].gl_tc * bary.y;
const uint tex_index = kusochki[kusok_index].texture;
const vec3 base_color = pow(texture(textures[nonuniformEXT(tex_index)], texture_uv).rgb, vec3(2.));
const float ray_cone_width = payload.pixel_cone_spread_angle * payload.t_offset;
const vec4 uv_lods = UVDerivsFromRayCone(gl_WorldRayDirectionEXT, normal, ray_cone_width, uvs, pos, matWorld);
const vec3 base_color = pow(textureGrad(textures[nonuniformEXT(tex_index)], texture_uv, uv_lods.xy, uv_lods.zw).rgb, vec3(2.));
payload.hit_pos_t = vec4(hit_pos, gl_HitTEXT);
payload.albedo = base_color;

View File

@ -74,6 +74,7 @@ layout (push_constant) uniform PushConstants {
uint random_seed;
int bounces;
float prev_frame_blend_factor;
float pixel_cone_spread_angle;
} push_constants;
// TODO find better random function
@ -281,6 +282,9 @@ void main() {
vec3 kc = vec3(1.);
vec3 C = vec3(0.);
payload.t_offset = .0;
payload.pixel_cone_spread_angle = push_constants.pixel_cone_spread_angle;
for (int bounce = 0; bounce < push_constants.bounces; ++bounce) {
const uint flags = 0
| gl_RayFlagsCullFrontFacingTrianglesEXT
@ -293,7 +297,7 @@ void main() {
const float L = 10000.;
traceRayEXT(tlas, flags, 0xff,
sbt_offset, sbt_stride, miss_index,
origin, .001, direction, L,
origin, 0., direction, L,
ray_payload_loc);
if (payload.hit_pos_t.w <= 0.) {

View File

@ -1,5 +1,6 @@
#extension GL_EXT_ray_tracing: require
struct RayPayload {
float t_offset, pixel_cone_spread_angle;
vec4 hit_pos_t;
vec3 albedo;
vec3 normal;

View File

@ -53,6 +53,8 @@ static struct {
vec3_t origin, color;
} static_lights[32];
int num_static_lights;
float fov_angle_y;
} g_render;
static qboolean createPipelines( void )
@ -516,10 +518,11 @@ static const matrix4x4 vk_proj_fixup = {
{0, 0, 0, 1}
};
void VK_RenderStateSetMatrixProjection(const matrix4x4 projection)
void VK_RenderStateSetMatrixProjection(const matrix4x4 projection, float fov_angle_y)
{
g_render_state.uniform_data_set_mask |= UNIFORM_SET_MATRIX_PROJECTION;
Matrix4x4_Concat( g_render_state.projection, vk_proj_fixup, projection );
g_render.fov_angle_y = fov_angle_y;
}
void VK_RenderStateSetMatrixView(const matrix4x4 view)
@ -794,6 +797,8 @@ void VK_RenderEndRTX( VkCommandBuffer cmdbuf, VkImageView img_dst_view, VkImage
.buffer = g_render.buffer.buffer,
.size = VK_WHOLE_SIZE,
},
.fov_angle_y = g_render.fov_angle_y,
};
if (args.ubo.offset == UINT32_MAX) {

View File

@ -48,7 +48,7 @@ void VK_RenderBufferPrintStats( void );
void VK_RenderStateSetColor( float r, float g, float b, float a );
// TODO void VK_RenderStateGetColor( vec4_t color );
void VK_RenderStateSetMatrixProjection(const matrix4x4 proj);
void VK_RenderStateSetMatrixProjection(const matrix4x4 proj, float fov_angle_y);
void VK_RenderStateSetMatrixView(const matrix4x4 view);
void VK_RenderStateSetMatrixModel(const matrix4x4 model);

View File

@ -42,6 +42,7 @@ typedef struct {
uint32_t random_seed;
int bounces;
float prev_frame_blend_factor;
float pixel_cone_spread_angle;
} vk_rtx_push_constants_t;
typedef struct {
@ -575,7 +576,7 @@ static void updateDescriptors( VkCommandBuffer cmdbuf, const vk_ray_frame_render
VK_DescriptorsWrite(&g_rtx.descriptors);
}
static qboolean rayTrace( VkCommandBuffer cmdbuf, VkImage frame_dst )
static qboolean rayTrace( VkCommandBuffer cmdbuf, VkImage frame_dst, float fov_angle_y )
{
// 4. Barrier for TLAS build and dest image layout transfer
{
@ -613,6 +614,7 @@ static qboolean rayTrace( VkCommandBuffer cmdbuf, VkImage frame_dst )
.random_seed = (uint32_t)gEngine.COM_RandomLong(0, INT32_MAX),
.bounces = vk_rtx_bounces->value,
.prev_frame_blend_factor = vk_rtx_prev_frame_blend_factor->value,
.pixel_cone_spread_angle = atanf((2.0f*tanf(fov_angle_y * 0.5f)) / (float)FRAME_HEIGHT),
};
vkCmdPushConstants(cmdbuf, g_rtx.descriptors.pipeline_layout, VK_SHADER_STAGE_RAYGEN_BIT_KHR, 0, sizeof(push_constants), &push_constants);
}
@ -788,7 +790,7 @@ void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args)
} else {
prepareTlas(cmdbuf);
updateDescriptors(cmdbuf, args, frame_src, frame_dst);
rayTrace(cmdbuf, frame_dst->image);
rayTrace(cmdbuf, frame_dst->image, args->fov_angle_y);
// Barrier for frame_dst image
{

View File

@ -45,6 +45,8 @@ typedef struct {
VkBuffer buffer; // must be the same as in vk_ray_model_create_t TODO: validate or make impossible to specify incorrectly
uint32_t size;
} geometry_data;
float fov_angle_y;
} vk_ray_frame_render_args_t;
void VK_RayFrameEnd(const vk_ray_frame_render_args_t* args);

View File

@ -657,7 +657,7 @@ void VK_SceneRender( const ref_viewpass_t *rvp )
setupCamera( rvp );
VK_RenderStateSetMatrixProjection( g_camera.projectionMatrix );
VK_RenderStateSetMatrixProjection( g_camera.projectionMatrix, g_camera.fov_y ); // FIXME why is this in degrees, not in radians? * M_PI_F / 360.0f );
VK_RenderStateSetMatrixView( g_camera.modelviewMatrix );
VK_RenderStateSetMatrixModel( matrix4x4_identity );