Skip to content

Commit 2e35405

Browse files
committed
Add a 3D soft body physics demo
1 parent 89b2660 commit 2e35405

27 files changed

+2828
-0
lines changed

3d/soft_body_physics/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# 3D Soft Body Physics
2+
3+
An example of [soft body physics](https://docs.godotengine.org/en/latest/tutorials/physics/soft_body.html)
4+
(deformable objects) such as cloth, boxes and spheres.
5+
6+
Soft bodies support pinning points as well as applying impulses/forces to specific points,
7+
which can be useful for effects such as wind.
8+
9+
Soft bodies can interact with static, rigid and character bodies (and will be aware of rigid bodies'
10+
weight when doing so). However, soft bodies currently do **not** interact with other soft bodies,
11+
which means they will pass through each other.
12+
13+
The per-point impulse timer example also showcases how to attach nodes to specific points of a SoftBody3D.
14+
This can be used to make particles, meshes or even rigid bodies follow specific points.
15+
16+
The cloth soft bodies in this demo use a BaseMaterial3D with the **Grow** property enabled to prevent
17+
visible clipping into surfaces.
18+
19+
Controls:
20+
21+
- <kbd>R</kbd>: Reset soft body simulation and user-placed objects
22+
- <kbd>C</kbd>: Place cloth at cursor position
23+
- <kbd>V</kbd>: Place light box at cursor position
24+
- <kbd>B</kbd>: Place heavy box at cursor position
25+
26+
For performance reasons, only 10 user-placed objects can be present at a time in this demo.
27+
The oldest objects will be removed when attempting to place more than 10 objects.
28+
29+
Language: GDScript
30+
31+
Renderer: Forward+
32+
33+
## Screenshots
34+
35+
![Screenshot](screenshots/soft_body_physics.webp)

3d/soft_body_physics/box.tscn

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
[gd_scene load_steps=7 format=3 uid="uid://inwnbl1ufttq"]
2+
3+
[ext_resource type="ArrayMesh" uid="uid://d2aecsqru2t1r" path="res://rounded_cube.obj" id="1_g2tbl"]
4+
5+
[sub_resource type="Gradient" id="Gradient_cbx31"]
6+
colors = PackedColorArray(0.619608, 0.227451, 0, 1, 1, 0.564706, 0, 1)
7+
8+
[sub_resource type="FastNoiseLite" id="FastNoiseLite_x8fbi"]
9+
fractal_lacunarity = 3.47
10+
fractal_gain = 1.105
11+
12+
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_41u45"]
13+
noise = SubResource("FastNoiseLite_x8fbi")
14+
color_ramp = SubResource("Gradient_cbx31")
15+
seamless = true
16+
17+
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_cbx31"]
18+
noise = SubResource("FastNoiseLite_x8fbi")
19+
color_ramp = SubResource("Gradient_cbx31")
20+
seamless = true
21+
as_normal_map = true
22+
bump_strength = 4.0
23+
24+
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_cbx31"]
25+
albedo_texture = SubResource("NoiseTexture2D_41u45")
26+
normal_enabled = true
27+
normal_texture = SubResource("NoiseTexture2D_cbx31")
28+
uv1_scale = Vector3(2, 2, 2)
29+
texture_filter = 5
30+
31+
[node name="SoftBody3D" type="SoftBody3D"]
32+
mesh = ExtResource("1_g2tbl")
33+
surface_material_override/0 = SubResource("StandardMaterial3D_cbx31")
34+
simulation_precision = 100
35+
total_mass = 10.01
36+
pressure_coefficient = 100.0

3d/soft_body_physics/cloth.tscn

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[gd_scene load_steps=6 format=3 uid="uid://ditdn410656"]
2+
3+
[ext_resource type="Texture2D" uid="uid://csp3kbg6r4rwd" path="res://textures/polyhaven/fabric_pattern_07_col_1_1k.jpg" id="1_pir5u"]
4+
[ext_resource type="Texture2D" uid="uid://hh6i17naw1qx" path="res://textures/polyhaven/fabric_pattern_07_nor_gl_1k.jpg" id="2_q5utd"]
5+
[ext_resource type="Texture2D" uid="uid://clyte8pu0nwom" path="res://textures/polyhaven/fabric_pattern_07_arm_1k.jpg" id="3_eo47f"]
6+
7+
[sub_resource type="ORMMaterial3D" id="ORMMaterial3D_g14j6"]
8+
cull_mode = 2
9+
albedo_texture = ExtResource("1_pir5u")
10+
orm_texture = ExtResource("3_eo47f")
11+
normal_enabled = true
12+
normal_texture = ExtResource("2_q5utd")
13+
uv1_scale = Vector3(4, 4, 4)
14+
texture_filter = 5
15+
grow = true
16+
grow_amount = 0.02
17+
18+
[sub_resource type="PlaneMesh" id="PlaneMesh_6uqi0"]
19+
material = SubResource("ORMMaterial3D_g14j6")
20+
size = Vector2(1.6, 1.6)
21+
subdivide_width = 63
22+
subdivide_depth = 63
23+
24+
[node name="Cloth" type="SoftBody3D"]
25+
mesh = SubResource("PlaneMesh_6uqi0")
26+
skeleton = NodePath("../..")

3d/soft_body_physics/icon.svg

Lines changed: 1 addition & 0 deletions
Loading

3d/soft_body_physics/icon.svg.import

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
[remap]
2+
3+
importer="texture"
4+
type="CompressedTexture2D"
5+
uid="uid://c5uks4gy25jah"
6+
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
7+
metadata={
8+
"vram_texture": false
9+
}
10+
11+
[deps]
12+
13+
source_file="res://icon.svg"
14+
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
15+
16+
[params]
17+
18+
compress/mode=0
19+
compress/high_quality=false
20+
compress/lossy_quality=0.7
21+
compress/uastc_level=0
22+
compress/rdo_quality_loss=0.0
23+
compress/hdr_compression=1
24+
compress/normal_map=0
25+
compress/channel_pack=0
26+
mipmaps/generate=false
27+
mipmaps/limit=-1
28+
roughness/mode=0
29+
roughness/src_normal=""
30+
process/channel_remap/red=0
31+
process/channel_remap/green=1
32+
process/channel_remap/blue=2
33+
process/channel_remap/alpha=3
34+
process/fix_alpha_border=true
35+
process/premult_alpha=false
36+
process/normal_map_invert_y=false
37+
process/hdr_as_srgb=false
38+
process/hdr_clamp_exposure=false
39+
process/size_limit=0
40+
detect_3d/compress_to=1
41+
svg/scale=1.0
42+
editor/scale_with_editor_scale=false
43+
editor/convert_colors_with_editor_theme=false

3d/soft_body_physics/pin.tscn

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
[gd_scene load_steps=12 format=3 uid="uid://da7gfvk1e0p6i"]
2+
3+
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_g14j6"]
4+
albedo_color = Color(1, 0.27, 0.27, 1)
5+
emission_enabled = true
6+
emission = Color(1, 0, 0, 1)
7+
8+
[sub_resource type="SphereMesh" id="SphereMesh_g14j6"]
9+
material = SubResource("StandardMaterial3D_g14j6")
10+
radius = 0.02
11+
height = 0.04
12+
radial_segments = 16
13+
rings = 8
14+
15+
[sub_resource type="Gradient" id="Gradient_c85u6"]
16+
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
17+
18+
[sub_resource type="GradientTexture1D" id="GradientTexture1D_nikp6"]
19+
gradient = SubResource("Gradient_c85u6")
20+
21+
[sub_resource type="Curve" id="Curve_gflbs"]
22+
_data = [Vector2(0, 1), 0.0, 0.0, 0, 0, Vector2(1, 0), 0.0, 0.0, 0, 0]
23+
point_count = 2
24+
25+
[sub_resource type="CurveTexture" id="CurveTexture_h4t62"]
26+
curve = SubResource("Curve_gflbs")
27+
28+
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_sw3mb"]
29+
spread = 180.0
30+
initial_velocity_max = 0.25
31+
gravity = Vector3(0, 0, 0)
32+
scale_curve = SubResource("CurveTexture_h4t62")
33+
color_ramp = SubResource("GradientTexture1D_nikp6")
34+
35+
[sub_resource type="Gradient" id="Gradient_jfmli"]
36+
interpolation_mode = 2
37+
colors = PackedColorArray(1, 1, 1, 1, 1, 1, 1, 0)
38+
39+
[sub_resource type="GradientTexture2D" id="GradientTexture2D_reuqr"]
40+
gradient = SubResource("Gradient_jfmli")
41+
fill = 1
42+
fill_from = Vector2(0.5, 0.5)
43+
fill_to = Vector2(0.5, 0)
44+
45+
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_c85u6"]
46+
transparency = 1
47+
blend_mode = 1
48+
shading_mode = 0
49+
vertex_color_use_as_albedo = true
50+
albedo_color = Color(1.8247963, 0.60199416, 0.49019507, 1)
51+
albedo_texture = SubResource("GradientTexture2D_reuqr")
52+
billboard_mode = 3
53+
billboard_keep_scale = true
54+
particles_anim_h_frames = 1
55+
particles_anim_v_frames = 1
56+
particles_anim_loop = false
57+
58+
[sub_resource type="QuadMesh" id="QuadMesh_nikp6"]
59+
material = SubResource("StandardMaterial3D_c85u6")
60+
size = Vector2(0.05, 0.05)
61+
62+
[node name="Pin" type="MeshInstance3D"]
63+
cast_shadow = 0
64+
visibility_range_end = 10.0
65+
visibility_range_end_margin = 5.0
66+
visibility_range_fade_mode = 1
67+
mesh = SubResource("SphereMesh_g14j6")
68+
69+
[node name="GPUParticles3D" type="GPUParticles3D" parent="."]
70+
visibility_range_end = 10.0
71+
visibility_range_end_margin = 5.0
72+
visibility_range_fade_mode = 1
73+
amount = 100
74+
process_material = SubResource("ParticleProcessMaterial_sw3mb")
75+
draw_pass_1 = SubResource("QuadMesh_nikp6")
76+
77+
[node name="OmniLight3D" type="OmniLight3D" parent="."]
78+
light_color = Color(1, 0.3137255, 0.2509804, 1)
79+
light_energy = 0.05
80+
light_size = 0.25
81+
distance_fade_enabled = true
82+
distance_fade_begin = 10.0
83+
distance_fade_length = 5.0
84+
omni_range = 0.25
85+
omni_attenuation = 2.0

3d/soft_body_physics/project.godot

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
; Engine configuration file.
2+
; It's best edited using the editor UI and not directly,
3+
; since the parameters that go here are not all obvious.
4+
;
5+
; Format:
6+
; [section] ; section goes between []
7+
; param=value ; assign values to parameters
8+
9+
config_version=5
10+
11+
[application]
12+
13+
config/name="Soft Body Physics"
14+
config/description="An example of soft body physics (deformable objects) such as cloth, boxes and spheres."
15+
config/tags=PackedStringArray("3d", "demo", "official", "rendering")
16+
run/main_scene="res://test.tscn"
17+
config/features=PackedStringArray("4.5")
18+
config/icon="uid://c5uks4gy25jah"
19+
20+
[debug]
21+
22+
settings/physics_interpolation/enable_warnings=false
23+
gdscript/warnings/untyped_declaration=1
24+
25+
[display]
26+
27+
window/stretch/mode="canvas_items"
28+
window/stretch/aspect="expand"
29+
30+
[filesystem]
31+
32+
import/blender/enabled=false
33+
34+
[input]
35+
36+
reset_physics_simulation={
37+
"deadzone": 0.2,
38+
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":82,"physical_keycode":0,"key_label":0,"unicode":114,"location":0,"echo":false,"script":null)
39+
]
40+
}
41+
place_cloth={
42+
"deadzone": 0.2,
43+
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":67,"physical_keycode":0,"key_label":0,"unicode":99,"location":0,"echo":false,"script":null)
44+
]
45+
}
46+
place_light_box={
47+
"deadzone": 0.2,
48+
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":86,"physical_keycode":0,"key_label":0,"unicode":118,"location":0,"echo":false,"script":null)
49+
]
50+
}
51+
place_heavy_box={
52+
"deadzone": 0.2,
53+
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":66,"physical_keycode":0,"key_label":0,"unicode":98,"location":0,"echo":false,"script":null)
54+
]
55+
}
56+
57+
[physics]
58+
59+
3d/physics_engine="Jolt Physics"
60+
common/physics_interpolation=true
61+
62+
[rendering]
63+
64+
lights_and_shadows/directional_shadow/soft_shadow_filter_quality=3
65+
textures/default_filters/anisotropic_filtering_level=4
66+
anti_aliasing/quality/msaa_3d=2
67+
textures/decals/filter=5
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[gd_scene load_steps=7 format=3 uid="uid://hlyf6l5pbqgu"]
2+
3+
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_ppyta"]
4+
friction = 0.75
5+
bounce = 0.4
6+
7+
[sub_resource type="Gradient" id="Gradient_jgx4i"]
8+
interpolation_mode = 2
9+
colors = PackedColorArray(1, 1, 1, 1, 0.5, 0.5, 0.5, 1)
10+
11+
[sub_resource type="GradientTexture2D" id="GradientTexture2D_jypa8"]
12+
gradient = SubResource("Gradient_jgx4i")
13+
fill = 2
14+
fill_from = Vector2(0.5, 0.5)
15+
16+
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ppyta"]
17+
albedo_color = Color(1, 0.298039, 0.74902, 1)
18+
albedo_texture = SubResource("GradientTexture2D_jypa8")
19+
uv1_scale = Vector3(3, 2, 1)
20+
texture_filter = 5
21+
22+
[sub_resource type="BoxMesh" id="BoxMesh_ykrsh"]
23+
material = SubResource("StandardMaterial3D_ppyta")
24+
size = Vector3(0.25, 0.25, 0.25)
25+
26+
[sub_resource type="BoxShape3D" id="BoxShape3D_ppyta"]
27+
size = Vector3(0.25, 0.25, 0.25)
28+
29+
[node name="RigidBoxHeavy" type="RigidBody3D"]
30+
collision_mask = 3
31+
mass = 1000.0
32+
physics_material_override = SubResource("PhysicsMaterial_ppyta")
33+
34+
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
35+
mesh = SubResource("BoxMesh_ykrsh")
36+
37+
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
38+
shape = SubResource("BoxShape3D_ppyta")
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
[gd_scene load_steps=7 format=3 uid="uid://b6uelvj3b82bf"]
2+
3+
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_ppyta"]
4+
friction = 0.75
5+
bounce = 0.4
6+
7+
[sub_resource type="Gradient" id="Gradient_jgx4i"]
8+
interpolation_mode = 2
9+
colors = PackedColorArray(1, 1, 1, 1, 0.5, 0.5, 0.5, 1)
10+
11+
[sub_resource type="GradientTexture2D" id="GradientTexture2D_nmss4"]
12+
gradient = SubResource("Gradient_jgx4i")
13+
fill = 2
14+
fill_from = Vector2(0.5, 0.5)
15+
16+
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ppyta"]
17+
albedo_color = Color(1.8771e-06, 0.751954, 0.25936, 1)
18+
albedo_texture = SubResource("GradientTexture2D_nmss4")
19+
uv1_scale = Vector3(3, 2, 1)
20+
texture_filter = 5
21+
22+
[sub_resource type="BoxMesh" id="BoxMesh_ykrsh"]
23+
material = SubResource("StandardMaterial3D_ppyta")
24+
size = Vector3(0.25, 0.25, 0.25)
25+
26+
[sub_resource type="BoxShape3D" id="BoxShape3D_ppyta"]
27+
size = Vector3(0.25, 0.25, 0.25)
28+
29+
[node name="RigidBoxLight" type="RigidBody3D"]
30+
collision_mask = 3
31+
mass = 10.0
32+
physics_material_override = SubResource("PhysicsMaterial_ppyta")
33+
34+
[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
35+
mesh = SubResource("BoxMesh_ykrsh")
36+
37+
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
38+
shape = SubResource("BoxShape3D_ppyta")
94.9 KB
Binary file not shown.

0 commit comments

Comments
 (0)