Merge pull request #80618 from DarioSamo/skeleton-motion-vectors
Add motion vector support for animated surfaces
This commit is contained in:
commit
04306777a7
|
@ -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 New Issue