generated from krampus/template-godot4
This commit is contained in:
parent
977ca741aa
commit
b0078c1bab
BIN
asset_dev/props/icosahedron.blend
Normal file
BIN
asset_dev/props/icosahedron.blend
Normal file
Binary file not shown.
50
asset_dev/props/icosahedron.blend.import
Normal file
50
asset_dev/props/icosahedron.blend.import
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://bg5qmh1jufujy"
|
||||||
|
valid=false
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://asset_dev/props/icosahedron.blend"
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
_subresources={}
|
||||||
|
blender/nodes/visible=0
|
||||||
|
blender/nodes/active_collection_only=false
|
||||||
|
blender/nodes/punctual_lights=true
|
||||||
|
blender/nodes/cameras=true
|
||||||
|
blender/nodes/custom_properties=true
|
||||||
|
blender/nodes/modifiers=1
|
||||||
|
blender/meshes/colors=false
|
||||||
|
blender/meshes/uvs=true
|
||||||
|
blender/meshes/normals=true
|
||||||
|
blender/meshes/tangents=true
|
||||||
|
blender/meshes/skins=2
|
||||||
|
blender/meshes/export_bones_deforming_mesh_only=false
|
||||||
|
blender/materials/unpack_enabled=true
|
||||||
|
blender/materials/export_materials=1
|
||||||
|
blender/animation/limit_playback=true
|
||||||
|
blender/animation/always_sample=true
|
||||||
|
blender/animation/group_tracks=true
|
BIN
asset_dev/props/monkey.blend
Normal file
BIN
asset_dev/props/monkey.blend
Normal file
Binary file not shown.
50
asset_dev/props/monkey.blend.import
Normal file
50
asset_dev/props/monkey.blend.import
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="scene"
|
||||||
|
importer_version=1
|
||||||
|
type="PackedScene"
|
||||||
|
uid="uid://c43vybloao3v5"
|
||||||
|
valid=false
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://asset_dev/props/monkey.blend"
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
nodes/root_type=""
|
||||||
|
nodes/root_name=""
|
||||||
|
nodes/apply_root_scale=true
|
||||||
|
nodes/root_scale=1.0
|
||||||
|
nodes/import_as_skeleton_bones=false
|
||||||
|
meshes/ensure_tangents=true
|
||||||
|
meshes/generate_lods=true
|
||||||
|
meshes/create_shadow_meshes=true
|
||||||
|
meshes/light_baking=1
|
||||||
|
meshes/lightmap_texel_size=0.2
|
||||||
|
meshes/force_disable_compression=false
|
||||||
|
skins/use_named_skins=true
|
||||||
|
animation/import=true
|
||||||
|
animation/fps=30
|
||||||
|
animation/trimming=false
|
||||||
|
animation/remove_immutable_tracks=true
|
||||||
|
animation/import_rest_as_RESET=false
|
||||||
|
import_script/path=""
|
||||||
|
_subresources={}
|
||||||
|
blender/nodes/visible=0
|
||||||
|
blender/nodes/active_collection_only=false
|
||||||
|
blender/nodes/punctual_lights=true
|
||||||
|
blender/nodes/cameras=true
|
||||||
|
blender/nodes/custom_properties=true
|
||||||
|
blender/nodes/modifiers=1
|
||||||
|
blender/meshes/colors=false
|
||||||
|
blender/meshes/uvs=true
|
||||||
|
blender/meshes/normals=true
|
||||||
|
blender/meshes/tangents=true
|
||||||
|
blender/meshes/skins=2
|
||||||
|
blender/meshes/export_bones_deforming_mesh_only=false
|
||||||
|
blender/materials/unpack_enabled=true
|
||||||
|
blender/materials/export_materials=1
|
||||||
|
blender/animation/limit_playback=true
|
||||||
|
blender/animation/always_sample=true
|
||||||
|
blender/animation/group_tracks=true
|
2
assets/props/icosahedron/icosahedron.mtl
Normal file
2
assets/props/icosahedron/icosahedron.mtl
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Blender 4.3.2 MTL File: 'icosahedron.blend'
|
||||||
|
# www.blender.org
|
79
assets/props/icosahedron/icosahedron.obj
Normal file
79
assets/props/icosahedron/icosahedron.obj
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
# Blender 4.3.2
|
||||||
|
# www.blender.org
|
||||||
|
mtllib icosahedron.mtl
|
||||||
|
o Icosphere
|
||||||
|
v 0.000000 -1.000000 0.000000
|
||||||
|
v 0.723600 -0.447215 0.525720
|
||||||
|
v -0.276385 -0.447215 0.850640
|
||||||
|
v -0.894425 -0.447215 0.000000
|
||||||
|
v -0.276385 -0.447215 -0.850640
|
||||||
|
v 0.723600 -0.447215 -0.525720
|
||||||
|
v 0.276385 0.447215 0.850640
|
||||||
|
v -0.723600 0.447215 0.525720
|
||||||
|
v -0.723600 0.447215 -0.525720
|
||||||
|
v 0.276385 0.447215 -0.850640
|
||||||
|
v 0.894425 0.447215 0.000000
|
||||||
|
v 0.000000 1.000000 0.000000
|
||||||
|
vn 0.1876 -0.7947 0.5774
|
||||||
|
vn 0.6071 -0.7947 -0.0000
|
||||||
|
vn -0.4911 -0.7947 0.3568
|
||||||
|
vn -0.4911 -0.7947 -0.3568
|
||||||
|
vn 0.1876 -0.7947 -0.5774
|
||||||
|
vn 0.9822 -0.1876 -0.0000
|
||||||
|
vn 0.3035 -0.1876 0.9342
|
||||||
|
vn -0.7946 -0.1876 0.5774
|
||||||
|
vn -0.7946 -0.1876 -0.5774
|
||||||
|
vn 0.3035 -0.1876 -0.9342
|
||||||
|
vn 0.7946 0.1876 0.5774
|
||||||
|
vn -0.3035 0.1876 0.9342
|
||||||
|
vn -0.9822 0.1876 -0.0000
|
||||||
|
vn -0.3035 0.1876 -0.9342
|
||||||
|
vn 0.7946 0.1876 -0.5774
|
||||||
|
vn 0.4911 0.7947 0.3568
|
||||||
|
vn -0.1876 0.7947 0.5774
|
||||||
|
vn -0.6071 0.7947 -0.0000
|
||||||
|
vn -0.1876 0.7947 -0.5774
|
||||||
|
vn 0.4911 0.7947 -0.3568
|
||||||
|
vt 0.181819 0.000000
|
||||||
|
vt 0.272728 0.157461
|
||||||
|
vt 0.090910 0.157461
|
||||||
|
vt 0.363637 0.000000
|
||||||
|
vt 0.454546 0.157461
|
||||||
|
vt 0.909091 0.000000
|
||||||
|
vt 1.000000 0.157461
|
||||||
|
vt 0.818182 0.157461
|
||||||
|
vt 0.727273 0.000000
|
||||||
|
vt 0.636364 0.157461
|
||||||
|
vt 0.545455 0.000000
|
||||||
|
vt 0.363637 0.314921
|
||||||
|
vt 0.181819 0.314921
|
||||||
|
vt 0.909091 0.314921
|
||||||
|
vt 0.727273 0.314921
|
||||||
|
vt 0.545455 0.314921
|
||||||
|
vt 0.000000 0.314921
|
||||||
|
vt 0.272728 0.472382
|
||||||
|
vt 0.090910 0.472382
|
||||||
|
vt 0.818182 0.472382
|
||||||
|
vt 0.636364 0.472382
|
||||||
|
vt 0.454546 0.472382
|
||||||
|
s 0
|
||||||
|
f 1/1/1 2/2/1 3/3/1
|
||||||
|
f 2/2/2 1/4/2 6/5/2
|
||||||
|
f 1/6/3 3/7/3 4/8/3
|
||||||
|
f 1/9/4 4/8/4 5/10/4
|
||||||
|
f 1/11/5 5/10/5 6/5/5
|
||||||
|
f 2/2/6 6/5/6 11/12/6
|
||||||
|
f 3/3/7 2/2/7 7/13/7
|
||||||
|
f 4/8/8 3/7/8 8/14/8
|
||||||
|
f 5/10/9 4/8/9 9/15/9
|
||||||
|
f 6/5/10 5/10/10 10/16/10
|
||||||
|
f 2/2/11 11/12/11 7/13/11
|
||||||
|
f 3/3/12 7/13/12 8/17/12
|
||||||
|
f 4/8/13 8/14/13 9/15/13
|
||||||
|
f 5/10/14 9/15/14 10/16/14
|
||||||
|
f 6/5/15 10/16/15 11/12/15
|
||||||
|
f 7/13/16 11/12/16 12/18/16
|
||||||
|
f 8/17/17 7/13/17 12/19/17
|
||||||
|
f 9/15/18 8/14/18 12/20/18
|
||||||
|
f 10/16/19 9/15/19 12/21/19
|
||||||
|
f 11/12/20 10/16/20 12/22/20
|
22
assets/props/icosahedron/icosahedron.obj.import
Normal file
22
assets/props/icosahedron/icosahedron.obj.import
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wavefront_obj"
|
||||||
|
importer_version=1
|
||||||
|
type="Mesh"
|
||||||
|
uid="uid://lvats6ptrcxt"
|
||||||
|
path="res://.godot/imported/icosahedron.obj-8f3e6519933309a73eb5326f98a3de95.mesh"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
files=["res://.godot/imported/icosahedron.obj-8f3e6519933309a73eb5326f98a3de95.mesh"]
|
||||||
|
|
||||||
|
source_file="res://assets/props/icosahedron/icosahedron.obj"
|
||||||
|
dest_files=["res://.godot/imported/icosahedron.obj-8f3e6519933309a73eb5326f98a3de95.mesh", "res://.godot/imported/icosahedron.obj-8f3e6519933309a73eb5326f98a3de95.mesh"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
generate_tangents=true
|
||||||
|
scale_mesh=Vector3(1, 1, 1)
|
||||||
|
offset_mesh=Vector3(0, 0, 0)
|
||||||
|
optimize_mesh=true
|
||||||
|
force_disable_mesh_compression=false
|
2
assets/props/monkey/monkey.mtl
Normal file
2
assets/props/monkey/monkey.mtl
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Blender 4.3.2 MTL File: 'monkey.blend'
|
||||||
|
# www.blender.org
|
2066
assets/props/monkey/monkey.obj
Normal file
2066
assets/props/monkey/monkey.obj
Normal file
File diff suppressed because it is too large
Load Diff
22
assets/props/monkey/monkey.obj.import
Normal file
22
assets/props/monkey/monkey.obj.import
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="wavefront_obj"
|
||||||
|
importer_version=1
|
||||||
|
type="Mesh"
|
||||||
|
uid="uid://e6syamfwiitk"
|
||||||
|
path="res://.godot/imported/monkey.obj-ee24e6fed272edb0c774a26f0a399a12.mesh"
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
files=["res://.godot/imported/monkey.obj-ee24e6fed272edb0c774a26f0a399a12.mesh"]
|
||||||
|
|
||||||
|
source_file="res://assets/props/monkey/monkey.obj"
|
||||||
|
dest_files=["res://.godot/imported/monkey.obj-ee24e6fed272edb0c774a26f0a399a12.mesh", "res://.godot/imported/monkey.obj-ee24e6fed272edb0c774a26f0a399a12.mesh"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
generate_tangents=true
|
||||||
|
scale_mesh=Vector3(1, 1, 1)
|
||||||
|
offset_mesh=Vector3(0, 0, 0)
|
||||||
|
optimize_mesh=true
|
||||||
|
force_disable_mesh_compression=false
|
28
levels/sandbox/debug_draw.gd
Normal file
28
levels/sandbox/debug_draw.gd
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
class_name DebugDraw extends Control
|
||||||
|
|
||||||
|
const COLOR := Color.ORANGE
|
||||||
|
const WIDTH := 4
|
||||||
|
|
||||||
|
var lines: Array = []
|
||||||
|
|
||||||
|
|
||||||
|
func _process(_delta: float) -> void:
|
||||||
|
if visible:
|
||||||
|
queue_redraw()
|
||||||
|
else:
|
||||||
|
lines = []
|
||||||
|
|
||||||
|
|
||||||
|
func draw_vector(vec: Vector3, origin: Vector3) -> void:
|
||||||
|
var camera := get_viewport().get_camera_3d()
|
||||||
|
var start := camera.unproject_position(origin)
|
||||||
|
var end := camera.unproject_position(origin + vec)
|
||||||
|
|
||||||
|
lines.push_back([start, end])
|
||||||
|
|
||||||
|
|
||||||
|
func _draw() -> void:
|
||||||
|
while lines:
|
||||||
|
var line: Array[Vector2] = []
|
||||||
|
line.assign(lines.pop_back() as Array)
|
||||||
|
draw_line(line[0], line[1], COLOR, WIDTH)
|
34
levels/sandbox/debug_gunk_mat.tres
Normal file
34
levels/sandbox/debug_gunk_mat.tres
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[gd_resource type="StandardMaterial3D" load_steps=8 format=3 uid="uid://byyjoruj8mwe0"]
|
||||||
|
|
||||||
|
[ext_resource type="Shader" path="res://src/shaders/gunk.gdshader" id="1_dot5s"]
|
||||||
|
|
||||||
|
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_pinpy"]
|
||||||
|
size = Vector2(256, 256)
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_f8h21"]
|
||||||
|
|
||||||
|
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_dj5ow"]
|
||||||
|
seamless = true
|
||||||
|
noise = SubResource("FastNoiseLite_f8h21")
|
||||||
|
|
||||||
|
[sub_resource type="FastNoiseLite" id="FastNoiseLite_1ennl"]
|
||||||
|
|
||||||
|
[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_kkru7"]
|
||||||
|
seamless = true
|
||||||
|
as_normal_map = true
|
||||||
|
noise = SubResource("FastNoiseLite_1ennl")
|
||||||
|
|
||||||
|
[sub_resource type="ShaderMaterial" id="ShaderMaterial_0jkcp"]
|
||||||
|
render_priority = 0
|
||||||
|
shader = ExtResource("1_dot5s")
|
||||||
|
shader_parameter/color_1 = Color(0, 0.03, 0.1, 1)
|
||||||
|
shader_parameter/color_2 = Color(0, 0.1, 0.3, 1)
|
||||||
|
shader_parameter/roughness = 0.15
|
||||||
|
shader_parameter/specular_contribution = 0.2
|
||||||
|
shader_parameter/gunk_mask = SubResource("PlaceholderTexture2D_pinpy")
|
||||||
|
shader_parameter/gunk_noise = SubResource("NoiseTexture2D_dj5ow")
|
||||||
|
shader_parameter/gunk_normal_map = SubResource("NoiseTexture2D_kkru7")
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
next_pass = SubResource("ShaderMaterial_0jkcp")
|
||||||
|
albedo_color = Color(1, 0.403922, 1, 1)
|
File diff suppressed because one or more lines are too long
@ -2,11 +2,13 @@ class_name Player extends CharacterBody3D
|
|||||||
|
|
||||||
const RUN_SPEED := 80.0
|
const RUN_SPEED := 80.0
|
||||||
const SPRINT_SPEED := 160.0
|
const SPRINT_SPEED := 160.0
|
||||||
const AIR_SPEED := 30.0
|
const AIR_SPEED := 10.0
|
||||||
const JUMP_FORCE := 4.5
|
const JUMP_FORCE := 4.5
|
||||||
const GROUND_FRICTION := 0.3
|
const GROUND_FRICTION := 0.3
|
||||||
const AIR_FRICTION := 0.03
|
const AIR_FRICTION := 0.03
|
||||||
|
|
||||||
|
const SPRAY_RADIUS := 15
|
||||||
|
|
||||||
var gravity: Vector3 = (
|
var gravity: Vector3 = (
|
||||||
ProjectSettings.get_setting("physics/3d/default_gravity")
|
ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||||
* ProjectSettings.get_setting("physics/3d/default_gravity_vector")
|
* ProjectSettings.get_setting("physics/3d/default_gravity_vector")
|
||||||
@ -14,6 +16,8 @@ var gravity: Vector3 = (
|
|||||||
|
|
||||||
@onready var camera_pivot: Node3D = %CameraPivot
|
@onready var camera_pivot: Node3D = %CameraPivot
|
||||||
|
|
||||||
|
@onready var spray_effect: MeshInstance3D = %SprayEffect
|
||||||
|
|
||||||
|
|
||||||
func get_speed() -> float:
|
func get_speed() -> float:
|
||||||
if is_on_floor():
|
if is_on_floor():
|
||||||
@ -29,7 +33,23 @@ func get_friction() -> float:
|
|||||||
return AIR_FRICTION
|
return AIR_FRICTION
|
||||||
|
|
||||||
|
|
||||||
|
func fire_spray() -> void:
|
||||||
|
for raycast: RayCast3D in get_tree().get_nodes_in_group("SprayCast"):
|
||||||
|
if raycast.is_colliding():
|
||||||
|
var collider := raycast.get_collider()
|
||||||
|
if collider is GunkBody:
|
||||||
|
(collider as GunkBody).paint_mask(
|
||||||
|
raycast.get_collision_point(), raycast.get_collision_normal(), SPRAY_RADIUS
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
|
if Input.is_action_pressed("fire"):
|
||||||
|
fire_spray()
|
||||||
|
spray_effect.visible = true
|
||||||
|
else:
|
||||||
|
spray_effect.visible = false
|
||||||
|
|
||||||
# Gravity
|
# Gravity
|
||||||
if not is_on_floor():
|
if not is_on_floor():
|
||||||
velocity += gravity * delta
|
velocity += gravity * delta
|
||||||
|
@ -1,8 +1,24 @@
|
|||||||
[gd_scene load_steps=4 format=3 uid="uid://bwe2jdmvinhqd"]
|
[gd_scene load_steps=8 format=3 uid="uid://bwe2jdmvinhqd"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/player/player.gd" id="1_npueo"]
|
[ext_resource type="Script" path="res://src/player/player.gd" id="1_npueo"]
|
||||||
[ext_resource type="Script" path="res://src/player/camera_controller.gd" id="2_veeqv"]
|
[ext_resource type="Script" path="res://src/player/camera_controller.gd" id="2_veeqv"]
|
||||||
|
|
||||||
|
[sub_resource type="BoxMesh" id="BoxMesh_ua7a2"]
|
||||||
|
size = Vector3(0.05, 0.05, 0.3)
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_ng43h"]
|
||||||
|
transparency = 1
|
||||||
|
shading_mode = 0
|
||||||
|
vertex_color_use_as_albedo = true
|
||||||
|
albedo_color = Color(0, 1, 0.301961, 0.254902)
|
||||||
|
|
||||||
|
[sub_resource type="PrismMesh" id="PrismMesh_ow0jh"]
|
||||||
|
material = SubResource("StandardMaterial3D_ng43h")
|
||||||
|
size = Vector3(1, 2, 0.1)
|
||||||
|
|
||||||
|
[sub_resource type="QuadMesh" id="QuadMesh_cn0yq"]
|
||||||
|
size = Vector2(1, 0.05)
|
||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_s7f0r"]
|
[sub_resource type="CapsuleShape3D" id="CapsuleShape3D_s7f0r"]
|
||||||
|
|
||||||
[node name="Player" type="CharacterBody3D"]
|
[node name="Player" type="CharacterBody3D"]
|
||||||
@ -14,8 +30,44 @@ unique_name_in_owner = true
|
|||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||||
script = ExtResource("2_veeqv")
|
script = ExtResource("2_veeqv")
|
||||||
|
|
||||||
|
[node name="SprayNozzle" type="MeshInstance3D" parent="CameraPivot"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.15, -0.1, -0.1)
|
||||||
|
mesh = SubResource("BoxMesh_ua7a2")
|
||||||
|
|
||||||
|
[node name="SprayMuzzle" type="Marker3D" parent="CameraPivot/SprayNozzle"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.15)
|
||||||
|
|
||||||
|
[node name="RayCast3D" type="RayCast3D" parent="CameraPivot/SprayNozzle/SprayMuzzle" groups=["SprayCast"]]
|
||||||
|
enabled = false
|
||||||
|
target_position = Vector3(-0.4, 0.1, -2)
|
||||||
|
|
||||||
|
[node name="RayCast3D2" type="RayCast3D" parent="CameraPivot/SprayNozzle/SprayMuzzle" groups=["SprayCast"]]
|
||||||
|
target_position = Vector3(-0.2, 0.1, -2)
|
||||||
|
|
||||||
|
[node name="RayCast3D3" type="RayCast3D" parent="CameraPivot/SprayNozzle/SprayMuzzle" groups=["SprayCast"]]
|
||||||
|
target_position = Vector3(0, 0.1, -2)
|
||||||
|
|
||||||
|
[node name="RayCast3D4" type="RayCast3D" parent="CameraPivot/SprayNozzle/SprayMuzzle" groups=["SprayCast"]]
|
||||||
|
target_position = Vector3(0.2, 0.1, -2)
|
||||||
|
|
||||||
|
[node name="RayCast3D5" type="RayCast3D" parent="CameraPivot/SprayNozzle/SprayMuzzle" groups=["SprayCast"]]
|
||||||
|
enabled = false
|
||||||
|
target_position = Vector3(0.4, 0.1, -2)
|
||||||
|
|
||||||
|
[node name="SprayEffect" type="MeshInstance3D" parent="CameraPivot/SprayNozzle/SprayMuzzle"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
transform = Transform3D(1, 0, 0, 0, -0.0697565, -0.997564, 0, 0.997564, -0.0697565, 0, 0.0436133, -1)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("PrismMesh_ow0jh")
|
||||||
|
skeleton = NodePath("../../..")
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="CameraPivot"]
|
[node name="Camera3D" type="Camera3D" parent="CameraPivot"]
|
||||||
current = true
|
current = true
|
||||||
|
|
||||||
|
[node name="SprayZone" type="MeshInstance3D" parent="CameraPivot"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.166592, 0, -2.25)
|
||||||
|
visible = false
|
||||||
|
mesh = SubResource("QuadMesh_cn0yq")
|
||||||
|
|
||||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
[node name="CollisionShape3D" type="CollisionShape3D" parent="."]
|
||||||
shape = SubResource("CapsuleShape3D_s7f0r")
|
shape = SubResource("CapsuleShape3D_s7f0r")
|
||||||
|
30
src/shaders/gunk.gdshader
Normal file
30
src/shaders/gunk.gdshader
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
shader_type spatial;
|
||||||
|
render_mode cull_back;
|
||||||
|
|
||||||
|
uniform vec4 color_1: source_color = vec4(0.0, 0.03, 0.1, 1.0);
|
||||||
|
uniform vec4 color_2: source_color = vec4(0.0, 0.1, 0.3, 1.0);
|
||||||
|
uniform float roughness: hint_range(0.0, 1.0) = 0.15;
|
||||||
|
uniform float specular_contribution = 0.2;
|
||||||
|
|
||||||
|
uniform sampler2D gunk_mask;
|
||||||
|
|
||||||
|
uniform highp sampler2D gunk_noise;
|
||||||
|
uniform highp sampler2D gunk_normal_map;
|
||||||
|
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
float mask = texture(gunk_mask, UV).r;
|
||||||
|
if(mask < 0.1) {
|
||||||
|
float value = texture(gunk_noise, UV).r;
|
||||||
|
vec4 color = mix(color_1, color_2, value);
|
||||||
|
float roughness_mix = value * roughness;
|
||||||
|
|
||||||
|
ALBEDO = color.rgb;
|
||||||
|
ROUGHNESS = roughness_mix;
|
||||||
|
SPECULAR = 0.5 * inversesqrt(specular_contribution);
|
||||||
|
NORMAL_MAP = texture(gunk_normal_map, UV).xyz;
|
||||||
|
ALPHA = 1.0;
|
||||||
|
} else {
|
||||||
|
ALPHA = 0.0;
|
||||||
|
}
|
||||||
|
}
|
96
src/world/gunk_body.gd
Normal file
96
src/world/gunk_body.gd
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
class_name GunkBody extends StaticBody3D
|
||||||
|
## StaticBody3D with an associated "gunkable" mesh.
|
||||||
|
|
||||||
|
const MASK_DIM := 512
|
||||||
|
const FACE_EPSILON := 0.4
|
||||||
|
const MASK_COLOR := Color.RED
|
||||||
|
|
||||||
|
@export var mask_image: Image
|
||||||
|
|
||||||
|
var meshtool := MeshDataTool.new()
|
||||||
|
|
||||||
|
@onready var mesh_instance: MeshInstance3D = $MeshInstance3D
|
||||||
|
@onready var mesh: ArrayMesh = mesh_instance.mesh
|
||||||
|
@onready var gunk_mat: ShaderMaterial = mesh_instance.get_surface_override_material(0).next_pass
|
||||||
|
|
||||||
|
@onready var debug_draw: DebugDraw = %DebugDraw
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not mask_image:
|
||||||
|
mask_image = Image.create_empty(MASK_DIM, MASK_DIM, false, Image.FORMAT_L8)
|
||||||
|
_update_gunk_material()
|
||||||
|
|
||||||
|
meshtool.create_from_surface(mesh, 0)
|
||||||
|
|
||||||
|
|
||||||
|
## Must be called internally whenever `mask_image` is updated
|
||||||
|
func _update_gunk_material() -> void:
|
||||||
|
gunk_mat.set_shader_parameter("gunk_mask", ImageTexture.create_from_image(mask_image))
|
||||||
|
|
||||||
|
|
||||||
|
## Transform cartesian coordinates to barycentric wrt the given triangle
|
||||||
|
func _barycentric(p: Vector3, a: Vector3, b: Vector3, c: Vector3) -> Vector3:
|
||||||
|
var v0 := b - a
|
||||||
|
var v1 := c - a
|
||||||
|
var v2 := p - a
|
||||||
|
var d00 := v0.dot(v0)
|
||||||
|
var d01 := v0.dot(v1)
|
||||||
|
var d11 := v1.dot(v1)
|
||||||
|
var d20 := v2.dot(v0)
|
||||||
|
var d21 := v2.dot(v1)
|
||||||
|
var denom := d00 * d11 - d01 * d01
|
||||||
|
var v := (d11 * d20 - d01 * d21) / denom
|
||||||
|
var w := (d00 * d21 - d01 * d20) / denom
|
||||||
|
var u := 1.0 - v - w
|
||||||
|
return Vector3(u, v, w)
|
||||||
|
|
||||||
|
|
||||||
|
func _is_in_triangle(point: Vector3, v1: Vector3, v2: Vector3, v3: Vector3) -> bool:
|
||||||
|
var bc := _barycentric(point, v1, v2, v3)
|
||||||
|
return (bc.x > 0 and bc.x < 1) and (bc.y > 0 and bc.y < 1) and (bc.z > 0 and bc.z < 1)
|
||||||
|
|
||||||
|
|
||||||
|
func _get_face(point: Vector3, normal: Vector3) -> int:
|
||||||
|
for i in range(meshtool.get_face_count()):
|
||||||
|
if meshtool.get_face_normal(i).distance_squared_to(normal) > FACE_EPSILON:
|
||||||
|
continue
|
||||||
|
# Normals match, so check if the point is on this face
|
||||||
|
var v1 := meshtool.get_vertex(meshtool.get_face_vertex(i, 0))
|
||||||
|
var v2 := meshtool.get_vertex(meshtool.get_face_vertex(i, 1))
|
||||||
|
var v3 := meshtool.get_vertex(meshtool.get_face_vertex(i, 2))
|
||||||
|
if _is_in_triangle(point, v1, v2, v3):
|
||||||
|
return i
|
||||||
|
return -1
|
||||||
|
|
||||||
|
|
||||||
|
func _get_uv(point: Vector3, normal: Vector3) -> Vector2:
|
||||||
|
var face := _get_face(point, normal)
|
||||||
|
if face < 0:
|
||||||
|
return Vector2.INF
|
||||||
|
var fv0 := meshtool.get_face_vertex(face, 0)
|
||||||
|
var fv1 := meshtool.get_face_vertex(face, 1)
|
||||||
|
var fv2 := meshtool.get_face_vertex(face, 2)
|
||||||
|
var v1 := meshtool.get_vertex(fv0)
|
||||||
|
var v2 := meshtool.get_vertex(fv1)
|
||||||
|
var v3 := meshtool.get_vertex(fv2)
|
||||||
|
var bc := _barycentric(point, v1, v2, v3) # TODO memoize
|
||||||
|
var uv1 := meshtool.get_vertex_uv(fv0)
|
||||||
|
var uv2 := meshtool.get_vertex_uv(fv1)
|
||||||
|
var uv3 := meshtool.get_vertex_uv(fv2)
|
||||||
|
return (uv1 * bc.x) + (uv2 * bc.y) + (uv3 * bc.z)
|
||||||
|
|
||||||
|
|
||||||
|
## Paint a rectangle on the mask at a given point & normal on the mesh.
|
||||||
|
func paint_mask(point: Vector3, normal: Vector3, radius: int) -> void:
|
||||||
|
# debug_draw.draw_vector(normal, point)
|
||||||
|
var local_point := point * global_transform
|
||||||
|
var local_normal := normal * global_basis
|
||||||
|
var uv := _get_uv(local_point, local_normal)
|
||||||
|
if uv == Vector2.INF:
|
||||||
|
return
|
||||||
|
var px_center: Vector2i = Vector2i(uv * Vector2(mask_image.get_size()))
|
||||||
|
var rect := Rect2i(px_center.x - radius, px_center.y - radius, 2 * radius, 2 * radius)
|
||||||
|
mask_image.fill_rect(rect, MASK_COLOR)
|
||||||
|
# TODO: can we call this once after all painting in a single frame is finished?
|
||||||
|
_update_gunk_material()
|
Loading…
x
Reference in New Issue
Block a user