Skip to content

Commit 792f959

Browse files
committed
SoftBody3D: Support physics Interpolation
1 parent 6c9765d commit 792f959

File tree

2 files changed

+124
-17
lines changed

2 files changed

+124
-17
lines changed

scene/3d/physics/soft_body_3d.cpp

Lines changed: 111 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,24 @@ 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[0] = 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];
61+
62+
buffer_curr = &buffer[0];
63+
buffer_prev = &buffer[1];
6064
}
6165

6266
void SoftBodyRenderingServerHandler::clear() {
63-
buffer.resize(0);
67+
aabb_prev = AABB();
68+
buffer[0].resize(0);
69+
buffer[1].resize(0);
70+
buffer_curr = nullptr;
71+
buffer_prev = nullptr;
72+
buffer_interp.resize(0);
6473
stride = 0;
6574
normal_stride = 0;
6675
offset_vertices = 0;
@@ -71,15 +80,73 @@ void SoftBodyRenderingServerHandler::clear() {
7180
}
7281

7382
void SoftBodyRenderingServerHandler::open() {
74-
write_buffer = buffer.ptrw();
83+
write_buffer = buffer_curr->ptrw();
7584
}
7685

7786
void SoftBodyRenderingServerHandler::close() {
7887
write_buffer = nullptr;
7988
}
8089

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

85152
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const Vector3 &p_vertex) {
@@ -98,7 +165,7 @@ void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const Vector3 &
98165
}
99166

100167
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
101-
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
168+
aabb_curr = p_aabb;
102169
}
103170

104171
SoftBody3D::PinnedPoint::PinnedPoint() {
@@ -274,7 +341,19 @@ void SoftBody3D::_notification(int p_what) {
274341
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
275342
_prepare_physics_server();
276343
} break;
277-
344+
case NOTIFICATION_INTERNAL_PROCESS: {
345+
if (is_inside_tree() && is_physics_interpolated_and_enabled()) {
346+
_commit_soft_mesh(Engine::get_singleton()->get_physics_interpolation_fraction());
347+
}
348+
} break;
349+
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
350+
if (is_inside_tree()) {
351+
_update_soft_mesh();
352+
if (!is_physics_interpolated_and_enabled()) {
353+
_commit_soft_mesh(1);
354+
}
355+
}
356+
} break;
278357
case NOTIFICATION_READY: {
279358
if (!parent_collision_ignore.is_empty()) {
280359
add_collision_exception_with(get_node(parent_collision_ignore));
@@ -295,7 +374,11 @@ void SoftBody3D::_notification(int p_what) {
295374
set_transform(Transform3D());
296375
set_notify_transform(true);
297376
} break;
298-
377+
case NOTIFICATION_RESET_PHYSICS_INTERPOLATION: {
378+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
379+
rendering_server_handler->fti_pump();
380+
}
381+
} break;
299382
case NOTIFICATION_VISIBILITY_CHANGED: {
300383
_update_pickable();
301384
} break;
@@ -394,6 +477,13 @@ void SoftBody3D::_bind_methods() {
394477
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
395478
}
396479

480+
void SoftBody3D::_physics_interpolated_changed() {
481+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
482+
rendering_server_handler->fti_pump();
483+
}
484+
MeshInstance3D::_physics_interpolated_changed();
485+
}
486+
397487
PackedStringArray SoftBody3D::get_configuration_warnings() const {
398488
PackedStringArray warnings = MeshInstance3D::get_configuration_warnings();
399489

@@ -420,7 +510,7 @@ void SoftBody3D::_update_physics_server() {
420510
}
421511
}
422512

423-
void SoftBody3D::_draw_soft_mesh() {
513+
void SoftBody3D::_update_soft_mesh() {
424514
if (mesh.is_null()) {
425515
return;
426516
}
@@ -443,11 +533,18 @@ void SoftBody3D::_draw_soft_mesh() {
443533

444534
_update_physics_server();
445535

536+
if (is_physics_interpolated_and_enabled()) {
537+
rendering_server_handler->fti_pump();
538+
}
446539
rendering_server_handler->open();
447540
PhysicsServer3D::get_singleton()->soft_body_update_rendering_server(physics_rid, rendering_server_handler);
448541
rendering_server_handler->close();
542+
}
449543

450-
rendering_server_handler->commit_changes();
544+
void SoftBody3D::_commit_soft_mesh(real_t p_interpolation_fraction) {
545+
if (mesh.is_valid() && rendering_server_handler->is_ready(mesh->get_rid())) {
546+
rendering_server_handler->commit_changes(p_interpolation_fraction);
547+
}
451548
}
452549

453550
void SoftBody3D::_prepare_physics_server() {
@@ -470,12 +567,12 @@ void SoftBody3D::_prepare_physics_server() {
470567
mesh_rid = mesh->get_rid();
471568
}
472569
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));
570+
set_process_internal(is_physics_interpolated_and_enabled());
571+
set_physics_process_internal(true);
474572
} else {
475573
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-
}
574+
set_process_internal(false);
575+
set_physics_process_internal(false);
479576
}
480577
}
481578

scene/3d/physics/soft_body_3d.h

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,13 @@ 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[2];
46+
Vector<uint8_t> *buffer_prev = nullptr;
47+
Vector<uint8_t> *buffer_curr = nullptr;
48+
Vector<uint8_t> buffer_interp;
49+
uint32_t vertex_count = 0;
4450
uint32_t stride = 0;
4551
uint32_t normal_stride = 0;
4652
uint32_t offset_vertices = 0;
@@ -55,7 +61,8 @@ class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHand
5561
void clear();
5662
void open();
5763
void close();
58-
void commit_changes();
64+
void fti_pump();
65+
void commit_changes(real_t p_interpolation_fraction);
5966

6067
public:
6168
void set_vertex(int p_vertex_id, const Vector3 &p_vertex) override;
@@ -107,7 +114,8 @@ class SoftBody3D : public MeshInstance3D {
107114
void _update_pickable();
108115

109116
void _update_physics_server();
110-
void _draw_soft_mesh();
117+
void _update_soft_mesh();
118+
void _commit_soft_mesh(real_t p_interpolation_fraction);
111119

112120
void _prepare_physics_server();
113121
void _become_mesh_owner();
@@ -124,6 +132,8 @@ class SoftBody3D : public MeshInstance3D {
124132
void _notification(int p_what);
125133
static void _bind_methods();
126134

135+
void _physics_interpolated_changed() override;
136+
127137
#ifndef DISABLE_DEPRECATED
128138
void _pin_point_bind_compat_94684(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
129139
static void _bind_compatibility_methods();

0 commit comments

Comments
 (0)