Terrain surface material is defined using terrain markers instead of abusing the collision bit fields

This commit is contained in:
Rob Kelly 2025-01-07 11:59:09 -07:00
parent 06d586d8f0
commit d0b4506d80
20 changed files with 343 additions and 148 deletions

View File

@ -36,7 +36,7 @@ loop-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
max-file-lines: 1000
max-line-length: 100
max-public-methods: 40
max-returns: 6
max-returns: 99
mixed-tabs-and-spaces: null
no-elif-return: null
no-else-return: null

View File

@ -3,25 +3,27 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://tancoet1lih5"
path="res://.godot/imported/basic_icon.png-bc904292cc126e1d3e1fd0eb1ba5acc2.ctex"
path.s3tc="res://.godot/imported/basic_icon.png-bc904292cc126e1d3e1fd0eb1ba5acc2.s3tc.ctex"
path.etc2="res://.godot/imported/basic_icon.png-bc904292cc126e1d3e1fd0eb1ba5acc2.etc2.ctex"
metadata={
"vram_texture": false
"imported_formats": ["s3tc_bptc", "etc2_astc"],
"vram_texture": true
}
[deps]
source_file="res://assets/ui/ball_icons/basic_icon.png"
dest_files=["res://.godot/imported/basic_icon.png-bc904292cc126e1d3e1fd0eb1ba5acc2.ctex"]
dest_files=["res://.godot/imported/basic_icon.png-bc904292cc126e1d3e1fd0eb1ba5acc2.s3tc.ctex", "res://.godot/imported/basic_icon.png-bc904292cc126e1d3e1fd0eb1ba5acc2.etc2.ctex"]
[params]
compress/mode=0
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
@ -31,4 +33,4 @@ process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
detect_3d/compress_to=0

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=64 format=3 uid="uid://bm2o3mex10v11"]
[gd_scene load_steps=65 format=3 uid="uid://bm2o3mex10v11"]
[ext_resource type="Terrain3DAssets" uid="uid://cwl34gstabgrx" path="res://levels/debug_level/terrain_assets.res" id="1_5smdk"]
[ext_resource type="Material" uid="uid://drxnue0xsen13" path="res://assets/materials/tropical_water.tres" id="4_bwkbv"]
@ -24,6 +24,7 @@
[ext_resource type="Texture2D" uid="uid://bq8dxuxfw1rwu" path="res://assets/textures/wood/lacquered_planks.png" id="17_xciuf"]
[ext_resource type="Texture2D" path="res://assets/textures/grass_green/grass_green_albedo.dds" id="18_scall"]
[ext_resource type="PackedScene" uid="uid://cblsayfgirexr" path="res://src/characters/umineko/umineko.tscn" id="21_ch6qk"]
[ext_resource type="Script" path="res://src/world/terrain_marker.gd" id="23_7p8cl"]
[sub_resource type="FastNoiseLite" id="FastNoiseLite_rpgb7"]
noise_type = 0
@ -67,12 +68,12 @@ auto_shader = true
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_h8tes"]
panorama = ExtResource("6_ectru")
[sub_resource type="Sky" id="Sky_3yoab"]
[sub_resource type="Sky" id="Sky_x5sbg"]
sky_material = SubResource("PanoramaSkyMaterial_h8tes")
[sub_resource type="Environment" id="Environment_k6wwx"]
background_mode = 2
sky = SubResource("Sky_3yoab")
sky = SubResource("Sky_x5sbg")
ambient_light_source = 2
ambient_light_color = Color(0.78, 0.78, 0.78, 1)
ssao_enabled = true
@ -573,6 +574,10 @@ mesh = SubResource("BoxMesh_jpetf")
[node name="StaticBody3D" type="StaticBody3D" parent="GravityCube/MeshInstance3D"]
[node name="TerrainMarker" type="Node" parent="GravityCube/MeshInstance3D/StaticBody3D"]
script = ExtResource("23_7p8cl")
type = 9
[node name="CollisionShape3D" type="CollisionShape3D" parent="GravityCube/MeshInstance3D/StaticBody3D"]
shape = SubResource("BoxShape3D_74f5g")
@ -639,6 +644,10 @@ mesh = SubResource("SphereMesh_ooxtq")
[node name="StaticBody3D" type="StaticBody3D" parent="GravityOrb/MeshInstance3D"]
[node name="TerrainMarker" type="Node" parent="GravityOrb/MeshInstance3D/StaticBody3D"]
script = ExtResource("23_7p8cl")
type = 5
[node name="CollisionShape3D" type="CollisionShape3D" parent="GravityOrb/MeshInstance3D/StaticBody3D"]
shape = SubResource("SphereShape3D_ne5nm")
@ -658,6 +667,10 @@ transform = Transform3D(2.33934e-08, 0.535178, -0.844739, 1, -4.37114e-08, 0, -3
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="GravityBowl"]
use_collision = true
[node name="TerrainMarker" type="Node" parent="GravityBowl/CSGCombiner3D"]
script = ExtResource("23_7p8cl")
type = 7
[node name="OuterCylinder" type="CSGCylinder3D" parent="GravityBowl/CSGCombiner3D"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 16, 0)
radius = 32.0
@ -689,6 +702,10 @@ transform = Transform3D(0.688355, -0.285755, 0.666717, 0, 0.919135, 0.393942, -0
[node name="CSGCombiner3D" type="CSGCombiner3D" parent="GravityHalo"]
use_collision = true
[node name="TerrainMarker" type="Node" parent="GravityHalo/CSGCombiner3D"]
script = ExtResource("23_7p8cl")
type = 7
[node name="OuterShell" type="CSGTorus3D" parent="GravityHalo/CSGCombiner3D"]
inner_radius = 32.0
outer_radius = 108.0

View File

@ -248,14 +248,6 @@ locale/translations=PackedStringArray("res://assets/text/text.en.translation")
3d_physics/layer_1="Collision Geometry"
3d_physics/layer_2="Water"
3d_physics/layer_25="Green Material"
3d_physics/layer_26="Fairway Material"
3d_physics/layer_27="Glass Material"
3d_physics/layer_28="Metal Material"
3d_physics/layer_29="Rock Material"
3d_physics/layer_30="Wood Material"
3d_physics/layer_31="Sand Material"
3d_physics/layer_32="Grass Material"
[physics]
@ -263,6 +255,7 @@ locale/translations=PackedStringArray("res://assets/text/text.en.translation")
3d/sleep_threshold_angular=2.0
jolt_3d/sleep/velocity_threshold=0.1
jolt_3d/sleep/time_threshold=1.0
jolt_3d/limits/max_angular_velocity=270000.0
jolt_3d/limits/max_temporary_memory=64
[rendering]

View File

@ -20,10 +20,14 @@ const MAGNUS_EPSILON := 1e-3
## If enabled, ball ability cooldown is only reset at end of shot.
@export var once_per_shot_ability := false
## Angular damping while in air
@export var air_damping := 0.0
## Angular damping while in collision with rough terrain
@export var rough_damping := 8.0
## Linear damping while in the air.
@export var aerial_linear_damping := 0.0
## Angular damping while in the air.
@export var aerial_angular_damping := 0.0
## Material physics configuration for this ball.
@export var terrain_physics: TerrainPhysics
#@export var fluid_density := 1.225
#@export var lift_coefficient := 0.05
@ -58,6 +62,8 @@ var _position_on_last_wake: Vector3
var _awake := false
var _ability_triggered := false
var _zones: Array[BallZone] = []
var _shot_time_s := 0.0
var _surface_time_s := 0.0
@onready var ability_cooldown: Timer = %AbilityCooldown
@onready var manual_sleep_timer: Timer = %ManualSleepTimer
@ -68,6 +74,9 @@ var _zones: Array[BallZone] = []
"res://src/equipment/balls/physics_ball/normal_physics.tres"
)
@onready var default_surface_linear_damping := linear_damp
@onready var default_surface_angular_damping := angular_damp
## Should this ball stick to surfaces, rather than bounce?
func is_sticky() -> bool:
@ -102,12 +111,6 @@ func get_damage() -> float:
return base_damage + linear_velocity.length_squared() * damage_force_scale
func _total_terrain_angular_damping() -> float:
return _zones.reduce(
func(a: float, b: BallZone) -> float: return a + b.terrain_angular_damping, 0.0
)
func _magnus_force() -> Vector3:
return magnus_coefficient * radius * angular_velocity.cross(linear_velocity)
@ -120,11 +123,11 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
_ability_triggered = false
_position_on_last_wake = global_position
_last_contact_normal = Vector3.UP
_shot_time_s = 0.0
# TODO something's fucky here... I think this gets called once after the ball sleeps
var damping := air_damping
if state.get_contact_count():
constant_force = Vector3.ZERO
# Ball is in contact with a surface
# We want the contact normal which minimizes the angle to the up vector
var min_dot := -1.0
@ -135,18 +138,39 @@ func _integrate_forces(state: PhysicsDirectBodyState3D) -> void:
min_dot = dot
_last_contact_normal = norm
damping = _total_terrain_angular_damping()
if damping <= TERRAIN_DAMPING_EPSILON:
damping = rough_damping
angular_damp = damping
# Use first contact to determine terrain properties
var primary_body: Node = state.get_contact_collider_object(0)
var terrain := Terrain.from_collision(global_position, primary_body)
var params := terrain_physics.get_params(terrain)
if params:
linear_damp = params.linear_damping
angular_damp = params.angular_damping
else:
linear_damp = default_surface_linear_damping
angular_damp = default_surface_angular_damping
var decay := 1.0 + terrain_physics.get_decay_factor(_surface_time_s)
#linear_damp *= decay
#angular_damp *= decay
_surface_time_s += state.step
else:
# Ball is in the air
linear_damp = aerial_linear_damping
angular_damp = aerial_angular_damping
_surface_time_s = 0.0
func _physics_process(_delta: float) -> void:
func _physics_process(delta: float) -> void:
# Simulate magnus effect
var magnus := _magnus_force()
if magnus.length_squared() > MAGNUS_EPSILON:
apply_central_force(magnus)
# Keep shot time
_shot_time_s += delta
func enter_zone(zone: BallZone) -> void:
_zones.push_back(zone)
@ -182,15 +206,8 @@ func _on_collision(body: Node) -> void:
freeze = true
manual_sleep_timer.start()
var terrain: Terrain.Type
if body is Terrain3D:
terrain = Terrain.at_position(global_position, body as Terrain3D)
elif body is CSGShape3D:
terrain = Terrain.from_physical_layer((body as CSGShape3D).collision_layer)
elif body is CollisionObject3D:
terrain = Terrain.from_physical_layer((body as CollisionObject3D).collision_layer)
else:
print_debug("COLLIDER: ", body)
var terrain := Terrain.from_collision(global_position, body)
print_debug("Collision terrain: ", Terrain.Type.keys()[terrain])
if terrain:
sfx.play_sfx(terrain)

View File

@ -1,8 +1,10 @@
[gd_scene load_steps=25 format=3 uid="uid://dfttci386ohip"]
[gd_scene load_steps=38 format=3 uid="uid://dfttci386ohip"]
[ext_resource type="Script" path="res://src/equipment/balls/physics_ball/game_ball.gd" id="1_iwh2u"]
[ext_resource type="PhysicsMaterial" uid="uid://3bih72l068ic" path="res://src/equipment/balls/physics_ball/normal_physics.tres" id="1_l23pw"]
[ext_resource type="Script" path="res://src/equipment/balls/physics_ball/terrain_physics/terrain_physics.gd" id="3_52hui"]
[ext_resource type="Material" uid="uid://dpsmjlhjpc7vs" path="res://assets/materials/basic_ball_material.tres" id="3_rc7m1"]
[ext_resource type="Script" path="res://src/equipment/balls/physics_ball/terrain_physics/terrain_parameters.gd" id="4_onl6o"]
[ext_resource type="Script" path="res://src/equipment/balls/physics_ball/ball_sfx.gd" id="5_bhshl"]
[ext_resource type="AudioStream" uid="uid://cayyndwmxua5x" path="res://assets/sound/sfx/ball/grass2.wav" id="7_l22cv"]
[ext_resource type="AudioStream" uid="uid://orisjdcj3mes" path="res://assets/sound/sfx/ball/concrete3.wav" id="7_t2ak2"]
@ -15,6 +17,71 @@
[ext_resource type="Texture2D" uid="uid://c47bkx508biqr" path="res://assets/sprites/particles/plasma.png" id="12_guipt"]
[ext_resource type="PackedScene" uid="uid://cm4bb3lg4mfd2" path="res://src/world/effects/splash/splash_effect.tscn" id="12_qlrvx"]
[sub_resource type="Resource" id="Resource_casfi"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 0.5
[sub_resource type="Resource" id="Resource_3k63c"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 8.0
[sub_resource type="Resource" id="Resource_xf73q"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 2.0
[sub_resource type="Resource" id="Resource_nhn3l"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 0.1
[sub_resource type="Resource" id="Resource_m3wjo"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 1.0
[sub_resource type="Resource" id="Resource_h4rld"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 0.1
[sub_resource type="Resource" id="Resource_j6lib"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 2.0
[sub_resource type="Resource" id="Resource_7f7ql"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 8.0
[sub_resource type="Resource" id="Resource_pusmf"]
script = ExtResource("4_onl6o")
linear_damping = 1.0
angular_damping = 24.0
[sub_resource type="Resource" id="Resource_edkxb"]
script = ExtResource("4_onl6o")
linear_damping = 0.0
angular_damping = 1.0
[sub_resource type="Resource" id="Resource_3ngau"]
script = ExtResource("3_52hui")
damping_decay_curve = 12.0
damping_decay_scale = 8.0
default = SubResource("Resource_3k63c")
rough = SubResource("Resource_7f7ql")
fairway = SubResource("Resource_xf73q")
green = SubResource("Resource_m3wjo")
sand = SubResource("Resource_pusmf")
concrete = SubResource("Resource_casfi")
rock = SubResource("Resource_j6lib")
wood = SubResource("Resource_edkxb")
metal = SubResource("Resource_h4rld")
glass = SubResource("Resource_nhn3l")
[sub_resource type="SphereMesh" id="SphereMesh_y0d13"]
material = ExtResource("3_rc7m1")
radius = 0.05
@ -132,14 +199,15 @@ size = Vector2(0.2, 0.2)
[node name="PhysicsBall" type="RigidBody3D"]
mass = 0.05
physics_material_override = ExtResource("1_l23pw")
sleeping = true
freeze = true
continuous_cd = true
contact_monitor = true
max_contacts_reported = 3
linear_damp_mode = 1
angular_damp_mode = 1
angular_damp = 8.0
script = ExtResource("1_iwh2u")
terrain_physics = SubResource("Resource_3ngau")
[node name="BallMesh" type="MeshInstance3D" parent="."]
mesh = SubResource("SphereMesh_y0d13")

View File

@ -0,0 +1,5 @@
class_name TerrainParameters extends Resource
## Physical parameters for an individual terrain type.
@export var linear_damping := 0.0
@export var angular_damping := 0.0

View File

@ -0,0 +1,50 @@
class_name TerrainPhysics extends Resource
## Container for ball behavior parameters when in contact with different terrain types
@export_exp_easing() var damping_decay_curve := 1.0
@export var damping_decay_scale := 8.0
@export var default: TerrainParameters
@export var rough: TerrainParameters
@export var fairway: TerrainParameters
@export var green: TerrainParameters
@export var sand: TerrainParameters
@export var concrete: TerrainParameters
@export var rock: TerrainParameters
@export var wood: TerrainParameters
@export var metal: TerrainParameters
@export var glass: TerrainParameters
func get_params(type: Terrain.Type) -> TerrainParameters:
# NOTE: sure would be nice to just store this in a dict,
# but that makes editing physics through the editor unweildy.
match type:
Terrain.Type.ROUGH:
return rough
Terrain.Type.FAIRWAY:
return fairway
Terrain.Type.GREEN:
return green
Terrain.Type.SAND:
return sand
Terrain.Type.CONCRETE:
return concrete
Terrain.Type.ROCK:
return rock
Terrain.Type.WOOD:
return wood
Terrain.Type.METAL:
return metal
Terrain.Type.GLASS:
return glass
_:
return default
func get_decay_factor(time: float) -> float:
var x := time / damping_decay_scale
if damping_decay_curve < 1.0:
return 1.0 - pow(1.0 - x, 1.0 / damping_decay_curve)
return pow(x, damping_decay_curve)

View File

@ -1,7 +1,7 @@
class_name Game extends Node
## Wrapper for the game application
@export var start_scene: String = "res://src/ui/menus/title_screen/title_screen.tscn"
@export_file("*.tscn") var start_scene: String = "res://src/ui/menus/title_screen/title_screen.tscn"
var _loading_resources := {}

View File

@ -119,6 +119,7 @@ _data = {
[node name="Game" type="Node" groups=["GameGroup"]]
process_mode = 3
script = ExtResource("1_4qa87")
start_scene = "res://src/world/world.tscn"
[node name="RootControl" type="Control" parent="."]
unique_name_in_owner = true

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://dagh38vap4t1d"]
[gd_scene load_steps=4 format=3 uid="uid://dagh38vap4t1d"]
[ext_resource type="PackedScene" uid="uid://mhycq1tk1bpm" path="res://assets/models/scenery/city/concrete_building_1/concrete_building_1.gltf" id="1_id6ph"]
[ext_resource type="Script" path="res://src/world/terrain_marker.gd" id="2_5x2lp"]
[sub_resource type="BoxShape3D" id="BoxShape3D_5g4vq"]
size = Vector3(16, 24, 16)
@ -9,6 +10,10 @@ size = Vector3(16, 24, 16)
[node name="StaticBody3D" type="StaticBody3D" parent="." index="1"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0"]
[node name="TerrainMarker" type="Node" parent="StaticBody3D" index="0"]
script = ExtResource("2_5x2lp")
type = 5
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="1"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 12, 0)
shape = SubResource("BoxShape3D_5g4vq")

View File

@ -1,7 +1,8 @@
[gd_scene load_steps=5 format=3 uid="uid://cjubxs7peir5k"]
[gd_scene load_steps=6 format=3 uid="uid://cjubxs7peir5k"]
[ext_resource type="PackedScene" uid="uid://hwc1px831dgm" path="res://assets/models/scenery/city/kana_signboard/kana_signboard.gltf" id="1_o4tvg"]
[ext_resource type="Texture2D" uid="uid://d0lsrrx0r5wnu" path="res://assets/models/scenery/city/kana_signboard/kana_signboard.png" id="2_85s5u"]
[ext_resource type="Script" path="res://src/world/terrain_marker.gd" id="3_dllon"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_dwyvb"]
albedo_texture = ExtResource("2_85s5u")
@ -18,13 +19,17 @@ surface_material_override/0 = SubResource("StandardMaterial3D_dwyvb")
[node name="StaticBody3D" type="StaticBody3D" parent="." index="3"]
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0"]
[node name="TerrainMarker" type="Node" parent="StaticBody3D" index="0"]
script = ExtResource("3_dllon")
type = 8
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="1"]
shape = SubResource("BoxShape3D_kp4b0")
[node name="CollisionShape3D2" type="CollisionShape3D" parent="StaticBody3D" index="1"]
[node name="CollisionShape3D2" type="CollisionShape3D" parent="StaticBody3D" index="2"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, 1.2)
shape = SubResource("BoxShape3D_kp4b0")
[node name="CollisionShape3D3" type="CollisionShape3D" parent="StaticBody3D" index="2"]
[node name="CollisionShape3D3" type="CollisionShape3D" parent="StaticBody3D" index="3"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.5, 1.2)
shape = SubResource("BoxShape3D_kp4b0")

View File

@ -1,10 +1,11 @@
[gd_scene load_steps=5 format=3 uid="uid://nqar1qcun8ax"]
[gd_scene load_steps=6 format=3 uid="uid://nqar1qcun8ax"]
[ext_resource type="Script" path="res://src/props/scenery/highway/guard_rail/guard_rail.gd" id="1_imntf"]
[ext_resource type="Material" uid="uid://cift6p0wn1oce" path="res://assets/materials/guard_rail.tres" id="2_1s4wy"]
[ext_resource type="PlaneMesh" uid="uid://bdcmgvgpj1e0w" path="res://src/props/scenery/highway/guard_rail/guard_rail_post_mesh.tres" id="3_hha2c"]
[ext_resource type="Script" path="res://src/world/terrain_marker.gd" id="3_nfjvf"]
[sub_resource type="MultiMesh" id="MultiMesh_1o4mq"]
[sub_resource type="MultiMesh" id="MultiMesh_1dcl6"]
transform_format = 1
mesh = ExtResource("3_hha2c")
@ -26,6 +27,10 @@ path_u_distance = 1.0
path_joined = false
material = ExtResource("2_1s4wy")
[node name="TerrainMarker" type="Node" parent="UpperRail"]
script = ExtResource("3_nfjvf")
type = 8
[node name="LowerRail" type="CSGPolygon3D" parent="."]
use_collision = true
polygon = PackedVector2Array(0, 0.4, -0.01, 0.5, 0, 0.6, 0.01, 0.5)
@ -41,7 +46,11 @@ path_u_distance = 1.0
path_joined = false
material = ExtResource("2_1s4wy")
[node name="TerrainMarker" type="Node" parent="LowerRail"]
script = ExtResource("3_nfjvf")
type = 8
[node name="PostMultiMesh" type="MultiMeshInstance3D" parent="."]
multimesh = SubResource("MultiMesh_1o4mq")
multimesh = SubResource("MultiMesh_1dcl6")
[connection signal="curve_changed" from="." to="." method="_on_curve_changed"]

View File

@ -1,6 +1,7 @@
[gd_scene load_steps=3 format=3 uid="uid://d0tcr6uijpym5"]
[gd_scene load_steps=4 format=3 uid="uid://d0tcr6uijpym5"]
[ext_resource type="Texture2D" uid="uid://dloe67udf7fpd" path="res://assets/textures/highway/highway_road_grass.png" id="1_f3xui"]
[ext_resource type="Script" path="res://src/world/terrain_marker.gd" id="2_4f0hb"]
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_nkovu"]
transparency = 1
@ -25,3 +26,7 @@ path_continuous_u = true
path_u_distance = 1.0
path_joined = false
material = SubResource("StandardMaterial3D_nkovu")
[node name="TerrainMarker" type="Node" parent="CSGPolygon3D"]
script = ExtResource("2_4f0hb")
type = 5

View File

@ -1,6 +1,7 @@
[gd_scene load_steps=8 format=3 uid="uid://di7aql54lksn7"]
[gd_scene load_steps=9 format=3 uid="uid://di7aql54lksn7"]
[ext_resource type="PackedScene" uid="uid://bgdgd3lky5w60" path="res://assets/models/scenery/trees/palm_tree/palm_tree.gltf" id="1_o3thn"]
[ext_resource type="Script" path="res://src/world/terrain_marker.gd" id="2_1lamy"]
[sub_resource type="ConcavePolygonShape3D" id="ConcavePolygonShape3D_bp5t6"]
data = PackedVector3Array(-0.6467, 5.2727, -3.6037, -0.7678, 3.663, -4.1571, 0.0705, 4.1529, -5.0529, 0.1793, 5.4514, -3.9613, 1.1035, 5.3325, -3.712, 0.2063, 5.6673, -3.3214, 0.2063, 5.6673, -3.3214, 1.1035, 5.3325, -3.712, 0.2526, 6.0382, -2.2225, -0.102, 1.5632, -4.5545, 0.9292, 3.4191, -4.4363, 0.0705, 4.1529, -5.0529, 0.0705, 4.1529, -5.0529, -0.7379, 3.4651, -4.2526, -0.102, 1.5632, -4.5545, 0.0705, 4.1529, -5.0529, 0.992, 3.6309, -4.3423, 1.1035, 5.3325, -3.712, 0.0705, 4.1529, -5.0529, 1.1035, 5.3325, -3.712, 0.1793, 5.4514, -3.9613, 0.0705, 4.1529, -5.0529, 0.1793, 5.4514, -3.9613, -0.6467, 5.2727, -3.6037, 0.2063, 5.6673, -3.3214, 0.2526, 6.0382, -2.2225, -0.4953, 5.4015, -3.3712, 0.2063, 5.6673, -3.3214, -0.6467, 5.2727, -3.6037, 0.1793, 5.4514, -3.9613)
@ -44,26 +45,35 @@ bones/10/rotation = Quaternion(0.183326, -0.237737, -0.342496, 0.890264)
bones/10/scale = Vector3(1, 1, 1)
bones/11/rotation = Quaternion(-0.13894, 0.0183908, 0.000355869, 0.99013)
[node name="StaticBody3D" type="StaticBody3D" parent="." index="2"]
collision_layer = 2147483649
[node name="LeafBody" type="StaticBody3D" parent="." index="2"]
[node name="CollisionShape3D2" type="CollisionShape3D" parent="StaticBody3D" index="0"]
[node name="TerrainMarker" type="Node" parent="LeafBody" index="0"]
script = ExtResource("2_1lamy")
type = 1
[node name="CollisionShape3D2" type="CollisionShape3D" parent="LeafBody" index="1"]
shape = SubResource("ConcavePolygonShape3D_bp5t6")
[node name="CollisionShape3D3" type="CollisionShape3D" parent="StaticBody3D" index="1"]
[node name="CollisionShape3D3" type="CollisionShape3D" parent="LeafBody" index="2"]
shape = SubResource("ConcavePolygonShape3D_j5qxc")
[node name="CollisionShape3D4" type="CollisionShape3D" parent="StaticBody3D" index="2"]
[node name="CollisionShape3D4" type="CollisionShape3D" parent="LeafBody" index="3"]
shape = SubResource("ConcavePolygonShape3D_eopyd")
[node name="CollisionShape3D5" type="CollisionShape3D" parent="StaticBody3D" index="3"]
[node name="CollisionShape3D5" type="CollisionShape3D" parent="LeafBody" index="4"]
shape = SubResource("ConcavePolygonShape3D_npgp7")
[node name="CollisionShape3D6" type="CollisionShape3D" parent="StaticBody3D" index="4"]
[node name="CollisionShape3D6" type="CollisionShape3D" parent="LeafBody" index="5"]
shape = SubResource("ConcavePolygonShape3D_xl1fh")
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="5"]
[node name="TrunkBody" type="StaticBody3D" parent="." index="3"]
[node name="TerrainMarker" type="Node" parent="TrunkBody" index="0"]
script = ExtResource("2_1lamy")
type = 7
[node name="CollisionShape3D" type="CollisionShape3D" parent="TrunkBody" index="1"]
shape = SubResource("ConcavePolygonShape3D_lol7j")
[node name="AnimationPlayer" parent="." index="3"]
[node name="AnimationPlayer" parent="." index="4"]
autoplay = "sway_circle"

View File

@ -64,25 +64,25 @@ void fragment() {
vec2 centered_uv = (UV - 0.5) * size;
float radius = length(centered_uv);
float angle = atan(centered_uv.y, centered_uv.x) + PI; // Add PI to fix left side cutoff
vec2 ray1 = vec2(angle * ray1_density + TIME * speed + seed + sin(angle * 3.0), radius * 2.0);
vec2 ray2 = vec2(angle * ray2_density + TIME * speed * 1.5 + seed + cos(angle * 2.0), radius * 2.0);
float cut = 1.0 - smoothstep(cutoff, cutoff + 0.2, radius);
ray1 *= cut;
ray2 *= cut;
float rays = hdr ?
float rays = hdr ?
noise(ray1) + (noise(ray2) * ray2_intensity) :
clamp(noise(ray1) + (noise(ray2) * ray2_intensity), 0., 1.);
rays *= smoothstep(spread, spread * 0.3, radius);
float core = smoothstep(0.2, 0.0, radius) * core_intensity;
rays += core;
vec4 gradient_color = texture(gradient, vec2(rays, 0.5));
vec3 shine = vec3(rays) * gradient_color.rgb;
float blur_amount = radius * 0.1;
vec2 blur_uv = SCREEN_UV + centered_uv * blur_amount;
vec4 blurred = texture(SCREEN_TEXTURE, blur_uv);

View File

@ -110,6 +110,57 @@ particles_anim_loop = false
material = SubResource("StandardMaterial3D_l1irr")
size = Vector2(0.1, 0.1)
[sub_resource type="Animation" id="Animation_mg6va"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Decal:size")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(2, 4, 2)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Decal:modulate")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("SprayParticles:emitting")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("BubbleParticles:emitting")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="Animation" id="Animation_ifddj"]
resource_name = "effect"
length = 2.0
@ -176,57 +227,6 @@ tracks/4/keys = {
}]
}
[sub_resource type="Animation" id="Animation_mg6va"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Decal:size")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector3(2, 4, 2)]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("Decal:modulate")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Color(1, 1, 1, 1)]
}
tracks/2/type = "value"
tracks/2/imported = false
tracks/2/enabled = true
tracks/2/path = NodePath("SprayParticles:emitting")
tracks/2/interp = 1
tracks/2/loop_wrap = true
tracks/2/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
tracks/3/type = "value"
tracks/3/imported = false
tracks/3/enabled = true
tracks/3/path = NodePath("BubbleParticles:emitting")
tracks/3/interp = 1
tracks/3/loop_wrap = true
tracks/3/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [false]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_87fye"]
_data = {
"RESET": SubResource("Animation_mg6va"),

View File

@ -16,17 +16,7 @@ enum Type {
GLASS,
}
## We use the upper bits of collision layers to encode material data
const PHYSICAL_LAYERS := {
1 << 31: Type.ROUGH,
1 << 30: Type.SAND,
1 << 29: Type.WOOD,
1 << 28: Type.ROCK,
1 << 27: Type.METAL,
1 << 26: Type.GLASS,
1 << 25: Type.FAIRWAY,
1 << 24: Type.GREEN,
}
const DEFAULT_MATERIAL := Type.CONCRETE
## Get the `Terrain.Type` value which corresponds to the given Terrain3D texture ID.
@ -46,18 +36,18 @@ static func from_texture_id(tex_id: int) -> Type:
4:
return Type.ROCK
_:
return Type.NONE
return DEFAULT_MATERIAL
## Get the `Terrain.Type` value encoded in the given collision layer setting.
## Get the `Terrain.Type` value associated with a collision body.
##
## We use the upper bits in the collision layer to encode material data.
## Check the collision layer descriptions for more information.
static func from_physical_layer(collision_layer: int) -> Type:
for bit: int in PHYSICAL_LAYERS:
if collision_layer & bit:
return PHYSICAL_LAYERS[bit]
return Type.CONCRETE
## This returns the type stored in the first `TerrainMarker` direct child of the body.
## Use this method to set the terrain type of arbitrary bodies!
static func from_body(body: Node) -> Type:
for n: Node in body.get_children():
if n is TerrainMarker:
return (n as TerrainMarker).type
return DEFAULT_MATERIAL
## Get the `Terrain.Type` value at the given position in a Terrain3D node.
@ -69,3 +59,13 @@ static func at_position(global_position: Vector3, terrain3d: Terrain3D) -> Type:
else:
id = int(blend.x)
return from_texture_id(id)
## Get the Terrain.Type value at the given position for the given body.
##
## Position is only used when colliding with a Terrain3D node.
## Other bodies will have one material type for the entire body node.
static func from_collision(global_position: Vector3, body: Node) -> Type:
if body is Terrain3D:
return Terrain.at_position(global_position, body as Terrain3D)
return Terrain.from_body(body)

View File

@ -0,0 +1,4 @@
class_name TerrainMarker extends Node
## Marks the terrain type of a parent collision body.
@export var type: Terrain.Type