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 SPRINT_SPEED := 160.0
|
||||
const AIR_SPEED := 30.0
|
||||
const AIR_SPEED := 10.0
|
||||
const JUMP_FORCE := 4.5
|
||||
const GROUND_FRICTION := 0.3
|
||||
const AIR_FRICTION := 0.03
|
||||
|
||||
const SPRAY_RADIUS := 15
|
||||
|
||||
var gravity: Vector3 = (
|
||||
ProjectSettings.get_setting("physics/3d/default_gravity")
|
||||
* ProjectSettings.get_setting("physics/3d/default_gravity_vector")
|
||||
@ -14,6 +16,8 @@ var gravity: Vector3 = (
|
||||
|
||||
@onready var camera_pivot: Node3D = %CameraPivot
|
||||
|
||||
@onready var spray_effect: MeshInstance3D = %SprayEffect
|
||||
|
||||
|
||||
func get_speed() -> float:
|
||||
if is_on_floor():
|
||||
@ -29,7 +33,23 @@ func get_friction() -> float:
|
||||
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:
|
||||
if Input.is_action_pressed("fire"):
|
||||
fire_spray()
|
||||
spray_effect.visible = true
|
||||
else:
|
||||
spray_effect.visible = false
|
||||
|
||||
# Gravity
|
||||
if not is_on_floor():
|
||||
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/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"]
|
||||
|
||||
[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)
|
||||
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"]
|
||||
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="."]
|
||||
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