From 14f062138b06d330cd7c7c025f43b19ef5c0fd24 Mon Sep 17 00:00:00 2001 From: Ivan 'provod' Avdeev Date: Mon, 24 Apr 2023 10:44:01 -0700 Subject: [PATCH] rt: group Material and ModelMetadata in Kusok They have mismatching frequencies. ModelMetadata should be per-Model, there should be only a few dozen of these. There maybe hundreds (or even thousands) of materials, but one material can be still referenced by many kusochki. This only moves fields into new structs, which still belong to Kusok. The real extraction will happen later, see #52. --- ref/vk/shaders/additive.rahit | 28 ++++++++------- ref/vk/shaders/alphamask.rahit | 2 +- ref/vk/shaders/bounce.comp | 2 +- ref/vk/shaders/light_common.glsl | 4 +-- ref/vk/shaders/ray_common_alphatest.rahit | 2 +- ref/vk/shaders/ray_interop.h | 44 ++++++++++++++++------- ref/vk/shaders/ray_primary.comp | 2 +- ref/vk/shaders/ray_primary.rchit | 11 +++--- ref/vk/shaders/ray_primary_hit.glsl | 15 ++++---- ref/vk/shaders/ray_shadow.rchit | 5 +-- ref/vk/shaders/rt_geometry.glsl | 6 ++-- ref/vk/shaders/trace_additive.glsl | 6 ++-- ref/vk/vk_ray_model.c | 41 ++++++++++----------- 13 files changed, 92 insertions(+), 76 deletions(-) diff --git a/ref/vk/shaders/additive.rahit b/ref/vk/shaders/additive.rahit index 973074c145..f66331256e 100644 --- a/ref/vk/shaders/additive.rahit +++ b/ref/vk/shaders/additive.rahit @@ -16,19 +16,21 @@ layout(location = PAYLOAD_LOCATION_ADDITIVE) rayPayloadInEXT RayPayloadAdditive hitAttributeEXT vec2 bary; void main() { - const int instance_kusochki_offset = gl_InstanceCustomIndexEXT; - const int kusok_index = instance_kusochki_offset + gl_GeometryIndexEXT; - const uint first_index_offset = getKusok(kusok_index).index_offset + gl_PrimitiveID * 3; - - const uint vi1 = uint(getIndex(first_index_offset+0)) + getKusok(kusok_index).vertex_offset; - const uint vi2 = uint(getIndex(first_index_offset+1)) + getKusok(kusok_index).vertex_offset; - const uint vi3 = uint(getIndex(first_index_offset+2)) + getKusok(kusok_index).vertex_offset; - - const vec2 texture_uv = GET_VERTEX(vi1).gl_tc * (1. - bary.x - bary.y) + GET_VERTEX(vi2).gl_tc * bary.x + GET_VERTEX(vi3).gl_tc * bary.y + push_constants.time * getKusok(kusok_index).uv_speed; - // TODO mips - const uint tex_index = getKusok(kusok_index).tex_base_color; - const vec4 texture_color = texture(textures[nonuniformEXT(tex_index)], texture_uv); - const vec3 color = texture_color.rgb * getKusok(kusok_index).color.rgb * texture_color.a * getKusok(kusok_index).color.a; + const int instance_kusochki_offset = gl_InstanceCustomIndexEXT; + const int kusok_index = instance_kusochki_offset + gl_GeometryIndexEXT; + const uint first_index_offset = getKusok(kusok_index).index_offset + gl_PrimitiveID * 3; + + const uint vi1 = uint(getIndex(first_index_offset+0)) + getKusok(kusok_index).vertex_offset; + const uint vi2 = uint(getIndex(first_index_offset+1)) + getKusok(kusok_index).vertex_offset; + const uint vi3 = uint(getIndex(first_index_offset+2)) + getKusok(kusok_index).vertex_offset; + + const vec2 texture_uv = GET_VERTEX(vi1).gl_tc * (1. - bary.x - bary.y) + GET_VERTEX(vi2).gl_tc * bary.x + GET_VERTEX(vi3).gl_tc * bary.y; + + const Kusok kusok = getKusok(kusok_index); + // TODO mips + const uint tex_index = kusok.material.tex_base_color; + const vec4 texture_color = texture(textures[nonuniformEXT(tex_index)], texture_uv); + const vec3 color = texture_color.rgb * kusok.model.color.rgb * texture_color.a * kusok.model.color.a; const float overshoot = gl_HitTEXT - payload_additive.ray_distance; diff --git a/ref/vk/shaders/alphamask.rahit b/ref/vk/shaders/alphamask.rahit index 59ae5a46d8..9d7df1df9d 100644 --- a/ref/vk/shaders/alphamask.rahit +++ b/ref/vk/shaders/alphamask.rahit @@ -19,7 +19,7 @@ void main() { const uint vi3 = uint(getIndex(first_index_offset+2)) + getKusok(kusok_index).vertex_offset; const vec2 texture_uv = GET_VERTEX(vi1).gl_tc * (1. - bary.x - bary.y) + GET_VERTEX(vi2).gl_tc * bary.x + GET_VERTEX(vi3).gl_tc * bary.y; - const uint tex_index = getKusok(kusok_index).tex_base_color; + const uint tex_index = getKusok(kusok_index).material.tex_base_color; const vec4 texture_color = texture(textures[nonuniformEXT(tex_index)], texture_uv); if (texture_color.a < 0.1) { diff --git a/ref/vk/shaders/bounce.comp b/ref/vk/shaders/bounce.comp index f4e0573ac0..bc19245c66 100644 --- a/ref/vk/shaders/bounce.comp +++ b/ref/vk/shaders/bounce.comp @@ -71,7 +71,7 @@ bool getHit(vec3 origin, vec3 direction, inout RayPayloadPrimary payload) { // Separate pass could be more efficient as it'd be doing the same thing for every invocation. // 2. Same as the above, but also with a completely independent TLAS. Why: no need to mask-check geometry for opaque-vs-alpha const MiniGeometry geom = readCandidateMiniGeometry(rq); - const uint tex_base_color = getKusok(geom.kusok_index).tex_base_color; + const uint tex_base_color = getKusok(geom.kusok_index).material.tex_base_color; const vec4 texture_color = texture(textures[nonuniformEXT(tex_base_color)], geom.uv); const float alpha_mask_threshold = .1f; diff --git a/ref/vk/shaders/light_common.glsl b/ref/vk/shaders/light_common.glsl index 4b740193fd..81d6cf18b5 100644 --- a/ref/vk/shaders/light_common.glsl +++ b/ref/vk/shaders/light_common.glsl @@ -63,7 +63,7 @@ bool shadowTestAlphaMask(vec3 pos, vec3 dir, float dist) { }; const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false); const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary); - const vec4 texture_color = texture(textures[nonuniformEXT(kusok.tex_base_color)], uv); + const vec4 texture_color = texture(textures[nonuniformEXT(kusok.material.tex_base_color)], uv); const float alpha_mask_threshold = .1f; if (texture_color.a >= alpha_mask_threshold) { @@ -141,7 +141,7 @@ bool shadowedSky(vec3 pos, vec3 dir) { const Kusok kusok = getKusok(kusok_index); // TODO this flag can be encoded into custom index, so that we'd need no extra indirection - if ((kusok.flags & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) + if ((kusok.material.flags & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) return true; } diff --git a/ref/vk/shaders/ray_common_alphatest.rahit b/ref/vk/shaders/ray_common_alphatest.rahit index c6f92d18cd..45632bbac4 100644 --- a/ref/vk/shaders/ray_common_alphatest.rahit +++ b/ref/vk/shaders/ray_common_alphatest.rahit @@ -21,7 +21,7 @@ const float alpha_mask_threshold = .1f; void main() { const Geometry geom = readHitGeometry(bary, ubo.ubo.ray_cone_width); - const uint tex_index = getKusok(geom.kusok_index).tex_base_color; + const uint tex_index = getKusok(geom.kusok_index).material.tex_base_color; const vec4 texture_color = texture(textures[nonuniformEXT(tex_index)], geom.uv); if (texture_color.a < alpha_mask_threshold) { diff --git a/ref/vk/shaders/ray_interop.h b/ref/vk/shaders/ray_interop.h index c6ad0bb516..51ad42824e 100644 --- a/ref/vk/shaders/ray_interop.h +++ b/ref/vk/shaders/ray_interop.h @@ -66,33 +66,51 @@ LIST_SPECIALIZATION_CONSTANTS(DECLARE_SPECIALIZATION_CONSTANT) #define KUSOK_MATERIAL_FLAG_SKYBOX (1<<0) #define KUSOK_MATERIAL_FLAG_FIXME_GLOW (1<<1) -struct Kusok { - uint index_offset; - uint vertex_offset; - uint triangles; +struct Material { + uint flags; - // Material uint tex_base_color; - // TODO the color is per-model, not per-kusok - vec4 color; - - vec3 emissive; + // TODO can be combined into a single texture uint tex_roughness; - - vec2 uv_speed; // for conveyors; TODO this can definitely be done in software more efficiently (there only a handful of these per map) uint tex_metalness; uint tex_normalmap; + // TODO: + // uint tex_emissive; + // uint tex_detail; + float roughness; float metalness; float normal_scale; - uint flags; +}; - // TODO per-model +struct ModelMetadata { + vec4 color; mat4 prev_transform; }; +struct Kusok { + // Geometry data + uint index_offset; + uint vertex_offset; + uint triangles; + + // material below consists of scalar fields only, so it's not aligned to vec4. + // Alignt it here to vec4 explicitly, so that later vector fields are properly aligned (for simplicity). + uint _padding0; + + // TODO reference into material table + STRUCT Material material; + + // Per-kusok because individual surfaces can be patched + vec3 emissive; + PAD(1) + + // TODO move into a separate model array, and reference it by gl_GeometryIndexEXT/rayQueryGetIntersectionGeometryIndexEXT + STRUCT ModelMetadata model; +}; + struct PointLight { vec4 origin_r; vec4 color_stopdot; diff --git a/ref/vk/shaders/ray_primary.comp b/ref/vk/shaders/ray_primary.comp index f2e0c230e8..2cf07cfd23 100644 --- a/ref/vk/shaders/ray_primary.comp +++ b/ref/vk/shaders/ray_primary.comp @@ -86,7 +86,7 @@ void main() { // Separate pass could be more efficient as it'd be doing the same thing for every invocation. // 2. Same as the above, but also with a completely independent TLAS. Why: no need to mask-check geometry for opaque-vs-alpha const MiniGeometry geom = readCandidateMiniGeometry(rq); - const uint tex_base_color = getKusok(geom.kusok_index).tex_base_color; + const uint tex_base_color = getKusok(geom.kusok_index).material.tex_base_color; const vec4 texture_color = texture(textures[nonuniformEXT(tex_base_color)], geom.uv); const float alpha_mask_threshold = .1f; diff --git a/ref/vk/shaders/ray_primary.rchit b/ref/vk/shaders/ray_primary.rchit index 69402c6a08..b8123dd1f4 100644 --- a/ref/vk/shaders/ray_primary.rchit +++ b/ref/vk/shaders/ray_primary.rchit @@ -28,17 +28,16 @@ void main() { payload.prev_pos_t = vec4(geom.prev_pos, 0.); const Kusok kusok = getKusok(geom.kusok_index); - const uint tex_base_color = kusok.tex_base_color; - if ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) { + if ((kusok.material.flags & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) { payload.emissive.rgb = SRGBtoLINEAR(texture(skybox, gl_WorldRayDirectionEXT).rgb); return; } else { - payload.base_color_a = sampleTexture(tex_base_color, geom.uv, geom.uv_lods) * kusok.color; - payload.material_rmxx.r = (kusok.tex_roughness > 0) ? sampleTexture(kusok.tex_roughness, geom.uv, geom.uv_lods).r : kusok.roughness; - payload.material_rmxx.g = (kusok.tex_metalness > 0) ? sampleTexture(kusok.tex_metalness, geom.uv, geom.uv_lods).r : kusok.metalness; + payload.base_color_a = sampleTexture(kusok.material.tex_base_color, geom.uv, geom.uv_lods) * kusok.model.color; + payload.material_rmxx.r = sampleTexture(kusok.material.tex_roughness, geom.uv, geom.uv_lods).r * kusok.material.roughness; + payload.material_rmxx.g = sampleTexture(kusok.material.tex_metalness, geom.uv, geom.uv_lods).r * kusok.material.metalness; - const uint tex_normal = kusok.tex_normalmap; + const uint tex_normal = kusok.material.tex_normalmap; vec3 T = geom.tangent; if (tex_normal > 0 && dot(T,T) > .5) { T = normalize(T - dot(T, geom.normal_shading) * geom.normal_shading); diff --git a/ref/vk/shaders/ray_primary_hit.glsl b/ref/vk/shaders/ray_primary_hit.glsl index aa9d118d6b..feb579fa41 100644 --- a/ref/vk/shaders/ray_primary_hit.glsl +++ b/ref/vk/shaders/ray_primary_hit.glsl @@ -28,24 +28,25 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) { payload.prev_pos_t = vec4(geom.prev_pos, 0.); const Kusok kusok = getKusok(geom.kusok_index); + const Material material = kusok.material; - if ((kusok.flags & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) { + if ((kusok.material.flags & KUSOK_MATERIAL_FLAG_SKYBOX) != 0) { payload.emissive.rgb = SRGBtoLINEAR(texture(skybox, rayDirection).rgb); return; } else { - payload.base_color_a = sampleTexture(kusok.tex_base_color, geom.uv, geom.uv_lods); - payload.material_rmxx.r = sampleTexture(kusok.tex_roughness, geom.uv, geom.uv_lods).r * kusok.roughness; - payload.material_rmxx.g = sampleTexture(kusok.tex_metalness, geom.uv, geom.uv_lods).r * kusok.metalness; + payload.base_color_a = sampleTexture(material.tex_base_color, geom.uv, geom.uv_lods); + payload.material_rmxx.r = sampleTexture(material.tex_roughness, geom.uv, geom.uv_lods).r * material.roughness; + payload.material_rmxx.g = sampleTexture(material.tex_metalness, geom.uv, geom.uv_lods).r * material.metalness; #ifndef RAY_BOUNCE - const uint tex_normal = kusok.tex_normalmap; + const uint tex_normal = material.tex_normalmap; vec3 T = geom.tangent; if (tex_normal > 0 && dot(T,T) > .5) { T = normalize(T - dot(T, geom.normal_shading) * geom.normal_shading); const vec3 B = normalize(cross(geom.normal_shading, T)); const mat3 TBN = mat3(T, B, geom.normal_shading); vec3 tnorm = sampleTexture(tex_normal, geom.uv, geom.uv_lods).xyz * 2. - 1.; // TODO is this sampling correct for normal data? - tnorm.xy *= kusok.normal_scale; + tnorm.xy *= material.normal_scale; tnorm.z = sqrt(max(0., 1. - dot(tnorm.xy, tnorm.xy))); geom.normal_shading = normalize(TBN * tnorm); } @@ -68,7 +69,7 @@ void primaryRayHit(rayQueryEXT rq, inout RayPayloadPrimary payload) { payload.emissive.rgb = payload.base_color_a.rgb; #endif - payload.base_color_a *= kusok.color; + payload.base_color_a *= kusok.model.color; } #endif // ifndef RAY_PRIMARY_HIT_GLSL_INCLUDED diff --git a/ref/vk/shaders/ray_shadow.rchit b/ref/vk/shaders/ray_shadow.rchit index 8823e99836..bc4da1adc0 100644 --- a/ref/vk/shaders/ray_shadow.rchit +++ b/ref/vk/shaders/ray_shadow.rchit @@ -9,7 +9,8 @@ layout(location = PAYLOAD_LOCATION_SHADOW) rayPayloadInEXT RayPayloadShadow payl void main() { const int instance_kusochki_offset = gl_InstanceCustomIndexEXT; const int kusok_index = instance_kusochki_offset + gl_GeometryIndexEXT; - const uint tex_base_color = getKusok(kusok_index).tex_base_color; + const Kusok kusok = getKusok(kusok_index); + const uint tex_base_color = kusok.material.tex_base_color; - payload_shadow.hit_type = ((tex_base_color & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) ? SHADOW_HIT : SHADOW_SKY ; + payload_shadow.hit_type = ((kusok.material.flags & KUSOK_MATERIAL_FLAG_SKYBOX) == 0) ? SHADOW_HIT : SHADOW_SKY ; } diff --git a/ref/vk/shaders/rt_geometry.glsl b/ref/vk/shaders/rt_geometry.glsl index c2274f8139..643b6fcde7 100644 --- a/ref/vk/shaders/rt_geometry.glsl +++ b/ref/vk/shaders/rt_geometry.glsl @@ -89,9 +89,9 @@ Geometry readHitGeometry(vec2 bary, float ray_cone_width) { }; const vec3 prev_pos[3] = { - (kusok.prev_transform * vec4(GET_VERTEX(vi1).prev_pos, 1.f)).xyz, - (kusok.prev_transform * vec4(GET_VERTEX(vi2).prev_pos, 1.f)).xyz, - (kusok.prev_transform * vec4(GET_VERTEX(vi3).prev_pos, 1.f)).xyz, + (kusok.model.prev_transform * vec4(GET_VERTEX(vi1).prev_pos, 1.f)).xyz, + (kusok.model.prev_transform * vec4(GET_VERTEX(vi2).prev_pos, 1.f)).xyz, + (kusok.model.prev_transform * vec4(GET_VERTEX(vi3).prev_pos, 1.f)).xyz, }; const vec2 uvs[3] = { diff --git a/ref/vk/shaders/trace_additive.glsl b/ref/vk/shaders/trace_additive.glsl index 13b2a922f3..831d03949d 100644 --- a/ref/vk/shaders/trace_additive.glsl +++ b/ref/vk/shaders/trace_additive.glsl @@ -15,15 +15,15 @@ vec3 traceAdditive(vec3 pos, vec3 dir, float L) { const MiniGeometry geom = readCandidateMiniGeometry(rq); const Kusok kusok = getKusok(geom.kusok_index); - const vec4 texture_color = texture(textures[nonuniformEXT(kusok.tex_base_color)], geom.uv); - const vec3 color = texture_color.rgb * kusok.emissive * texture_color.a * kusok.color.a * SRGBtoLINEAR(geom.color.rgb * geom.color.a); + const vec4 texture_color = texture(textures[nonuniformEXT(kusok.material.tex_base_color)], geom.uv); + const vec3 color = texture_color.rgb * kusok.emissive * texture_color.a * kusok.model.color.a * SRGBtoLINEAR(geom.color.rgb * geom.color.a); const float hit_t = rayQueryGetIntersectionTEXT(rq, false); const float overshoot = hit_t - L; if (overshoot < 0.) ret += color; - else if ((kusok.flags & KUSOK_MATERIAL_FLAG_FIXME_GLOW) != 0) + else if ((kusok.material.flags & KUSOK_MATERIAL_FLAG_FIXME_GLOW) != 0) ret += color * smoothstep(additive_soft_overshoot, 0., overshoot); } return ret; diff --git a/ref/vk/vk_ray_model.c b/ref/vk/vk_ray_model.c index fd3679b66b..376ff21b2f 100644 --- a/ref/vk/vk_ray_model.c +++ b/ref/vk/vk_ray_model.c @@ -138,7 +138,7 @@ void XVK_RayModel_Validate( void ) { for (int j = 0; j < num_geoms; j++) { const vk_kusok_data_t *kusok = kusochki + j; - const vk_texture_t *tex = findTexture(kusok->tex_base_color); + const vk_texture_t *tex = findTexture(kusok->material.tex_base_color); ASSERT(tex); ASSERT(tex->vk.image.view != VK_NULL_HANDLE); @@ -165,30 +165,32 @@ static void applyMaterialToKusok(vk_kusok_data_t* kusok, const vk_render_geometr kusok->index_offset = geom->index_offset; kusok->triangles = geom->element_count / 3; - kusok->tex_base_color = mat->tex_base_color; - kusok->tex_roughness = mat->tex_roughness; - kusok->tex_metalness = mat->tex_metalness; - kusok->tex_normalmap = mat->tex_normalmap; + kusok->material = (struct Material){ + .flags = 0, - kusok->roughness = mat->roughness; - kusok->metalness = mat->metalness; - kusok->normal_scale = mat->normal_scale; + .tex_base_color = mat->tex_base_color, + .tex_roughness = mat->tex_roughness, + .tex_metalness = mat->tex_metalness, + .tex_normalmap = mat->tex_normalmap, - kusok->flags = 0; + .roughness = mat->roughness, + .metalness = mat->metalness, + .normal_scale = mat->normal_scale, + }; // HACK until there is a proper mechanism for patching materials, see https://github.com/w23/xash3d-fwgs/issues/213 // FIXME also this erases previous roughness unconditionally if (HACK_reflective) { - kusok->tex_roughness = tglob.blackTexture; + kusok->material.tex_roughness = tglob.blackTexture; } else if (!mat->set && geom->material == kXVkMaterialChrome) { - kusok->tex_roughness = tglob.grayTexture; + kusok->material.tex_roughness = tglob.grayTexture; } if (geom->material == kXVkMaterialSky) - kusok->flags |= KUSOK_MATERIAL_FLAG_SKYBOX; + kusok->material.flags |= KUSOK_MATERIAL_FLAG_SKYBOX; if (geom->material == kXVkMaterialEmissiveGlow) - kusok->flags |= KUSOK_MATERIAL_FLAG_FIXME_GLOW; + kusok->material.flags |= KUSOK_MATERIAL_FLAG_FIXME_GLOW; { vec4_t gcolor; @@ -196,17 +198,10 @@ static void applyMaterialToKusok(vk_kusok_data_t* kusok, const vk_render_geometr gcolor[1] = color[1] * mat->base_color[1]; gcolor[2] = color[2] * mat->base_color[2]; gcolor[3] = color[3] * mat->base_color[3]; - Vector4Copy(gcolor, kusok->color); + Vector4Copy(gcolor, kusok->model.color); } VectorCopy(geom->emissive, kusok->emissive); - -/* FIXME these should be done in a different way - if (geom->material == kXVkMaterialConveyor) { - computeConveyorSpeed( entcolor, geom->texture, kusok->uv_speed ); - } else */ { - kusok->uv_speed[0] = kusok->uv_speed[1] = 0.f; - } } vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) { @@ -277,7 +272,7 @@ vk_ray_model_t* VK_RayModelCreate( vk_ray_model_init_t args ) { }; applyMaterialToKusok(kusochki + i, mg, args.model->color, false); - Matrix4x4_LoadIdentity(kusochki[i].prev_transform); + Matrix4x4_LoadIdentity(kusochki[i].model.prev_transform); } R_VkStagingUnlock(kusok_staging.handle); @@ -475,7 +470,7 @@ void VK_RayFrameAddModel( vk_ray_model_t *model, const vk_render_model_t *render applyMaterialToKusok(kusochki + i, geom, render_model->color, HACK_reflective); - Matrix4x4_ToArrayFloatGL(render_model->prev_transform, (float*)(kusochki + i)->prev_transform); + Matrix4x4_ToArrayFloatGL(render_model->prev_transform, (float*)(kusochki + i)->model.prev_transform); } /* gEngine.Con_Reportf("model %s: geom=%d kuoffs=%d kustoff=%d kustsz=%d sthndl=%d\n", */