Add motion vector support for animated surfaces like skeletons or blend shapes.
Extends mesh instances that required custom vertex buffers to create two alternating buffers that are written to and binds them to use them as the previous vertex buffer when generating motion vectors.
This commit is contained in:
parent
90f90cbcb0
commit
e2984af013
6 changed files with 201 additions and 71 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue