Skip to content

Commit 7f13876

Browse files
committed
SoftBody3D: Support physics Interpolation
1 parent 6c9765d commit 7f13876

File tree

2 files changed

+91
-13
lines changed

2 files changed

+91
-13
lines changed

scene/3d/physics/soft_body_3d.cpp

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,16 @@ void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
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

5555
buffer = 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() {
64+
aabb_prev = AABB();
65+
buffer_prev.resize(0);
6366
buffer.resize(0);
6467
stride = 0;
6568
normal_stride = 0;
@@ -78,8 +81,48 @@ void SoftBodyRenderingServerHandler::close() {
7881
write_buffer = nullptr;
7982
}
8083

81-
void SoftBodyRenderingServerHandler::commit_changes() {
82-
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer);
84+
void SoftBodyRenderingServerHandler::fti_pump() {
85+
buffer_prev = buffer;
86+
aabb_prev = aabb;
87+
}
88+
89+
void SoftBodyRenderingServerHandler::commit_changes(real_t p_interpolation_fraction) {
90+
real_t f = p_interpolation_fraction;
91+
Vector<uint8_t> buffer_interp = buffer;
92+
AABB aabb_interp = aabb;
93+
94+
if (p_interpolation_fraction < 1) {
95+
// AABB.
96+
aabb_interp = AABB(aabb_prev.position.lerp(aabb.position, f), aabb_prev.size.lerp(aabb.size, f));
97+
98+
for (uint32_t i = 0; i < vertex_count; i++) {
99+
// Vertex.
100+
float *vertex_buffer_prev = reinterpret_cast<float *>(buffer_prev.ptrw() + i * stride + offset_vertices);
101+
float *vertex_buffer_interp = reinterpret_cast<float *>(buffer_interp.ptrw() + i * stride + offset_vertices);
102+
103+
*vertex_buffer_interp = Math::lerp(*vertex_buffer_prev, *vertex_buffer_interp, (float)f);
104+
vertex_buffer_interp++;
105+
vertex_buffer_prev++;
106+
*vertex_buffer_interp = Math::lerp(*vertex_buffer_prev, *vertex_buffer_interp, (float)f);
107+
vertex_buffer_interp++;
108+
vertex_buffer_prev++;
109+
*vertex_buffer_interp = Math::lerp(*vertex_buffer_prev, *vertex_buffer_interp, (float)f);
110+
111+
// Normal.
112+
uint32_t *normal_buffer_prev = reinterpret_cast<uint32_t *>(buffer_prev.ptrw() + i * normal_stride + offset_normal);
113+
uint32_t *normal_buffer_interp = reinterpret_cast<uint32_t *>(buffer_interp.ptrw() + i * normal_stride + offset_normal);
114+
Vector2 prev = Vector2((normal_buffer_prev[0] & 0xffff) / 65535.0f, (normal_buffer_prev[0] >> 16) / 65535.0f);
115+
Vector2 curr = Vector2((normal_buffer_interp[0] & 0xffff) / 65535.0f, (normal_buffer_prev[0] >> 16) / 65535.0f);
116+
Vector2 interp = Vector3::octahedron_decode(prev).lerp(Vector3::octahedron_decode(curr), f).octahedron_encode();
117+
uint32_t value = 0;
118+
value |= (uint16_t)CLAMP(interp.x * 65535, 0, 65535);
119+
value |= (uint16_t)CLAMP(interp.y * 65535, 0, 65535) << 16;
120+
normal_buffer_interp[0] = value;
121+
}
122+
}
123+
124+
RS::get_singleton()->mesh_set_custom_aabb(mesh, aabb_interp);
125+
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer_interp);
83126
}
84127

85128
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const Vector3 &p_vertex) {
@@ -98,7 +141,7 @@ void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const Vector3 &
98141
}
99142

100143
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
101-
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
144+
aabb = p_aabb;
102145
}
103146

104147
SoftBody3D::PinnedPoint::PinnedPoint() {
@@ -274,7 +317,16 @@ void SoftBody3D::_notification(int p_what) {
274317
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
275318
_prepare_physics_server();
276319
} break;
277-
320+
case NOTIFICATION_INTERNAL_PROCESS: {
321+
if (is_inside_tree()) {
322+
_commit_soft_mesh(is_physics_interpolated_and_enabled() ? Engine::get_singleton()->get_physics_interpolation_fraction() : 1);
323+
}
324+
} break;
325+
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
326+
if (is_inside_tree()) {
327+
_update_soft_mesh();
328+
}
329+
} break;
278330
case NOTIFICATION_READY: {
279331
if (!parent_collision_ignore.is_empty()) {
280332
add_collision_exception_with(get_node(parent_collision_ignore));
@@ -295,7 +347,11 @@ void SoftBody3D::_notification(int p_what) {
295347
set_transform(Transform3D());
296348
set_notify_transform(true);
297349
} break;
298-
350+
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
351+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
352+
rendering_server_handler->fti_pump();
353+
}
354+
} break;
299355
case NOTIFICATION_VISIBILITY_CHANGED: {
300356
_update_pickable();
301357
} break;
@@ -394,6 +450,13 @@ void SoftBody3D::_bind_methods() {
394450
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
395451
}
396452

453+
void SoftBody3D::_physics_interpolated_changed() {
454+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
455+
rendering_server_handler->fti_pump();
456+
}
457+
MeshInstance3D::_physics_interpolated_changed();
458+
}
459+
397460
PackedStringArray SoftBody3D::get_configuration_warnings() const {
398461
PackedStringArray warnings = MeshInstance3D::get_configuration_warnings();
399462

@@ -420,7 +483,7 @@ void SoftBody3D::_update_physics_server() {
420483
}
421484
}
422485

423-
void SoftBody3D::_draw_soft_mesh() {
486+
void SoftBody3D::_update_soft_mesh() {
424487
if (mesh.is_null()) {
425488
return;
426489
}
@@ -443,11 +506,18 @@ void SoftBody3D::_draw_soft_mesh() {
443506

444507
_update_physics_server();
445508

509+
if (is_physics_interpolated_and_enabled()) {
510+
rendering_server_handler->fti_pump();
511+
}
446512
rendering_server_handler->open();
447513
PhysicsServer3D::get_singleton()->soft_body_update_rendering_server(physics_rid, rendering_server_handler);
448514
rendering_server_handler->close();
515+
}
449516

450-
rendering_server_handler->commit_changes();
517+
void SoftBody3D::_commit_soft_mesh(real_t p_interpolation_fraction) {
518+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
519+
rendering_server_handler->commit_changes(p_interpolation_fraction);
520+
}
451521
}
452522

453523
void SoftBody3D::_prepare_physics_server() {
@@ -470,12 +540,12 @@ void SoftBody3D::_prepare_physics_server() {
470540
mesh_rid = mesh->get_rid();
471541
}
472542
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));
543+
set_process_internal(true);
544+
set_physics_process_internal(true);
474545
} else {
475546
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-
}
547+
set_process_internal(false);
548+
set_physics_process_internal(false);
479549
}
480550
}
481551

scene/3d/physics/soft_body_3d.h

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

4141
RID mesh;
4242
int surface = 0;
43+
AABB aabb_prev;
44+
AABB aabb;
45+
Vector<uint8_t> buffer_prev;
4346
Vector<uint8_t> buffer;
47+
uint32_t vertex_count = 0;
4448
uint32_t stride = 0;
4549
uint32_t normal_stride = 0;
4650
uint32_t offset_vertices = 0;
@@ -55,7 +59,8 @@ class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHand
5559
void clear();
5660
void open();
5761
void close();
58-
void commit_changes();
62+
void fti_pump();
63+
void commit_changes(real_t p_interpolation_fraction);
5964

6065
public:
6166
void set_vertex(int p_vertex_id, const Vector3 &p_vertex) override;
@@ -107,7 +112,8 @@ class SoftBody3D : public MeshInstance3D {
107112
void _update_pickable();
108113

109114
void _update_physics_server();
110-
void _draw_soft_mesh();
115+
void _update_soft_mesh();
116+
void _commit_soft_mesh(real_t p_interpolation_fraction);
111117

112118
void _prepare_physics_server();
113119
void _become_mesh_owner();
@@ -124,6 +130,8 @@ class SoftBody3D : public MeshInstance3D {
124130
void _notification(int p_what);
125131
static void _bind_methods();
126132

133+
void _physics_interpolated_changed() override;
134+
127135
#ifndef DISABLE_DEPRECATED
128136
void _pin_point_bind_compat_94684(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
129137
static void _bind_compatibility_methods();

0 commit comments

Comments
 (0)