Skip to content

Commit a52f31f

Browse files
authored
Instanced Decals (#6813)
* prepare instancing * Render single decal with instance-like buffer * encode per-instance data in the instance matrix * Actually render decals instanced * Update todo commit * actually add stubs * Gate decal preparation behind GPU capability flag * Fix MSVC warnigns * remove explicit layout * Fix MSVC warnigns 2 * Clang Tidy
1 parent 62c8260 commit a52f31f

17 files changed

Lines changed: 215 additions & 157 deletions

code/decals/decals.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,11 @@ void initializeMission() {
370370
active_decals.clear();
371371
}
372372

373-
matrix4 getDecalTransform(Decal& decal) {
373+
// Discard any fragments where the angle to the direction to greater than 45°
374+
const float DECAL_ANGLE_CUTOFF = fl_radians(45.f);
375+
const float DECAL_ANGLE_FADE_START = fl_radians(30.f);
376+
377+
static matrix4 getDecalTransform(Decal& decal, float alpha) {
374378
Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!");
375379

376380
auto objp = decal.object.objp();
@@ -405,11 +409,17 @@ matrix4 getDecalTransform(Decal& decal) {
405409
matrix4 mat4;
406410
vm_matrix4_set_transform(&mat4, &worldOrient, &worldPos);
407411

412+
// This is currently a constant but in the future this may be configurable by the decals table
413+
mat4.a2d[0][3] = DECAL_ANGLE_CUTOFF;
414+
mat4.a2d[1][3] = DECAL_ANGLE_FADE_START;
415+
416+
mat4.a2d[2][3] = alpha;
417+
408418
return mat4;
409419
}
410420

411421
void renderAll() {
412-
if (!Decal_system_active || !Decal_option_active) {
422+
if (!Decal_system_active || !Decal_option_active || !gr_is_capable(gr_capability::CAPABILITY_INSTANCED_RENDERING)) {
413423
return;
414424
}
415425

@@ -438,7 +448,7 @@ void renderAll() {
438448

439449
auto mission_time = f2fl(Missiontime);
440450

441-
graphics::decal_draw_list draw_list(active_decals.size());
451+
graphics::decal_draw_list draw_list;
442452
for (auto& decal : active_decals) {
443453

444454
Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int)DecalDefinitions.size(),
@@ -473,7 +483,7 @@ void renderAll() {
473483
+ bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping());
474484
}
475485

476-
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal), alpha);
486+
draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha));
477487
}
478488

479489
draw_list.render();

code/def_files/data/effects/decal-f.sdr

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ out vec4 fragOut0; // Diffuse buffer
1010
out vec4 fragOut1; // Normal buffer
1111
out vec4 fragOut2; // Emissive buffer
1212

13+
in flat mat4 invModelMatrix;
14+
in flat vec3 decalDirection;
15+
in flat float normal_angle_cutoff;
16+
in flat float angle_fade_start;
17+
in flat float alpha_scale;
18+
1319
uniform sampler2D gDepthBuffer;
1420
uniform sampler2D gNormalBuffer;
1521

@@ -24,23 +30,17 @@ layout (std140) uniform decalGlobalData {
2430
mat4 invProjMatrix;
2531

2632
vec3 ambientLight;
33+
float pad0;
2734

2835
vec2 viewportSize;
2936
};
30-
layout (std140) uniform decalInfoData {
31-
mat4 model_matrix;
32-
mat4 inv_model_matrix;
33-
34-
vec3 decal_direction;
35-
float normal_angle_cutoff;
3637

38+
layout (std140) uniform decalInfoData {
3739
int diffuse_index;
3840
int glow_index;
3941
int normal_index;
40-
float angle_fade_start;
41-
42-
float alpha_scale;
4342
int diffuse_blend_mode;
43+
4444
int glow_blend_mode;
4545
};
4646

@@ -77,7 +77,7 @@ vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out v
7777
#endif
7878

7979
//Calculate angle between surface normal and decal direction
80-
float angle = acos(dot(normal, decal_direction));
80+
float angle = acos(dot(normal, decalDirection));
8181

8282
if (angle > normal_angle_cutoff) {
8383
// The angle between surface normal and decal direction is too big
@@ -91,7 +91,7 @@ vec3 getPixelNormal(vec3 frag_position, vec2 tex_coord, inout float alpha, out v
9191
}
9292

9393
vec2 getDecalTexCoord(vec3 view_pos, inout float alpha) {
94-
vec4 object_pos = inv_model_matrix * invViewMatrix * vec4(view_pos, 1.0);
94+
vec4 object_pos = invModelMatrix * invViewMatrix * vec4(view_pos, 1.0);
9595

9696
bvec3 invalidComponents = greaterThan(abs(object_pos.xyz), vec3(0.5));
9797
bvec4 nanComponents = isnan(object_pos); // nan can happen some times if we have an infinite depth value
@@ -111,6 +111,7 @@ void main() {
111111
vec3 frag_position = computeViewPosition(gl_FragCoord.xy);
112112

113113
float alpha = alpha_scale;
114+
114115
vec2 tex_coord = getDecalTexCoord(frag_position, alpha);
115116

116117
vec3 binormal;
Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11

22
in vec4 vertPosition;
3+
in mat4 vertModelMatrix;
4+
5+
out flat mat4 invModelMatrix;
6+
out flat vec3 decalDirection;
7+
out flat float normal_angle_cutoff;
8+
out flat float angle_fade_start;
9+
out flat float alpha_scale;
310

411
layout (std140) uniform decalGlobalData {
512
mat4 viewMatrix;
@@ -8,26 +15,31 @@ layout (std140) uniform decalGlobalData {
815
mat4 invProjMatrix;
916

1017
vec3 ambientLight;
18+
float pad0;
1119

1220
vec2 viewportSize;
1321
};
14-
layout (std140) uniform decalInfoData {
15-
mat4 model_matrix;
16-
mat4 inv_model_matrix;
17-
18-
vec3 decal_direction;
19-
float normal_angle_cutoff;
2022

23+
layout (std140) uniform decalInfoData {
2124
int diffuse_index;
2225
int glow_index;
2326
int normal_index;
24-
float angle_fade_start;
25-
26-
float alpha_scale;
2727
int diffuse_blend_mode;
28+
2829
int glow_blend_mode;
2930
};
3031

3132
void main() {
32-
gl_Position = projMatrix * viewMatrix * model_matrix * vertPosition;
33+
normal_angle_cutoff = vertModelMatrix[0][3];
34+
angle_fade_start = vertModelMatrix[1][3];
35+
alpha_scale = vertModelMatrix[2][3];
36+
37+
mat4 modelMatrix = vertModelMatrix;
38+
modelMatrix[0][3] = 0.0;
39+
modelMatrix[1][3] = 0.0;
40+
modelMatrix[2][3] = 0.0;
41+
42+
invModelMatrix = inverse(modelMatrix);
43+
decalDirection = mat3(viewMatrix) * vec3(modelMatrix[0][2], modelMatrix[1][2], modelMatrix[2][2]);
44+
gl_Position = projMatrix * viewMatrix * modelMatrix * vertPosition;
3345
}

code/graphics/2d.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ gr_capability_def gr_capabilities[] = {
7979
GR_CAPABILITY_ENTRY(SEPARATE_BLEND_FUNCTIONS),
8080
GR_CAPABILITY_ENTRY(PERSISTENT_BUFFER_MAPPING),
8181
gr_capability_def {gr_capability::CAPABILITY_BPTC, "BPTC Texture Compression"}, //This one had a different parse string already!
82-
GR_CAPABILITY_ENTRY(LARGE_SHADER)
82+
GR_CAPABILITY_ENTRY(LARGE_SHADER),
83+
GR_CAPABILITY_ENTRY(INSTANCED_RENDERING),
8384
};
8485

8586
const size_t gr_capabilities_num = sizeof(gr_capabilities) / sizeof(gr_capabilities[0]);
@@ -3072,7 +3073,7 @@ size_t hash<vertex_layout>::operator()(const vertex_layout& data) const {
30723073
bool vertex_layout::resident_vertex_format(vertex_format_data::vertex_format format_type) const {
30733074
return ( Vertex_mask & vertex_format_data::mask(format_type) ) ? true : false;
30743075
}
3075-
void vertex_layout::add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset) {
3076+
void vertex_layout::add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset, size_t divisor, size_t buffer_number ) {
30763077
// A stride value of 0 is not handled consistently by the graphics API so we must enforce that that does not happen
30773078
Assertion(stride != 0, "The stride of a vertex component may not be zero!");
30783079

@@ -3081,15 +3082,16 @@ void vertex_layout::add_vertex_component(vertex_format_data::vertex_format forma
30813082
return;
30823083
}
30833084

3084-
if (Vertex_mask == 0) {
3085+
auto stride_it = Vertex_stride.find(buffer_number);
3086+
if (stride_it == Vertex_stride.end()) {
30853087
// This is the first element so we need to initialize the global stride here
3086-
Vertex_stride = stride;
3088+
stride_it = Vertex_stride.emplace(buffer_number, stride).first;
30873089
}
30883090

3089-
Assertion(Vertex_stride == stride, "The strides of all elements must be the same in a vertex layout!");
3091+
Assertion(stride_it->second == stride, "The strides of all elements must be the same in a vertex layout!");
30903092

30913093
Vertex_mask |= (1 << format_type);
3092-
Vertex_components.push_back(vertex_format_data(format_type, stride, offset));
3094+
Vertex_components.emplace_back(format_type, stride, offset, divisor, buffer_number);
30933095
}
30943096
bool vertex_layout::operator==(const vertex_layout& other) const {
30953097
if (Vertex_mask != other.Vertex_mask) {

code/graphics/2d.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,14 +271,17 @@ struct vertex_format_data
271271
MODEL_ID,
272272
RADIUS,
273273
UVEC,
274+
MATRIX4,
274275
};
275276

276277
vertex_format format_type;
277278
size_t stride;
278279
size_t offset;
280+
size_t divisor;
281+
size_t buffer_number;
279282

280-
vertex_format_data(vertex_format i_format_type, size_t i_stride, size_t i_offset) :
281-
format_type(i_format_type), stride(i_stride), offset(i_offset) {}
283+
vertex_format_data(vertex_format i_format_type, size_t i_stride, size_t i_offset, size_t i_divisor, size_t i_buffer_number) :
284+
format_type(i_format_type), stride(i_stride), offset(i_offset), divisor(i_divisor), buffer_number(i_buffer_number) {}
282285

283286
static inline uint mask(vertex_format v_format) { return 1 << v_format; }
284287

@@ -291,7 +294,7 @@ class vertex_layout
291294
SCP_vector<vertex_format_data> Vertex_components;
292295

293296
uint Vertex_mask = 0;
294-
size_t Vertex_stride = 0;
297+
SCP_unordered_map<size_t, size_t> Vertex_stride;
295298
public:
296299
vertex_layout() {}
297300

@@ -301,9 +304,9 @@ class vertex_layout
301304

302305
bool resident_vertex_format(vertex_format_data::vertex_format format_type) const;
303306

304-
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset);
307+
void add_vertex_component(vertex_format_data::vertex_format format_type, size_t stride, size_t offset, size_t divisor = 0, size_t buffer_number = 0);
305308

306-
size_t get_vertex_stride() const { return Vertex_stride; }
309+
size_t get_vertex_stride(size_t buffer_number = 0) const { return Vertex_stride.at(buffer_number); }
307310

308311
bool operator==(const vertex_layout& other) const;
309312

@@ -333,7 +336,8 @@ enum class gr_capability {
333336
CAPABILITY_SEPARATE_BLEND_FUNCTIONS,
334337
CAPABILITY_PERSISTENT_BUFFER_MAPPING,
335338
CAPABILITY_BPTC,
336-
CAPABILITY_LARGE_SHADER
339+
CAPABILITY_LARGE_SHADER,
340+
CAPABILITY_INSTANCED_RENDERING
337341
};
338342

339343
struct gr_capability_def {
@@ -891,7 +895,9 @@ typedef struct screen {
891895
primitive_type prim_type,
892896
vertex_layout* layout,
893897
int num_elements,
894-
const indexed_vertex_source& buffers)>
898+
const indexed_vertex_source& buffers,
899+
const gr_buffer_handle& instance_buffer,
900+
int num_instances)>
895901
gf_render_decals;
896902
void (*gf_render_rocket_primitives)(interface_material* material_info,
897903
primitive_type prim_type,

0 commit comments

Comments
 (0)