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:
commit
84babdfff8
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*/));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,9 +103,8 @@ void traceSimpleBlending(vec3 pos, vec3 dir, float L, inout vec3 emissive, inout
|
|||
#endif // !DEBUG_BLEND_MODES
|
||||
}
|
||||
|
||||
if (entries_count == 0)
|
||||
return;
|
||||
|
||||
float revealage = 1.;
|
||||
if (entries_count > 0) {
|
||||
// Tyno O(N^2) sort
|
||||
for (uint i = 0; i < entries_count; ++i) {
|
||||
uint min_i = i;
|
||||
|
@ -104,15 +121,13 @@ void traceSimpleBlending(vec3 pos, vec3 dir, float L, inout vec3 emissive, inout
|
|||
}
|
||||
|
||||
// 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;
|
||||
emissive += 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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
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];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue