Merge pull request #80618 from DarioSamo/skeleton-motion-vectors

Add motion vector support for animated surfaces
This commit is contained in:
Rémi Verschelde 2023-08-17 11:26:40 +02:00
commit 04306777a7
No known key found for this signature in database
GPG Key ID: C3336907360768E1
6 changed files with 201 additions and 71 deletions

View File

@ -433,10 +433,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p
RID index_array_rd;
//skeleton and blend shape
bool pipeline_motion_vectors = pipeline_color_pass_flags & SceneShaderForwardClustered::PIPELINE_COLOR_PASS_FLAG_MOTION_VECTORS;
if (surf->owner->mesh_instance.is_valid()) {
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), pipeline_motion_vectors, vertex_array_rd, vertex_format);
} else {
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), pipeline_motion_vectors, vertex_array_rd, vertex_format);
}
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);

View File

@ -2139,9 +2139,9 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr
//skeleton and blend shape
if (surf->owner->mesh_instance.is_valid()) {
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(surf->owner->mesh_instance, surf->surface_index, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
} else {
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), vertex_array_rd, vertex_format);
mesh_storage->mesh_surface_get_vertex_arrays_and_format(mesh_surface, pipeline->get_vertex_input_mask(), false, vertex_array_rd, vertex_format);
}
index_array_rd = mesh_storage->mesh_surface_get_index_array(mesh_surface, element_info.lod_index);

View File

@ -900,9 +900,9 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
RD::VertexFormatID vertex_format = RD::INVALID_FORMAT_ID;
if (mesh_instance.is_valid()) {
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, vertex_array, vertex_format);
mesh_storage->mesh_instance_surface_get_vertex_arrays_and_format(mesh_instance, j, input_mask, false, vertex_array, vertex_format);
} else {
mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, vertex_array, vertex_format);
mesh_storage->mesh_surface_get_vertex_arrays_and_format(surface, input_mask, false, vertex_array, vertex_format);
}
RID pipeline = pipeline_variants->variants[light_mode][variant[primitive]].get_render_pipeline(vertex_format, p_framebuffer_format);

View File

@ -18,7 +18,11 @@ layout(location = 0) in vec3 vertex_attrib;
layout(location = 1) in vec2 normal_attrib;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED))
#define TANGENT_USED
#endif
#ifdef TANGENT_USED
layout(location = 2) in vec2 tangent_attrib;
#endif
@ -58,6 +62,18 @@ layout(location = 10) in uvec4 bone_attrib;
layout(location = 11) in vec4 weight_attrib;
#endif
#ifdef MOTION_VECTORS
layout(location = 12) in vec3 previous_vertex_attrib;
#ifdef NORMAL_USED
layout(location = 13) in vec2 previous_normal_attrib;
#endif
#ifdef TANGENT_USED
layout(location = 14) in vec2 previous_tangent_attrib;
#endif
#endif // MOTION_VECTORS
vec3 oct_to_vec3(vec2 e) {
vec3 v = vec3(e.xy, 1.0 - abs(e.x) - abs(e.y));
float t = max(-v.z, 0.0);
@ -85,7 +101,7 @@ layout(location = 3) out vec2 uv_interp;
layout(location = 4) out vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifdef TANGENT_USED
layout(location = 5) out vec3 tangent_interp;
layout(location = 6) out vec3 binormal_interp;
#endif
@ -161,7 +177,14 @@ vec3 double_add_vec3(vec3 base_a, vec3 prec_a, vec3 base_b, vec3 prec_b, out vec
}
#endif
void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
void vertex_shader(vec3 vertex_input,
#ifdef NORMAL_USED
in vec2 normal_input,
#endif
#ifdef TANGENT_USED
in vec2 tangent_input,
#endif
in uint instance_index, in bool is_multimesh, in uint multimesh_offset, in SceneData scene_data, in mat4 model_matrix, out vec4 screen_pos) {
vec4 instance_custom = vec4(0.0);
#if defined(COLOR_USED)
color_interp = color_attrib;
@ -289,15 +312,15 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
model_normal_matrix = model_normal_matrix * mat3(matrix);
}
vec3 vertex = vertex_attrib;
vec3 vertex = vertex_input;
#ifdef NORMAL_USED
vec3 normal = oct_to_vec3(normal_attrib * 2.0 - 1.0);
vec3 normal = oct_to_vec3(normal_input * 2.0 - 1.0);
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
vec2 signed_tangent_attrib = tangent_attrib * 2.0 - 1.0;
vec3 tangent = oct_to_vec3(vec2(signed_tangent_attrib.x, abs(signed_tangent_attrib.y) * 2.0 - 1.0));
float binormalf = sign(signed_tangent_attrib.y);
#ifdef TANGENT_USED
vec2 signed_tangent_input = tangent_input * 2.0 - 1.0;
vec3 tangent = oct_to_vec3(vec2(signed_tangent_input.x, abs(signed_tangent_input.y) * 2.0 - 1.0));
float binormalf = sign(signed_tangent_input.y);
vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
@ -333,7 +356,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
normal = model_normal_matrix * normal;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifdef TANGENT_USED
tangent = model_normal_matrix * tangent;
binormal = model_normal_matrix * binormal;
@ -377,7 +400,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifdef TANGENT_USED
binormal = modelview_normal * binormal;
tangent = modelview_normal * tangent;
@ -391,7 +414,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
normal = (scene_data.view_matrix * vec4(normal, 0.0)).xyz;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifdef TANGENT_USED
binormal = (scene_data.view_matrix * vec4(binormal, 0.0)).xyz;
tangent = (scene_data.view_matrix * vec4(tangent, 0.0)).xyz;
#endif
@ -403,7 +426,7 @@ void vertex_shader(in uint instance_index, in bool is_multimesh, in uint multime
normal_interp = normal;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifdef TANGENT_USED
tangent_interp = tangent;
binormal_interp = binormal;
#endif
@ -472,16 +495,33 @@ void main() {
instance_index_interp = instance_index;
mat4 model_matrix = instances.data[instance_index].transform;
#if defined(MOTION_VECTORS)
#ifdef MOTION_VECTORS
// Previous vertex.
global_time = scene_data_block.prev_data.time;
vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
global_time = scene_data_block.data.time;
vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
#else
global_time = scene_data_block.data.time;
vec4 screen_position;
vertex_shader(instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
vertex_shader(previous_vertex_attrib,
#ifdef NORMAL_USED
previous_normal_attrib,
#endif
#ifdef TANGENT_USED
previous_tangent_attrib,
#endif
instance_index, is_multimesh, draw_call.multimesh_motion_vectors_previous_offset, scene_data_block.prev_data, instances.data[instance_index].prev_transform, prev_screen_position);
#else
// Unused output.
vec4 screen_position;
#endif
// Current vertex.
global_time = scene_data_block.data.time;
vertex_shader(vertex_attrib,
#ifdef NORMAL_USED
normal_attrib,
#endif
#ifdef TANGENT_USED
tangent_attrib,
#endif
instance_index, is_multimesh, draw_call.multimesh_motion_vectors_current_offset, scene_data_block.data, model_matrix, screen_position);
}
#[fragment]
@ -535,7 +575,11 @@ layout(location = 3) in vec2 uv_interp;
layout(location = 4) in vec2 uv2_interp;
#endif
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#if !defined(TANGENT_USED) && (defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED))
#define TANGENT_USED
#endif
#ifdef TANGENT_USED
layout(location = 5) in vec3 tangent_interp;
layout(location = 6) in vec3 binormal_interp;
#endif
@ -771,7 +815,7 @@ void fragment_shader(in SceneData scene_data) {
float alpha = float(instances.data[instance_index].flags >> INSTANCE_FLAGS_FADE_SHIFT) / float(255.0);
#if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED)
#ifdef TANGENT_USED
vec3 binormal = normalize(binormal_interp);
vec3 tangent = normalize(tangent_interp);
#else

View File

@ -29,7 +29,6 @@
/**************************************************************************/
#include "mesh_storage.h"
#include "../../rendering_server_globals.h"
using namespace RendererRD;
@ -854,8 +853,11 @@ void MeshStorage::_mesh_instance_clear(MeshInstance *mi) {
}
memfree(surface.versions);
}
if (surface.vertex_buffer.is_valid()) {
RD::get_singleton()->free(surface.vertex_buffer);
for (uint32_t i = 0; i < 2; i++) {
if (surface.vertex_buffer[i].is_valid()) {
RD::get_singleton()->free(surface.vertex_buffer[i]);
}
}
}
mi->surfaces.clear();
@ -881,35 +883,38 @@ void MeshStorage::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint3
MeshInstance::Surface s;
if ((mesh->blend_shape_count > 0 || (mesh->surfaces[p_surface]->format & RS::ARRAY_FORMAT_BONES)) && mesh->surfaces[p_surface]->vertex_buffer_size > 0) {
//surface warrants transform
s.vertex_buffer = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.binding = 1;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(s.vertex_buffer);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
if (mi->blend_weights_buffer.is_valid()) {
u.append_id(mi->blend_weights_buffer);
} else {
u.append_id(default_rd_storage_buffer);
}
uniforms.push_back(u);
}
s.uniform_set = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
_mesh_instance_add_surface_buffer(mi, mesh, &s, p_surface, 0);
}
mi->surfaces.push_back(s);
mi->dirty = true;
}
void MeshStorage::_mesh_instance_add_surface_buffer(MeshInstance *mi, Mesh *mesh, MeshInstance::Surface *s, uint32_t p_surface, uint32_t p_buffer_index) {
s->vertex_buffer[p_buffer_index] = RD::get_singleton()->vertex_buffer_create(mesh->surfaces[p_surface]->vertex_buffer_size, Vector<uint8_t>(), true);
Vector<RD::Uniform> uniforms;
{
RD::Uniform u;
u.binding = 1;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
u.append_id(s->vertex_buffer[p_buffer_index]);
uniforms.push_back(u);
}
{
RD::Uniform u;
u.binding = 2;
u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER;
if (mi->blend_weights_buffer.is_valid()) {
u.append_id(mi->blend_weights_buffer);
} else {
u.append_id(default_rd_storage_buffer);
}
uniforms.push_back(u);
}
s->uniform_set[p_buffer_index] = RD::get_singleton()->uniform_set_create(uniforms, skeleton_shader.version_shader[0], SkeletonShader::UNIFORM_SET_INSTANCE);
}
void MeshStorage::mesh_instance_check_for_update(RID p_mesh_instance) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
@ -956,6 +961,8 @@ void MeshStorage::update_mesh_instances() {
}
//process skeletons and blend shapes
uint64_t frame = RSG::rasterizer->get_frame_number();
bool uses_motion_vectors = (RSG::viewport->get_num_viewports_with_motion_vectors() > 0);
RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
while (dirty_mesh_instance_arrays.first()) {
@ -964,7 +971,29 @@ void MeshStorage::update_mesh_instances() {
Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton);
for (uint32_t i = 0; i < mi->surfaces.size(); i++) {
if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) {
if (mi->surfaces[i].uniform_set[0].is_null() || mi->mesh->surfaces[i]->uniform_set.is_null()) {
// Skip over mesh instances that don't require their own uniform buffers.
continue;
}
mi->surfaces[i].previous_buffer = mi->surfaces[i].current_buffer;
if (uses_motion_vectors && (frame - mi->surfaces[i].last_change) == 1) {
// Previous buffer's data can only be one frame old to be able to use motion vectors.
uint32_t new_buffer_index = mi->surfaces[i].current_buffer ^ 1;
if (mi->surfaces[i].uniform_set[new_buffer_index].is_null()) {
// Create the new vertex buffer on demand where the result for the current frame will be stored.
_mesh_instance_add_surface_buffer(mi, mi->mesh, &mi->surfaces[i], i, new_buffer_index);
}
mi->surfaces[i].current_buffer = new_buffer_index;
}
mi->surfaces[i].last_change = frame;
RID mi_surface_uniform_set = mi->surfaces[i].uniform_set[mi->surfaces[i].current_buffer];
if (mi_surface_uniform_set.is_null()) {
continue;
}
@ -972,7 +1001,7 @@ void MeshStorage::update_mesh_instances() {
RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, skeleton_shader.pipeline[array_is_2d ? SkeletonShader::SHADER_MODE_2D : SkeletonShader::SHADER_MODE_3D]);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->surfaces[i].uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi_surface_uniform_set, SkeletonShader::UNIFORM_SET_INSTANCE);
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, mi->mesh->surfaces[i]->uniform_set, SkeletonShader::UNIFORM_SET_SURFACE);
if (sk && sk->uniform_set_mi.is_valid()) {
RD::get_singleton()->compute_list_bind_uniform_set(compute_list, sk->uniform_set_mi, SkeletonShader::UNIFORM_SET_SKELETON);
@ -1032,7 +1061,7 @@ void MeshStorage::update_mesh_instances() {
RD::get_singleton()->compute_list_end();
}
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis) {
void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis) {
Vector<RD::VertexAttribute> attributes;
Vector<RID> buffers;
@ -1105,7 +1134,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
if (mis) {
buffer = mis->vertex_buffer;
buffer = mis->vertex_buffer[mis->current_buffer];
} else {
buffer = s->vertex_buffer;
}
@ -1117,7 +1146,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
stride += sizeof(uint16_t) * 2;
if (mis) {
buffer = mis->vertex_buffer;
buffer = mis->vertex_buffer[mis->current_buffer];
} else {
buffer = s->vertex_buffer;
}
@ -1128,7 +1157,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
stride += sizeof(uint16_t) * 2;
if (mis) {
buffer = mis->vertex_buffer;
buffer = mis->vertex_buffer[mis->current_buffer];
} else {
buffer = s->vertex_buffer;
}
@ -1193,6 +1222,32 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
attributes.push_back(vd);
buffers.push_back(buffer);
if (p_input_motion_vectors) {
// Since the previous vertex, normal and tangent can't be part of the vertex format but they are required when motion
// vectors are enabled, we opt to push a copy of the vertex attribute with a different location and buffer (if it's
// part of an instance that has one).
switch (i) {
case RS::ARRAY_VERTEX: {
vd.location = ATTRIBUTE_LOCATION_PREV_VERTEX;
} break;
case RS::ARRAY_NORMAL: {
vd.location = ATTRIBUTE_LOCATION_PREV_NORMAL;
} break;
case RS::ARRAY_TANGENT: {
vd.location = ATTRIBUTE_LOCATION_PREV_TANGENT;
} break;
}
if (int(vd.location) != i) {
if (mis && buffer != mesh_default_rd_buffers[i]) {
buffer = mis->vertex_buffer[mis->previous_buffer];
}
attributes.push_back(vd);
buffers.push_back(buffer);
}
}
}
//update final stride
@ -1202,7 +1257,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
int loc = attributes[i].location;
if (loc < RS::ARRAY_COLOR) {
if ((loc < RS::ARRAY_COLOR) || ((loc >= ATTRIBUTE_LOCATION_PREV_VERTEX) && (loc <= ATTRIBUTE_LOCATION_PREV_TANGENT))) {
attributes.write[i].stride = stride;
} else if (loc < RS::ARRAY_BONES) {
attributes.write[i].stride = attribute_stride;
@ -1212,6 +1267,9 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
}
v.input_mask = p_input_mask;
v.current_buffer = mis ? mis->current_buffer : 0;
v.previous_buffer = mis ? mis->previous_buffer : 0;
v.input_motion_vectors = p_input_motion_vectors;
v.vertex_format = RD::get_singleton()->vertex_format_create(attributes);
v.vertex_array = RD::get_singleton()->vertex_array_create(s->vertex_count, v.vertex_format, buffers);
}

View File

@ -31,6 +31,7 @@
#ifndef MESH_STORAGE_RD_H
#define MESH_STORAGE_RD_H
#include "../../rendering_server_globals.h"
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
@ -90,6 +91,9 @@ private:
struct Version {
uint32_t input_mask = 0;
uint32_t current_buffer = 0;
uint32_t previous_buffer = 0;
bool input_motion_vectors = false;
RD::VertexFormatID vertex_format = 0;
RID vertex_array;
};
@ -162,8 +166,11 @@ private:
Mesh *mesh = nullptr;
RID skeleton;
struct Surface {
RID vertex_buffer;
RID uniform_set;
RID vertex_buffer[2];
RID uniform_set[2];
uint32_t current_buffer = 0;
uint32_t previous_buffer = 0;
uint64_t last_change = 0;
Mesh::Surface::Version *versions = nullptr; //allocated on demand
uint32_t version_count = 0;
@ -183,10 +190,11 @@ private:
weight_update_list(this), array_update_list(this) {}
};
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, MeshInstance::Surface *mis = nullptr);
void _mesh_surface_generate_version_for_input_mask(Mesh::Surface::Version &v, Mesh::Surface *s, uint32_t p_input_mask, bool p_input_motion_vectors, MeshInstance::Surface *mis = nullptr);
void _mesh_instance_clear(MeshInstance *mi);
void _mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, uint32_t p_surface);
void _mesh_instance_add_surface_buffer(MeshInstance *mi, Mesh *mesh, MeshInstance::Surface *s, uint32_t p_surface, uint32_t p_buffer_index);
mutable RID_Owner<MeshInstance> mesh_instance_owner;
@ -311,6 +319,12 @@ private:
Skeleton *skeleton_dirty_list = nullptr;
enum AttributeLocation {
ATTRIBUTE_LOCATION_PREV_VERTEX = 12,
ATTRIBUTE_LOCATION_PREV_NORMAL = 13,
ATTRIBUTE_LOCATION_PREV_TANGENT = 14
};
public:
static MeshStorage *get_singleton();
@ -437,7 +451,7 @@ public:
}
}
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
_FORCE_INLINE_ void mesh_surface_get_vertex_arrays_and_format(void *p_surface, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
s->version_lock.lock();
@ -445,9 +459,11 @@ public:
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
for (uint32_t i = 0; i < s->version_count; i++) {
if (s->versions[i].input_mask != p_input_mask) {
if (s->versions[i].input_mask != p_input_mask || s->versions[i].input_motion_vectors != p_input_motion_vectors) {
// Find the version that matches the inputs required.
continue;
}
//we have this version, hooray
r_vertex_format = s->versions[i].vertex_format;
r_vertex_array_rd = s->versions[i].vertex_array;
@ -459,7 +475,7 @@ public:
s->version_count++;
s->versions = (Mesh::Surface::Version *)memrealloc(s->versions, sizeof(Mesh::Surface::Version) * s->version_count);
_mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask);
_mesh_surface_generate_version_for_input_mask(s->versions[version], s, p_input_mask, p_input_motion_vectors);
r_vertex_format = s->versions[version].vertex_format;
r_vertex_array_rd = s->versions[version].vertex_array;
@ -467,7 +483,7 @@ public:
s->version_lock.unlock();
}
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, bool p_input_motion_vectors, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
ERR_FAIL_COND(!mi);
Mesh *mesh = mi->mesh;
@ -475,15 +491,26 @@ public:
MeshInstance::Surface *mis = &mi->surfaces[p_surface_index];
Mesh::Surface *s = mesh->surfaces[p_surface_index];
uint32_t current_buffer = mis->current_buffer;
// Using the previous buffer is only allowed if the surface was updated this frame and motion vectors are required.
uint32_t previous_buffer = p_input_motion_vectors && (RSG::rasterizer->get_frame_number() == mis->last_change) ? mis->previous_buffer : current_buffer;
s->version_lock.lock();
//there will never be more than, at much, 3 or 4 versions, so iterating is the fastest way
for (uint32_t i = 0; i < mis->version_count; i++) {
if (mis->versions[i].input_mask != p_input_mask) {
if (mis->versions[i].input_mask != p_input_mask || mis->versions[i].input_motion_vectors != p_input_motion_vectors) {
// Find the version that matches the inputs required.
continue;
}
if (mis->versions[i].current_buffer != current_buffer || mis->versions[i].previous_buffer != previous_buffer) {
// Find the version that corresponds to the correct buffers that should be used.
continue;
}
//we have this version, hooray
r_vertex_format = mis->versions[i].vertex_format;
r_vertex_array_rd = mis->versions[i].vertex_array;
@ -495,7 +522,7 @@ public:
mis->version_count++;
mis->versions = (Mesh::Surface::Version *)memrealloc(mis->versions, sizeof(Mesh::Surface::Version) * mis->version_count);
_mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, mis);
_mesh_surface_generate_version_for_input_mask(mis->versions[version], s, p_input_mask, p_input_motion_vectors, mis);
r_vertex_format = mis->versions[version].vertex_format;
r_vertex_array_rd = mis->versions[version].vertex_array;