Merge pull request #719 from w23/stream-E352

Stuff done during streams E352-E354

- [x] tune emissive/additive blending so that it matches original, fixes #668
- [x] make additive studio and brush models single-sided, fixes #665
- [x] convert override_color (from TriApi) to linear space together with gamma
- [x] apply soft-alpha-depth universally, fixes #722
This commit is contained in:
Ivan Avdeev 2023-12-29 09:17:36 -08:00 committed by GitHub
commit 84babdfff8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 220 additions and 45 deletions

View File

@ -1079,3 +1079,78 @@ xash vk (remapped)
+Y = -X
+X = +Z
+Z = +Y
# 2023-12-22 E352
## sRGB vs γ blending
Original:
`color = a + b`
Our:
`color = sqrt(a*a + b*b)`
There's nothing we can to do `a` only that would make it fake the "original" mixing result.
# 2023-12-28 E353
## Passing colors from all over the place into `trace_simple_blending.glsl`
- color = mm_color * texture_color * geom.vertex_color * alpha
- alpha = mm_color.a * texture_color.a * geom.vertex_color.a
- mm_color = model.color * kusok.material.base_color
- model.color -- already linearized
- kusok.material.base_color = mat->base_color * override_color
- mat->base_color -- specified in .mat files by hand
- [x] Which colorspace should it be specified in?
Currently it is passed in as is, which means that it's accidentally linear.
- override_color -- passed from the engine through `R_RenderDrawOnce()`, called from triapi
- [x] sRGB-γ, should linearize
- texture_color -- just texture sampled color. sRGB-γ vs linear is specified at VkImageView level at loading time
- geom.vertex_color -- barycentric-lerped from vk_vertex[].color
- vk_vertex[].color -- rgba8
- [x] which colorspace? Should be sRGB-γ originally
- [x] Do we need to linearize it? YES
- [x] Before lerping or after? BEFORE -- already done
- Should α be converted from gamma to linear?
- Doing so:
- seems kinda logical -- everything is gamma-space in engine, so it probably should be.
- fixes some 'background' sprites transparency
- makes too-brighs c0a0c beams darker (but kinda too dark imo)
- breaks sprite animation lerping -- now we need 2 native gamma-to-linear functions, wich alpha conv and w/o
As usual -- original sRGB-specialized game art is painfully incompatible with modern linear PBR.
The best way to address it (hopefully w/o breaking too much linear rendering math) remains to be discovered.
# 2023-12-29 E354
## Sprite animation lerping woes
Problem: converting alpha from sRGB to linear fixes various blending glitches, but makes animation blink.
Possible approaches:
1. Original math: pass and compute colors and alphas for simple blending in the original (sRGB-γ) colorspace. PBR-incorrect, but should give the original look.
Pro:
- original look
- should solve a whole class of issues.
- Relatively separate from physically-correct math, doesn't interfere that much.
Except for background + emissive part.
- Individual PRB-ized parts of blending could be extracted out from legacy mode gradually.
Cons:
- special legacy blending code.
- Passing these things around is obnoxious: needs lots of special code for model passing.
- Large amount of work.
Possible implementation plan:
- `vk_ray_model.c`: sRGB-to-linear colorspace conversion should be made based on `material_mode`:
do not convert for legacy blending modes
- what to do with `mat->base_color`, which is assumed linear? Leaving it as-is for now.
- sRGB-γ-ize linear texture color (still a bit different from legacy. alt: specifically for sprites and beams textures mark them as UNORM)
- keep/lerp vertex colors in sRGB space
2. Special code for sprite lerping: add second texture channel, add lerp parameter, etc.
Pro: should be relatively easy to do.
Cons: Fragile special code for special case.
3. Track alpha channel with animation lerping in mind: only linearize it for no-animation case.
Pro: no additional parameters to pass to shaders.
Cons: math might not converge on a good solution.
4. Generate intermediate textures.
Pro: no special code for shaders/model passing.
Cons: ridiculous texture explosion
5. Hand-patch things that look weird. E.g. for known sprite/beam textures specify how their alphas should be mapped.

View File

@ -1,3 +1,11 @@
# 2023-12-29 E354
- [x] Figure out why additive transparency differs visibly from raster
- [x] Implement special legacy-blending in sRGB-γ colorspace
# 2023-12-28 E353
- [x] track color spaces when passing colors into shaders
- [-] validation failure at startup, #723 -- seems like memory corruption
Longer-term agenda for current season:
- [ ] Better PBR math, e.g.:
- [ ] Black metals: https://github.com/w23/xash3d-fwgs/issues/666
@ -5,13 +13,12 @@ Longer-term agenda for current season:
- [ ] Just make sure that all the BRDF math is correct
- [ ] Transparency/translucency:
- [ ] Proper material mode for translucency, with reflections, refraction (index), fresnel, etc.
- [ ] Figure out why additive transparency differs visibly from raster
- [ ] Extract and specialize effects, e.g.
- [ ] Rays -> volumetrics
- [ ] Glow -> bloom
- [ ] Smoke -> volumetrics
- [ ] Sprites/portals -> emissive volumetrics
- [ ] Holo models -> emissive additive
- [x] Holo models -> emissive additive
- [ ] Some additive -> translucent
- [ ] what else
- [ ] Render-graph-ish approach to resources.

View File

@ -178,9 +178,8 @@ void computeBounce(ivec2 pix, vec3 direction, out vec3 diffuse, out vec3 specula
vec3 background = payload.base_color_a.rgb * ldiffuse;
background += lspecular * mix(vec3(1.), payload.base_color_a.rgb, hit_material.metalness);
vec3 emissive = vec3(0.);
traceSimpleBlending(pos, bounce_direction, payload.hit_t.w, emissive, background);
lighting = emissive + background;
const vec4 blend = traceLegacyBlending(pos, bounce_direction, payload.hit_t.w);
lighting = SRGBtoLINEAR(blend.rgb) + background * blend.a;
} else {
lighting = texture(skybox, bounce_direction).rgb * ubo.ubo.skybox_exposure;
//payload.emissive.rgb = texture(skybox, bounce_direction).rgb * ubo.ubo.skybox_exposure;

View File

@ -42,7 +42,9 @@ layout(set = 0, binding = 18) uniform sampler3D blue_noise_texture;
#include "bluenoise.glsl"
#endif
//layout(set = 0, binding = 19) uniform sampler2D textures[MAX_TEXTURES];
layout(set = 0, binding = 19, rgba16f) uniform readonly image2D legacy_blend;
//layout(set = 0, binding = 20) uniform sampler2D textures[MAX_TEXTURES];
const int INDIRECT_SCALE = 2;
@ -306,8 +308,19 @@ void main() {
colour = diffuse + specular;
}
const vec4 legacy_blend = imageLoad(legacy_blend, pix);
colour += imageLoad(emissive, pix).rgb;
// Revealage. TODO: which colorspace?
colour *= legacy_blend.a;
colour = LINEARtoSRGB(colour);
// See issue https://github.com/w23/xash3d-fwgs/issues/668, map test_blendmode_additive_alpha.
// Adding emissive_blend to the final color in the *incorrect* sRGB-γ space. It makes
// it look much more like the original. Adding emissive in the *correct* linear space differs
// from the original a lot, and looks perceptively worse.
colour += legacy_blend.rgb;
imageStore(out_dest, pix, vec4(colour, 0./*unused*/));
}

View File

@ -23,6 +23,7 @@ layout(set = 0, binding = 12, rgba16f) uniform writeonly image2D out_normals_gs;
layout(set = 0, binding = 13, rgba8) uniform writeonly image2D out_material_rmxx;
layout(set = 0, binding = 14, rgba16f) uniform writeonly image2D out_emissive;
layout(set = 0, binding = 15, rgba32f) uniform writeonly image2D out_geometry_prev_position;
layout(set = 0, binding = 16, rgba16f) uniform writeonly image2D out_legacy_blend;
layout(set = 0, binding = 30, std430) readonly buffer ModelHeaders { ModelHeader a[]; } model_headers;
layout(set = 0, binding = 31, std430) readonly buffer Kusochki { Kusok a[]; } kusochki;
@ -118,7 +119,8 @@ void main() {
payload.emissive.rgb = texture(skybox, ray.direction).rgb * ubo.ubo.skybox_exposure;
}
traceSimpleBlending(ray.origin, ray.direction, L, payload.emissive.rgb, payload.base_color_a.rgb);
const vec4 blend = traceLegacyBlending(ray.origin, ray.direction, L);
imageStore(out_legacy_blend, pix, blend);
imageStore(out_position_t, pix, payload.hit_t);
imageStore(out_base_color_a, pix, LINEARtoSRGB(payload.base_color_a));

View File

@ -134,7 +134,7 @@ Geometry readHitGeometry(vec2 bary, float ray_cone_width) {
struct MiniGeometry {
vec2 uv;
uint kusok_index;
vec4 vertex_color;
vec4 vertex_color_srgb;
};
MiniGeometry readCandidateMiniGeometry(rayQueryEXT rq) {
@ -156,16 +156,23 @@ MiniGeometry readCandidateMiniGeometry(rayQueryEXT rq) {
const vec2 bary = rayQueryGetIntersectionBarycentricsEXT(rq, false);
const vec2 uv = baryMix(uvs[0], uvs[1], uvs[2], bary);
/*
const vec4 colors[3] = {
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi1).color)),
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi2).color)),
SRGBtoLINEAR(unpackUnorm4x8(GET_VERTEX(vi3).color)),
};
*/
const vec4 colors_srgb[3] = {
unpackUnorm4x8(GET_VERTEX(vi1).color),
unpackUnorm4x8(GET_VERTEX(vi2).color),
unpackUnorm4x8(GET_VERTEX(vi3).color),
};
MiniGeometry ret;
ret.uv = uv;
ret.kusok_index = kusok_index;
ret.vertex_color = baryMix(colors[0], colors[1], colors[2], bary);
ret.vertex_color_srgb = baryMix(colors_srgb[0], colors_srgb[1], colors_srgb[2], bary);
return ret;
}
#endif // #ifdef RAY_QUERY

View File

@ -2,8 +2,11 @@
#define TRACE_SIMPLE_BLENDING_GLSL_INCLUDED
// Traces geometry with simple blending. Simple means that it's only additive or mix/coverage, and it doesn't participate in lighting, and it doesn't reflect/refract rays.
void traceSimpleBlending(vec3 pos, vec3 dir, float L, inout vec3 emissive, inout vec3 background) {
// Done in sRGB-γ space for legacy-look reasons.
// Returns vec4(emissive_srgb.rgb, revealage)
vec4 traceLegacyBlending(vec3 pos, vec3 dir, float L) {
const float glow_soft_overshoot = 16.;
vec3 emissive = vec3(0.);
// TODO probably a better way would be to sort only MIX entries.
// ADD/GLOW are order-independent relative to each other, but not to MIX
@ -32,14 +35,20 @@ void traceSimpleBlending(vec3 pos, vec3 dir, float L, inout vec3 emissive, inout
const Kusok kusok = getKusok(geom.kusok_index);
const float hit_t = rayQueryGetIntersectionTEXT(rq, false);
const float overshoot = hit_t - L;
// Use soft alpha depth effect globally, not only for glow
#define GLOBAL_SOFT_DEPTH
#ifndef GLOBAL_SOFT_DEPTH
if (overshoot > 0. && model.mode != MATERIAL_MODE_BLEND_GLOW)
continue;
#endif
//#define DEBUG_BLEND_MODES
#ifdef DEBUG_BLEND_MODES
if (model.mode == MATERIAL_MODE_BLEND_GLOW) {
emissive += vec3(1., 0., 0.);
//ret += color * smoothstep(glow_soft_overshoot, 0., overshoot);
//emissive += color * smoothstep(glow_soft_overshoot, 0., overshoot);
} else if (model.mode == MATERIAL_MODE_BLEND_ADD) {
emissive += vec3(0., 1., 0.);
} else if (model.mode == MATERIAL_MODE_BLEND_MIX) {
@ -50,15 +59,24 @@ void traceSimpleBlending(vec3 pos, vec3 dir, float L, inout vec3 emissive, inout
emissive += vec3(1., 1., 1.);
}
#else
const vec4 texture_color = texture(textures[nonuniformEXT(kusok.material.tex_base_color)], geom.uv);
// Note that simple blending is legacy blending really.
// It is done in sRGB-γ space for correct legacy-look reasons.
const vec4 texture_color = LINEARtoSRGB(texture(textures[nonuniformEXT(kusok.material.tex_base_color)], geom.uv));
const vec4 mm_color = model.color * kusok.material.base_color;
float alpha = mm_color.a * texture_color.a * geom.vertex_color.a;
vec3 color = mm_color.rgb * texture_color.rgb * geom.vertex_color.rgb * alpha;
float alpha = mm_color.a * texture_color.a * geom.vertex_color_srgb.a;
vec3 color = mm_color.rgb * texture_color.rgb * geom.vertex_color_srgb.rgb * alpha;
#ifdef GLOBAL_SOFT_DEPTH
const float overshoot_factor = smoothstep(glow_soft_overshoot, 0., overshoot);
color *= overshoot_factor;
#endif
if (model.mode == MATERIAL_MODE_BLEND_GLOW) {
// Glow is additive + small overshoot
#ifndef GLOBAL_SOFT_DEPTH
const float overshoot_factor = smoothstep(glow_soft_overshoot, 0., overshoot);
color *= overshoot_factor;
#endif
alpha = 0.;
} else if (model.mode == MATERIAL_MODE_BLEND_ADD) {
// Additive doesn't attenuate what's behind
@ -85,34 +103,31 @@ void traceSimpleBlending(vec3 pos, vec3 dir, float L, inout vec3 emissive, inout
#endif // !DEBUG_BLEND_MODES
}
if (entries_count == 0)
return;
// Tyno O(N^2) sort
for (uint i = 0; i < entries_count; ++i) {
uint min_i = i;
for (uint j = i+1; j < entries_count; ++j) {
if (entries[min_i].depth > entries[j].depth) {
min_i = j;
float revealage = 1.;
if (entries_count > 0) {
// Tyno O(N^2) sort
for (uint i = 0; i < entries_count; ++i) {
uint min_i = i;
for (uint j = i+1; j < entries_count; ++j) {
if (entries[min_i].depth > entries[j].depth) {
min_i = j;
}
}
if (min_i != i) {
BlendEntry tmp = entries[min_i];
entries[min_i] = entries[i];
entries[i] = tmp;
}
}
if (min_i != i) {
BlendEntry tmp = entries[min_i];
entries[min_i] = entries[i];
entries[i] = tmp;
// Composite everything in the right order
for (uint i = 0; i < entries_count; ++i) {
emissive += entries[i].add * revealage;
revealage *= 1. - entries[i].blend;
}
}
// Composite everything in the right order
float revealage = 1.;
vec3 add = vec3(0.);
for (uint i = 0; i < entries_count; ++i) {
add += entries[i].add * revealage;
revealage *= 1. - entries[i].blend;
}
emissive = emissive * revealage + add;
background *= revealage;
return vec4(emissive, revealage);
}
#endif //ifndef TRACE_SIMPLE_BLENDING_GLSL_INCLUDED

View File

@ -700,6 +700,7 @@ static void brushDrawWater(r_brush_water_model_t *wmodel, const cl_entity_t *ent
R_RenderModelDraw(&wmodel->render_model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
.material_flags = kMaterialFlag_None,
.color = (const vec4_t*)color,
.transform = (const matrix4x4*)transform,
.prev_transform = (const matrix4x4*)prev_transform,
@ -829,6 +830,7 @@ void R_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, con
vec4_t color = {1, 1, 1, 1};
vk_render_type_e render_type = kVkRenderTypeSolid;
uint32_t material_flags = kMaterialFlag_None;
switch (render_mode) {
case kRenderNormal:
Vector4Set(color, 1.f, 1.f, 1.f, 1.f);
@ -845,6 +847,7 @@ void R_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, con
case kRenderTransAdd:
Vector4Set(color, blend, blend, blend, 1.f);
render_type = kVkRenderType_A_1_R;
material_flags |= kMaterialFlag_CullBackFace_Bit;
break;
case kRenderTransAlpha:
if( gEngine.EngineGetParm( PARM_QUAKE_COMPATIBLE, 0 ))
@ -949,6 +952,7 @@ void R_BrushModelDraw( const cl_entity_t *ent, int render_mode, float blend, con
R_RenderModelDraw(&bmodel->render_model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
.material_flags = material_flags,
.color = &color,
.transform = &transform,
.prev_transform = &bmodel->prev_transform,

View File

@ -270,13 +270,16 @@ vk_resource_t RT_VkAccelPrepareTlas(vk_combuf_t *combuf) {
.instanceShaderBindingTableRecordOffset = 0,
.accelerationStructureReference = instance->blas_addr,
};
const VkGeometryInstanceFlagsKHR flags = (instance->material_flags & kMaterialFlag_CullBackFace_Bit) ? 0 : VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
switch (instance->material_mode) {
case MATERIAL_MODE_OPAQUE:
inst[i].mask = GEOMETRY_BIT_OPAQUE;
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
// Force no-culling because there are cases where culling leads to leaking shadows, holes in reflections, etc
// CULL_DISABLE_BIT disables culling even if the gl_RayFlagsCullFrontFacingTrianglesEXT bit is set in shaders
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR | VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR | flags;
break;
case MATERIAL_MODE_OPAQUE_ALPHA_TEST:
inst[i].mask = GEOMETRY_BIT_ALPHA_TEST;
@ -287,7 +290,7 @@ vk_resource_t RT_VkAccelPrepareTlas(vk_combuf_t *combuf) {
inst[i].mask = GEOMETRY_BIT_REFRACTIVE;
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_REGULAR,
// Disable culling for translucent surfaces: decide what side it is based on normal wrt ray directions
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR | VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_OPAQUE_BIT_KHR | flags;
break;
case MATERIAL_MODE_BLEND_ADD:
case MATERIAL_MODE_BLEND_MIX:
@ -295,7 +298,7 @@ vk_resource_t RT_VkAccelPrepareTlas(vk_combuf_t *combuf) {
inst[i].mask = GEOMETRY_BIT_BLEND;
inst[i].instanceShaderBindingTableRecordOffset = SHADER_OFFSET_HIT_ADDITIVE,
// Force no-culling because these should be visible from any angle
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR | VK_GEOMETRY_INSTANCE_TRIANGLE_FACING_CULL_DISABLE_BIT_KHR;
inst[i].flags = VK_GEOMETRY_INSTANCE_FORCE_NO_OPAQUE_BIT_KHR | flags;
break;
default:
gEngine.Host_Error("Unexpected material mode %d\n", instance->material_mode);

View File

@ -20,6 +20,7 @@ typedef struct rt_draw_instance_s {
matrix4x4 prev_transform_row;
vec4_t color;
uint32_t material_mode; // MATERIAL_MODE_ from ray_interop.h
uint32_t material_flags; // material_flag_bits_e
} rt_draw_instance_t;
typedef struct {

View File

@ -323,6 +323,17 @@ rt_draw_instance_t *getDrawInstance(void) {
return g_ray_model_state.frame.instances + (g_ray_model_state.frame.instances_count++);
}
static qboolean isLegacyBlendingMode(int material_mode) {
switch (material_mode) {
case MATERIAL_MODE_BLEND_ADD:
case MATERIAL_MODE_BLEND_MIX:
case MATERIAL_MODE_BLEND_GLOW:
return true;
default:
return false;
}
}
static float sRGBtoLinearScalar(const float sRGB) {
// IEC 61966-2-1:1999
const float linearLow = sRGB / 12.92f;
@ -334,9 +345,24 @@ static void sRGBtoLinearVec4(const vec4_t in, vec4_t out) {
out[0] = sRGBtoLinearScalar(in[0]);
out[1] = sRGBtoLinearScalar(in[1]);
out[2] = sRGBtoLinearScalar(in[2]);
// Historically: sprite animation lerping is linear
// To-linear conversion should not be done on anything with blending, therefore
// it's irrelevant really.
out[3] = in[3];
}
/*
static void sRGBAtoLinearVec4(const vec4_t in, vec4_t out) {
out[0] = sRGBtoLinearScalar(in[0]);
out[1] = sRGBtoLinearScalar(in[1]);
out[2] = sRGBtoLinearScalar(in[2]);
// α also needs to be linearized for tau-cannon hit position sprite to look okay
out[3] = sRGBtoLinearScalar(in[3]);
}
*/
void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args ) {
if (!model || !model->blas)
return;
@ -361,7 +387,14 @@ void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args ) {
draw_instance->blas_addr = model->blas_addr;
draw_instance->kusochki_offset = kusochki_offset;
draw_instance->material_mode = args.material_mode;
sRGBtoLinearVec4(*args.color_srgb, draw_instance->color);
draw_instance->material_flags = args.material_flags;
// Legacy blending is done in sRGB-γ space
if (isLegacyBlendingMode(args.material_mode))
Vector4Copy(*args.color_srgb, draw_instance->color);
else
sRGBtoLinearVec4(*args.color_srgb, draw_instance->color);
Matrix3x4_Copy(draw_instance->transform_row, args.transform);
Matrix4x4_Copy(draw_instance->prev_transform_row, args.prev_transform);
}
@ -435,7 +468,6 @@ void RT_DynamicModelProcessFrame(void) {
goto tail;
}
// FIXME override color
if (!RT_KusochkiUpload(kusochki_offset, dyn->geometries, dyn->geometries_count, NULL, dyn->colors)) {
gEngine.Con_Printf(S_ERROR "Couldn't build blas for %d geoms of %s, skipping\n", dyn->geometries_count, group_names[i]);
goto tail;
@ -453,6 +485,7 @@ void RT_DynamicModelProcessFrame(void) {
draw_instance->blas_addr = dyn->blas_addr;
draw_instance->kusochki_offset = kusochki_offset;
draw_instance->material_mode = i;
draw_instance->material_flags = 0;
Vector4Set(draw_instance->color, 1, 1, 1, 1);
Matrix3x4_LoadIdentity(draw_instance->transform_row);
Matrix4x4_LoadIdentity(draw_instance->prev_transform_row);
@ -474,7 +507,12 @@ void RT_FrameAddOnce( rt_frame_add_once_t args ) {
break;
}
Vector4Copy(*args.color, dyn->colors[dyn->geometries_count]);
// Legacy blending is done in sRGB-γ space
if (isLegacyBlendingMode(material_mode))
Vector4Copy(*args.color_srgb, dyn->colors[dyn->geometries_count]);
else
sRGBtoLinearVec4(*args.color_srgb, dyn->colors[dyn->geometries_count]);
dyn->geometries[dyn->geometries_count++] = args.geometries[i];
}
}

View File

@ -791,6 +791,7 @@ void R_RenderModelDraw(const vk_render_model_t *model, r_model_draw_t args) {
ASSERT(model->rt_model);
RT_FrameAddModel(model->rt_model, (rt_frame_add_model_t){
.material_mode = args.material_mode,
.material_flags = args.material_flags,
.transform = (const matrix3x4*)args.transform,
.prev_transform = (const matrix3x4*)args.prev_transform,
.color_srgb = args.color,
@ -843,7 +844,7 @@ void R_RenderDrawOnce(r_draw_once_t args) {
RT_FrameAddOnce((rt_frame_add_once_t){
.debug_name = args.name,
.geometries = &geometry,
.color = args.color,
.color_srgb = args.color,
.geometries_count = 1,
.render_type = args.render_type,
});

View File

@ -123,9 +123,15 @@ void R_RenderModelDestroy( vk_render_model_t* model );
qboolean R_RenderModelUpdate( const vk_render_model_t *model );
qboolean R_RenderModelUpdateMaterials( const vk_render_model_t *model, const int *geom_indices, int geom_indices_count);
typedef enum {
kMaterialFlag_None = 0,
kMaterialFlag_CullBackFace_Bit = (1<<0),
} material_flag_bits_e;
typedef struct {
vk_render_type_e render_type; // TODO rename legacy
material_mode_e material_mode;
uint32_t material_flags; // material_flag_bits_e
// These are "consumed": copied into internal storage and can be pointers to stack vars
const vec4_t *color;

View File

@ -58,6 +58,8 @@ qboolean RT_ModelUpdateMaterials(struct rt_model_s *model, const struct vk_rende
typedef struct {
int material_mode;
uint32_t material_flags;
const matrix3x4 *transform, *prev_transform;
const vec4_t *color_srgb;
@ -76,7 +78,7 @@ void RT_FrameAddModel( struct rt_model_s *model, rt_frame_add_model_t args );
typedef struct {
const char *debug_name;
const struct vk_render_geometry_s *geometries;
const vec4_t *color;
const vec4_t *color_srgb;
int geometries_count;
int render_type;
} rt_frame_add_once_t;

View File

@ -808,6 +808,7 @@ static void R_DrawSpriteQuad( const char *debug_name, const mspriteframe_t *fram
R_RenderModelDraw(&g_sprite.quad.model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
.material_flags = kMaterialFlag_None,
.color = (const vec4_t*)color,
.transform = &transform,
.prev_transform = &transform,

View File

@ -2331,6 +2331,7 @@ static void R_StudioDrawPoints( void ) {
R_RenderModelDraw(&render_submodel->model, (r_model_draw_t){
.render_type = render_type,
.material_mode = material_mode,
.material_flags = kMaterialFlag_CullBackFace_Bit, // TODO for transparent only?
.color = &color,
.transform = &g_studio_current.entmodel->transform,
.prev_transform = &g_studio_current.entmodel->prev_transform,