Skip to content

Commit 42be62c

Browse files
committed
SoftBody3D: Support physics Interpolation
1 parent 6c9765d commit 42be62c

File tree

2 files changed

+112
-17
lines changed

2 files changed

+112
-17
lines changed

scene/3d/physics/soft_body_3d.cpp

Lines changed: 100 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,19 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
5252
uint32_t skin_stride;
5353
RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_data.format, surface_data.vertex_count, surface_data.index_count, surface_offsets, vertex_stride, normal_tangent_stride, attrib_stride, skin_stride);
5454

55-
buffer = surface_data.vertex_data;
55+
buffer_curr = surface_data.vertex_data;
56+
vertex_count = surface_data.vertex_count;
5657
stride = vertex_stride;
5758
normal_stride = normal_tangent_stride;
5859
offset_vertices = surface_offsets[RS::ARRAY_VERTEX];
5960
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
6061
}
6162

6263
void SoftBodyRenderingServerHandler::clear() {
63-
buffer.resize(0);
64+
aabb_prev = AABB();
65+
buffer_prev.resize(0);
66+
buffer_curr.resize(0);
67+
buffer_interp.resize(0);
6468
stride = 0;
6569
normal_stride = 0;
6670
offset_vertices = 0;
@@ -71,15 +75,70 @@ void SoftBodyRenderingServerHandler::clear() {
7175
}
7276

7377
void SoftBodyRenderingServerHandler::open() {
74-
write_buffer = buffer.ptrw();
78+
write_buffer = buffer_curr.ptrw();
7579
}
7680

7781
void SoftBodyRenderingServerHandler::close() {
7882
write_buffer = nullptr;
7983
}
8084

81-
void SoftBodyRenderingServerHandler::commit_changes() {
82-
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer);
85+
void SoftBodyRenderingServerHandler::fti_pump() {
86+
if (buffer_prev.is_empty()) {
87+
buffer_prev.resize(buffer_curr.size());
88+
}
89+
SWAP(buffer_prev, buffer_curr);
90+
aabb_prev = aabb_curr;
91+
}
92+
93+
void SoftBodyRenderingServerHandler::commit_changes(real_t p_interpolation_fraction) {
94+
real_t f = p_interpolation_fraction;
95+
AABB aabb_interp = aabb_curr;
96+
97+
if (buffer_interp.is_empty()) {
98+
buffer_interp.resize(buffer_curr.size());
99+
}
100+
101+
if (p_interpolation_fraction < 1) {
102+
// AABB.
103+
if (aabb_prev != AABB() && aabb_curr != AABB()) {
104+
aabb_interp = AABB(aabb_prev.position.lerp(aabb_curr.position, f), aabb_prev.size.lerp(aabb_curr.size, f));
105+
}
106+
107+
const float *vertex_prev = reinterpret_cast<const float *>(buffer_prev.ptr() + offset_vertices);
108+
const float *vertex_curr = reinterpret_cast<const float *>(buffer_curr.ptr() + offset_vertices);
109+
float *vertex_interp = reinterpret_cast<float *>(buffer_interp.ptrw() + offset_vertices);
110+
111+
const uint32_t *normal_prev = reinterpret_cast<const uint32_t *>(buffer_prev.ptr() + offset_normal);
112+
const uint32_t *normal_curr = reinterpret_cast<const uint32_t *>(buffer_curr.ptr() + offset_normal);
113+
uint32_t *normal_interp = reinterpret_cast<uint32_t *>(buffer_interp.ptrw() + offset_normal);
114+
115+
for (uint32_t i = 0; i < vertex_count; i++) {
116+
// Vertex.
117+
vertex_interp[0] = Math::lerp(vertex_prev[0], vertex_curr[0], (float)f);
118+
vertex_interp[1] = Math::lerp(vertex_prev[1], vertex_curr[1], (float)f);
119+
vertex_interp[2] = Math::lerp(vertex_prev[2], vertex_curr[2], (float)f);
120+
121+
vertex_prev += stride / sizeof(float);
122+
vertex_curr += stride / sizeof(float);
123+
vertex_interp += stride / sizeof(float);
124+
125+
// Normal.
126+
Vector2 prev = Vector2((normal_prev[0] & 0xffff) / 65535.0f, (normal_prev[0] >> 16) / 65535.0f);
127+
Vector2 curr = Vector2((normal_curr[0] & 0xffff) / 65535.0f, (normal_curr[0] >> 16) / 65535.0f);
128+
Vector2 interp = Vector3::octahedron_decode(prev).lerp(Vector3::octahedron_decode(curr), f).octahedron_encode();
129+
uint32_t n = 0;
130+
n |= (uint16_t)CLAMP(interp.x * 65535, 0, 65535);
131+
n |= (uint16_t)CLAMP(interp.y * 65535, 0, 65535) << 16;
132+
normal_interp[0] = n;
133+
134+
normal_prev += normal_stride / sizeof(uint32_t);
135+
normal_curr += normal_stride / sizeof(uint32_t);
136+
normal_interp += normal_stride / sizeof(uint32_t);
137+
}
138+
}
139+
140+
RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb_interp);
141+
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, p_interpolation_fraction < 1 ? buffer_interp : buffer_curr);
83142
}
84143

85144
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const Vector3 &p_vertex) {
@@ -98,7 +157,7 @@ void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const Vector3 &
98157
}
99158

100159
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
101-
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
160+
aabb_curr = p_aabb;
102161
}
103162

104163
SoftBody3D::PinnedPoint::PinnedPoint() {
@@ -274,7 +333,16 @@ void SoftBody3D::_notification(int p_what) {
274333
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
275334
_prepare_physics_server();
276335
} break;
277-
336+
case NOTIFICATION_INTERNAL_PROCESS: {
337+
if (is_inside_tree()) {
338+
_commit_soft_mesh(is_physics_interpolated_and_enabled() ? Engine::get_singleton()->get_physics_interpolation_fraction() : 1);
339+
}
340+
} break;
341+
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
342+
if (is_inside_tree()) {
343+
_update_soft_mesh();
344+
}
345+
} break;
278346
case NOTIFICATION_READY: {
279347
if (!parent_collision_ignore.is_empty()) {
280348
add_collision_exception_with(get_node(parent_collision_ignore));
@@ -295,7 +363,11 @@ void SoftBody3D::_notification(int p_what) {
295363
set_transform(Transform3D());
296364
set_notify_transform(true);
297365
} break;
298-
366+
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
367+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
368+
rendering_server_handler->fti_pump();
369+
}
370+
} break;
299371
case NOTIFICATION_VISIBILITY_CHANGED: {
300372
_update_pickable();
301373
} break;
@@ -394,6 +466,13 @@ void SoftBody3D::_bind_methods() {
394466
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
395467
}
396468

469+
void SoftBody3D::_physics_interpolated_changed() {
470+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
471+
rendering_server_handler->fti_pump();
472+
}
473+
MeshInstance3D::_physics_interpolated_changed();
474+
}
475+
397476
PackedStringArray SoftBody3D::get_configuration_warnings() const {
398477
PackedStringArray warnings = MeshInstance3D::get_configuration_warnings();
399478

@@ -420,7 +499,7 @@ void SoftBody3D::_update_physics_server() {
420499
}
421500
}
422501

423-
void SoftBody3D::_draw_soft_mesh() {
502+
void SoftBody3D::_update_soft_mesh() {
424503
if (mesh.is_null()) {
425504
return;
426505
}
@@ -443,11 +522,18 @@ void SoftBody3D::_draw_soft_mesh() {
443522

444523
_update_physics_server();
445524

525+
if (is_physics_interpolated_and_enabled()) {
526+
rendering_server_handler->fti_pump();
527+
}
446528
rendering_server_handler->open();
447529
PhysicsServer3D::get_singleton()->soft_body_update_rendering_server(physics_rid, rendering_server_handler);
448530
rendering_server_handler->close();
531+
}
449532

450-
rendering_server_handler->commit_changes();
533+
void SoftBody3D::_commit_soft_mesh(real_t p_interpolation_fraction) {
534+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
535+
rendering_server_handler->commit_changes(p_interpolation_fraction);
536+
}
451537
}
452538

453539
void SoftBody3D::_prepare_physics_server() {
@@ -470,12 +556,12 @@ void SoftBody3D::_prepare_physics_server() {
470556
mesh_rid = mesh->get_rid();
471557
}
472558
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid);
473-
RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
559+
set_process_internal(true);
560+
set_physics_process_internal(true);
474561
} else {
475562
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
476-
if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh))) {
477-
RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
478-
}
563+
set_process_internal(false);
564+
set_physics_process_internal(false);
479565
}
480566
}
481567

scene/3d/physics/soft_body_3d.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHand
4040

4141
RID mesh;
4242
int surface = 0;
43-
Vector<uint8_t> buffer;
43+
AABB aabb_prev;
44+
AABB aabb_curr;
45+
Vector<uint8_t> buffer_prev;
46+
Vector<uint8_t> buffer_curr;
47+
Vector<uint8_t> buffer_interp;
48+
uint32_t vertex_count = 0;
4449
uint32_t stride = 0;
4550
uint32_t normal_stride = 0;
4651
uint32_t offset_vertices = 0;
@@ -55,7 +60,8 @@ class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHand
5560
void clear();
5661
void open();
5762
void close();
58-
void commit_changes();
63+
void fti_pump();
64+
void commit_changes(real_t p_interpolation_fraction);
5965

6066
public:
6167
void set_vertex(int p_vertex_id, const Vector3 &p_vertex) override;
@@ -107,7 +113,8 @@ class SoftBody3D : public MeshInstance3D {
107113
void _update_pickable();
108114

109115
void _update_physics_server();
110-
void _draw_soft_mesh();
116+
void _update_soft_mesh();
117+
void _commit_soft_mesh(real_t p_interpolation_fraction);
111118

112119
void _prepare_physics_server();
113120
void _become_mesh_owner();
@@ -124,6 +131,8 @@ class SoftBody3D : public MeshInstance3D {
124131
void _notification(int p_what);
125132
static void _bind_methods();
126133

134+
void _physics_interpolated_changed() override;
135+
127136
#ifndef DISABLE_DEPRECATED
128137
void _pin_point_bind_compat_94684(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
129138
static void _bind_compatibility_methods();

0 commit comments

Comments
 (0)