Adds bushes and flowers to ground tiles
Implements bush and flower spawning on ground tiles based on vegetation density. Adds new assets for bushes and flowers, and introduces multi-mesh rendering for optimized performance. Introduces seasonal color variations for vegetation using a shader for bushes and materials for flowers and grass. Refactors material application into a MaterialManager to handle material assignments over multiple frames. Moves ground tile scripts into a subfolder. Adds floating particles to test scene.
This commit is contained in:
parent
ea5006e8a2
commit
3959333534
46 changed files with 559 additions and 77 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,3 +1,4 @@
|
||||||
# Godot 4+ specific ignores
|
# Godot 4+ specific ignores
|
||||||
.godot/
|
.godot/
|
||||||
/android/
|
/android/
|
||||||
|
*.tmp
|
||||||
BIN
Entities/Bush/assets/bush_large.res
Normal file
BIN
Entities/Bush/assets/bush_large.res
Normal file
Binary file not shown.
BIN
Entities/Bush/assets/bush_small.res
Normal file
BIN
Entities/Bush/assets/bush_small.res
Normal file
Binary file not shown.
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://c3objh5he4fv7"
|
uid="uid://c3objh5he4fv7"
|
||||||
path="res://.godot/imported/plant_bush.glb-e9806d63c67fa60c2bf9125a46d34412.scn"
|
path="res://.godot/imported/plant_bush.glb-4eaf384fbf61c7e3b82505202bc9874e.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entities/Tree/assets/temp/plant_bush.glb"
|
source_file="res://Entities/Bush/assets/plant_bush.glb"
|
||||||
dest_files=["res://.godot/imported/plant_bush.glb-e9806d63c67fa60c2bf9125a46d34412.scn"]
|
dest_files=["res://.godot/imported/plant_bush.glb-4eaf384fbf61c7e3b82505202bc9874e.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://cefyfwcx88gn8"
|
uid="uid://cefyfwcx88gn8"
|
||||||
path="res://.godot/imported/plant_bushDetailed.glb-b49c41eb141c3e76fb272adf14466b5a.scn"
|
path="res://.godot/imported/plant_bushDetailed.glb-8633db2639023d65ffc045b449119f56.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entities/Tree/assets/temp/plant_bushDetailed.glb"
|
source_file="res://Entities/Bush/assets/plant_bushDetailed.glb"
|
||||||
dest_files=["res://.godot/imported/plant_bushDetailed.glb-b49c41eb141c3e76fb272adf14466b5a.scn"]
|
dest_files=["res://.godot/imported/plant_bushDetailed.glb-8633db2639023d65ffc045b449119f56.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -32,6 +32,17 @@ animation/trimming=false
|
||||||
animation/remove_immutable_tracks=true
|
animation/remove_immutable_tracks=true
|
||||||
animation/import_rest_as_RESET=false
|
animation/import_rest_as_RESET=false
|
||||||
import_script/path=""
|
import_script/path=""
|
||||||
_subresources={}
|
_subresources={
|
||||||
|
"meshes": {
|
||||||
|
"plant_bushDetailed_Mesh plant_bushDetailed": {
|
||||||
|
"generate/lightmap_uv": 0,
|
||||||
|
"generate/lods": 0,
|
||||||
|
"generate/shadow_meshes": 0,
|
||||||
|
"lods/normal_merge_angle": 60.0,
|
||||||
|
"save_to_file/enabled": true,
|
||||||
|
"save_to_file/path": "res://Entities/Bush/assets/bush_large.res"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
gltf/naming_version=1
|
gltf/naming_version=1
|
||||||
gltf/embedded_image_handling=1
|
gltf/embedded_image_handling=1
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://bqh742nyfy67t"
|
uid="uid://bqh742nyfy67t"
|
||||||
path="res://.godot/imported/plant_bushLarge.glb-444f7e2fefa42d9967360c2460aba973.scn"
|
path="res://.godot/imported/plant_bushLarge.glb-034f46e010fc48537badbba708af03b9.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entities/Tree/assets/temp/plant_bushLarge.glb"
|
source_file="res://Entities/Bush/assets/plant_bushLarge.glb"
|
||||||
dest_files=["res://.godot/imported/plant_bushLarge.glb-444f7e2fefa42d9967360c2460aba973.scn"]
|
dest_files=["res://.godot/imported/plant_bushLarge.glb-034f46e010fc48537badbba708af03b9.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://xj45kysvl047"
|
uid="uid://xj45kysvl047"
|
||||||
path="res://.godot/imported/plant_bushLargeTriangle.glb-9e831461ae4497bcbdb95549623cbaf6.scn"
|
path="res://.godot/imported/plant_bushLargeTriangle.glb-4c2a6e5fedd13bffdd9cfb0a212c89c8.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entities/Tree/assets/temp/plant_bushLargeTriangle.glb"
|
source_file="res://Entities/Bush/assets/plant_bushLargeTriangle.glb"
|
||||||
dest_files=["res://.godot/imported/plant_bushLargeTriangle.glb-9e831461ae4497bcbdb95549623cbaf6.scn"]
|
dest_files=["res://.godot/imported/plant_bushLargeTriangle.glb-4c2a6e5fedd13bffdd9cfb0a212c89c8.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://cjoyr61xdo3hx"
|
uid="uid://cjoyr61xdo3hx"
|
||||||
path="res://.godot/imported/plant_bushSmall.glb-636059e56114bd2f2c7902ac6a574e3a.scn"
|
path="res://.godot/imported/plant_bushSmall.glb-2218874f9d8b685dac1fd79232f82be8.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entities/Tree/assets/temp/plant_bushSmall.glb"
|
source_file="res://Entities/Bush/assets/plant_bushSmall.glb"
|
||||||
dest_files=["res://.godot/imported/plant_bushSmall.glb-636059e56114bd2f2c7902ac6a574e3a.scn"]
|
dest_files=["res://.godot/imported/plant_bushSmall.glb-2218874f9d8b685dac1fd79232f82be8.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -32,6 +32,17 @@ animation/trimming=false
|
||||||
animation/remove_immutable_tracks=true
|
animation/remove_immutable_tracks=true
|
||||||
animation/import_rest_as_RESET=false
|
animation/import_rest_as_RESET=false
|
||||||
import_script/path=""
|
import_script/path=""
|
||||||
_subresources={}
|
_subresources={
|
||||||
|
"meshes": {
|
||||||
|
"plant_bushSmall_Mesh plant_bushSmall": {
|
||||||
|
"generate/lightmap_uv": 0,
|
||||||
|
"generate/lods": 0,
|
||||||
|
"generate/shadow_meshes": 0,
|
||||||
|
"lods/normal_merge_angle": 60.0,
|
||||||
|
"save_to_file/enabled": true,
|
||||||
|
"save_to_file/path": "res://Entities/Bush/assets/bush_small.res"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
gltf/naming_version=1
|
gltf/naming_version=1
|
||||||
gltf/embedded_image_handling=1
|
gltf/embedded_image_handling=1
|
||||||
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://dsch27pqxgud5"
|
uid="uid://dsch27pqxgud5"
|
||||||
path="res://.godot/imported/plant_bushTriangle.glb-68d6459f20861ebce284d042b5ea0419.scn"
|
path="res://.godot/imported/plant_bushTriangle.glb-518273ba96c29be659e875adddc31676.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entities/Tree/assets/temp/plant_bushTriangle.glb"
|
source_file="res://Entities/Bush/assets/plant_bushTriangle.glb"
|
||||||
dest_files=["res://.godot/imported/plant_bushTriangle.glb-68d6459f20861ebce284d042b5ea0419.scn"]
|
dest_files=["res://.godot/imported/plant_bushTriangle.glb-518273ba96c29be659e875adddc31676.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
[gd_scene load_steps=13 format=3 uid="uid://bwcevwwphdvq"]
|
[gd_scene load_steps=17 format=3 uid="uid://bwcevwwphdvq"]
|
||||||
|
|
||||||
[ext_resource type="Script" uid="uid://bq7hia2dit80y" path="res://Entities/GroundTile/ground_tile.gd" id="1_uwxqs"]
|
[ext_resource type="Script" uid="uid://bq7hia2dit80y" path="res://Entities/GroundTile/scripts/ground_tile.gd" id="1_uwxqs"]
|
||||||
[ext_resource type="ArrayMesh" uid="uid://duj6747nq4qsk" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass.res" id="3_8mhad"]
|
[ext_resource type="ArrayMesh" uid="uid://duj6747nq4qsk" path="res://Stages/Test3D/assets/stylizedGrassMeshes/grass.res" id="3_8mhad"]
|
||||||
[ext_resource type="Script" uid="uid://cacp8ncwuofuj" path="res://Entities/GroundTile/scripts/grass.gd" id="3_224hx"]
|
[ext_resource type="Script" uid="uid://cacp8ncwuofuj" path="res://Entities/GroundTile/scripts/grass.gd" id="3_224hx"]
|
||||||
[ext_resource type="Material" uid="uid://b1miqvl8lus75" path="res://Stages/Test3D/GrassMaterialOverride.tres" id="3_f37ob"]
|
[ext_resource type="Material" uid="uid://b1miqvl8lus75" path="res://Stages/Test3D/GrassMaterialOverride.tres" id="3_f37ob"]
|
||||||
[ext_resource type="Script" uid="uid://btju6b83mvgvk" path="res://Entities/GroundTile/scripts/grass_multimesh.gd" id="4_3wpcb"]
|
[ext_resource type="Script" uid="uid://btju6b83mvgvk" path="res://Entities/GroundTile/scripts/grass_multimesh.gd" id="4_3wpcb"]
|
||||||
|
[ext_resource type="Script" uid="uid://bt67yhdkwtqy5" path="res://Entities/GroundTile/scripts/bushes.gd" id="6_224hx"]
|
||||||
[ext_resource type="Script" uid="uid://cqko4m7cbxsfb" path="res://Entities/GroundTile/scripts/trees.gd" id="7_7lc7k"]
|
[ext_resource type="Script" uid="uid://cqko4m7cbxsfb" path="res://Entities/GroundTile/scripts/trees.gd" id="7_7lc7k"]
|
||||||
|
[ext_resource type="Script" uid="uid://dri5tubavplji" path="res://Entities/GroundTile/scripts/bush_multimesh.gd" id="7_jysav"]
|
||||||
|
[ext_resource type="Script" uid="uid://d3s0u7rm1y7i6" path="res://Entities/GroundTile/scripts/flower_multimesh.gd" id="8_jysav"]
|
||||||
|
[ext_resource type="Script" uid="uid://18vxtm3ua4x0" path="res://Entities/GroundTile/scripts/flowers.gd" id="8_q0r4p"]
|
||||||
|
|
||||||
[sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"]
|
[sub_resource type="ViewportTexture" id="ViewportTexture_h4g11"]
|
||||||
viewport_path = NodePath("DebugText/DebugTextViewport")
|
viewport_path = NodePath("DebugText/DebugTextViewport")
|
||||||
|
|
@ -67,5 +71,33 @@ script = ExtResource("4_3wpcb")
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0111763, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0111763, 0)
|
||||||
mesh = SubResource("PlaneMesh_f37ob")
|
mesh = SubResource("PlaneMesh_f37ob")
|
||||||
|
|
||||||
|
[node name="Bushes" type="Node3D" parent="."]
|
||||||
|
script = ExtResource("6_224hx")
|
||||||
|
|
||||||
|
[node name="BushMultimesh" type="MultiMeshInstance3D" parent="Bushes"]
|
||||||
|
cast_shadow = 0
|
||||||
|
multimesh = SubResource("MultiMesh_3wpcb")
|
||||||
|
script = ExtResource("7_jysav")
|
||||||
|
|
||||||
|
[node name="BushTarget" type="MeshInstance3D" parent="Bushes"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0111763, 0)
|
||||||
|
mesh = SubResource("PlaneMesh_f37ob")
|
||||||
|
|
||||||
|
[node name="Flowers" type="Node3D" parent="."]
|
||||||
|
script = ExtResource("8_q0r4p")
|
||||||
|
|
||||||
|
[node name="FlowerMultimesh" type="MultiMeshInstance3D" parent="Flowers"]
|
||||||
|
cast_shadow = 0
|
||||||
|
multimesh = SubResource("MultiMesh_3wpcb")
|
||||||
|
script = ExtResource("8_jysav")
|
||||||
|
|
||||||
|
[node name="FloewerTarget" type="MeshInstance3D" parent="Flowers"]
|
||||||
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0111763, 0)
|
||||||
|
mesh = SubResource("PlaneMesh_f37ob")
|
||||||
|
|
||||||
[node name="Trees" type="Node3D" parent="."]
|
[node name="Trees" type="Node3D" parent="."]
|
||||||
script = ExtResource("7_7lc7k")
|
script = ExtResource("7_7lc7k")
|
||||||
|
|
||||||
|
[node name="Special" type="Node3D" parent="."]
|
||||||
|
|
||||||
|
[node name="Rocks" type="Node3D" parent="Special"]
|
||||||
|
|
|
||||||
56
Entities/GroundTile/scripts/bush_multimesh.gd
Normal file
56
Entities/GroundTile/scripts/bush_multimesh.gd
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
extends MultiMeshInstance3D
|
||||||
|
var mm: MultiMesh
|
||||||
|
var parent_node: BushController
|
||||||
|
static var bush_mesh: Mesh = null
|
||||||
|
var material: ShaderMaterial
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
parent_node = get_parent() as BushController
|
||||||
|
if parent_node == null:
|
||||||
|
Log.pr("Error: Parent node is not a BushController!")
|
||||||
|
|
||||||
|
# Load mesh once and reuse
|
||||||
|
if bush_mesh == null:
|
||||||
|
bush_mesh = load("res://Entities/Bush/assets/bush_large.res")
|
||||||
|
|
||||||
|
func setup_multimesh() -> void:
|
||||||
|
if parent_node == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
if bush_mesh == null:
|
||||||
|
Log.pr("Error: Could not load bush mesh")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Reuse existing MultiMesh if possible, or create new one
|
||||||
|
if mm == null:
|
||||||
|
mm = MultiMesh.new()
|
||||||
|
mm.transform_format = MultiMesh.TRANSFORM_3D
|
||||||
|
mm.mesh = bush_mesh
|
||||||
|
|
||||||
|
material = ColorData.get_random_bush_material(Season.current)
|
||||||
|
mm.mesh.surface_set_material(0, material)
|
||||||
|
|
||||||
|
# Configure instance count
|
||||||
|
mm.instance_count = parent_node.bush_instance_range
|
||||||
|
|
||||||
|
# Get shared RNG from GroundTile
|
||||||
|
var rng = parent_node.parent_node.get_rng()
|
||||||
|
|
||||||
|
# Generate positions using shared RNG
|
||||||
|
for i in range(mm.instance_count):
|
||||||
|
var random_pos = Vector3(
|
||||||
|
rng.randf_range(-1.0, 1.0),
|
||||||
|
0.0,
|
||||||
|
rng.randf_range(-1.0, 1.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
var random_rotation = rng.randf_range(0.0, TAU)
|
||||||
|
var basis = Basis(Vector3.UP, random_rotation)
|
||||||
|
|
||||||
|
var random_scale = rng.randf_range(0.3, 0.9)
|
||||||
|
basis = basis.scaled(Vector3(random_scale, random_scale, random_scale))
|
||||||
|
|
||||||
|
var tx = Transform3D(basis, random_pos)
|
||||||
|
mm.set_instance_transform(i, tx)
|
||||||
|
|
||||||
|
multimesh = mm
|
||||||
1
Entities/GroundTile/scripts/bush_multimesh.gd.uid
Normal file
1
Entities/GroundTile/scripts/bush_multimesh.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://dri5tubavplji
|
||||||
36
Entities/GroundTile/scripts/bushes.gd
Normal file
36
Entities/GroundTile/scripts/bushes.gd
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
# GrassController.gd
|
||||||
|
extends Node3D
|
||||||
|
class_name BushController
|
||||||
|
|
||||||
|
@onready var bush_multimesh: MultiMeshInstance3D = $BushMultimesh
|
||||||
|
var parent_node: GroundTile = null
|
||||||
|
var bush_density: float = 0.5
|
||||||
|
var bush_instance_range: int = 10
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
parent_node = get_parent() as GroundTile
|
||||||
|
|
||||||
|
func spawn_bushes_for_cell(value):
|
||||||
|
if value == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
bush_density = value.vegetation_density
|
||||||
|
update_bush_density()
|
||||||
|
|
||||||
|
if bush_multimesh and bush_multimesh.has_method("setup_multimesh"):
|
||||||
|
bush_multimesh.setup_multimesh()
|
||||||
|
|
||||||
|
func update_bush_density() -> void:
|
||||||
|
if parent_node == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var rng = parent_node.get_rng()
|
||||||
|
|
||||||
|
if bush_density > 0.8:
|
||||||
|
bush_instance_range = rng.randi_range(5, 10)
|
||||||
|
elif bush_density > 0.6:
|
||||||
|
bush_instance_range = rng.randi_range(2, 7)
|
||||||
|
elif bush_density > 0.3:
|
||||||
|
bush_instance_range = rng.randi_range(0, 1)
|
||||||
|
else:
|
||||||
|
bush_instance_range = rng.randi_range(0, 0)
|
||||||
1
Entities/GroundTile/scripts/bushes.gd.uid
Normal file
1
Entities/GroundTile/scripts/bushes.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bt67yhdkwtqy5
|
||||||
59
Entities/GroundTile/scripts/flower_multimesh.gd
Normal file
59
Entities/GroundTile/scripts/flower_multimesh.gd
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
extends MultiMeshInstance3D
|
||||||
|
|
||||||
|
var mm: MultiMesh
|
||||||
|
var parent_node: FlowerController
|
||||||
|
static var flower_mesh: Mesh = null
|
||||||
|
var material: StandardMaterial3D
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
parent_node = get_parent() as FlowerController
|
||||||
|
if parent_node == null:
|
||||||
|
Log.pr("Error: Parent node is not a FlowerController!")
|
||||||
|
|
||||||
|
# Load mesh once and reuse
|
||||||
|
if flower_mesh == null:
|
||||||
|
flower_mesh = load("res://Entities/Plant/assets/flower_tall.res")
|
||||||
|
|
||||||
|
func setup_multimesh() -> void:
|
||||||
|
if parent_node == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
if flower_mesh == null:
|
||||||
|
Log.pr("Error: Could not load flower mesh")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Reuse existing MultiMesh if possible, or create new one
|
||||||
|
if mm == null:
|
||||||
|
mm = MultiMesh.new()
|
||||||
|
mm.transform_format = MultiMesh.TRANSFORM_3D
|
||||||
|
mm.mesh = flower_mesh
|
||||||
|
|
||||||
|
var flower_material = ColorData.flower_materials[Season.current]["flower"]
|
||||||
|
var stem_material = ColorData.flower_materials[Season.current]["stem"]
|
||||||
|
mm.mesh.surface_set_material(0, stem_material)
|
||||||
|
mm.mesh.surface_set_material(1, flower_material)
|
||||||
|
|
||||||
|
# Configure instance count
|
||||||
|
mm.instance_count = parent_node.flower_instance_range
|
||||||
|
|
||||||
|
# Get shared RNG from GroundTile
|
||||||
|
var rng = parent_node.parent_node.get_rng()
|
||||||
|
|
||||||
|
# Generate positions using shared RNG
|
||||||
|
for i in range(mm.instance_count):
|
||||||
|
var random_pos = Vector3(
|
||||||
|
rng.randf_range(-1.0, 1.0),
|
||||||
|
0.0,
|
||||||
|
rng.randf_range(-1.0, 1.0)
|
||||||
|
)
|
||||||
|
|
||||||
|
var random_rotation = rng.randf_range(0.0, TAU)
|
||||||
|
var basis = Basis(Vector3.UP, random_rotation)
|
||||||
|
|
||||||
|
var random_scale = rng.randf_range(0.2, 0.4)
|
||||||
|
basis = basis.scaled(Vector3(random_scale, random_scale, random_scale))
|
||||||
|
|
||||||
|
var tx = Transform3D(basis, random_pos)
|
||||||
|
mm.set_instance_transform(i, tx)
|
||||||
|
|
||||||
|
multimesh = mm
|
||||||
1
Entities/GroundTile/scripts/flower_multimesh.gd.uid
Normal file
1
Entities/GroundTile/scripts/flower_multimesh.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://d3s0u7rm1y7i6
|
||||||
36
Entities/GroundTile/scripts/flowers.gd
Normal file
36
Entities/GroundTile/scripts/flowers.gd
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
# GrassController.gd
|
||||||
|
extends Node3D
|
||||||
|
class_name FlowerController
|
||||||
|
|
||||||
|
@onready var flower_multimesh: MultiMeshInstance3D = $FlowerMultimesh
|
||||||
|
var parent_node: GroundTile = null
|
||||||
|
var flower_density: float = 0.5
|
||||||
|
var flower_instance_range: int = 10
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
parent_node = get_parent() as GroundTile
|
||||||
|
|
||||||
|
func spawn_flowers_for_cell(value):
|
||||||
|
if value == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
flower_density = value.vegetation_density
|
||||||
|
update_flower_density()
|
||||||
|
|
||||||
|
if flower_multimesh and flower_multimesh.has_method("setup_multimesh"):
|
||||||
|
flower_multimesh.setup_multimesh()
|
||||||
|
|
||||||
|
func update_flower_density() -> void:
|
||||||
|
if parent_node == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
var rng = parent_node.get_rng()
|
||||||
|
|
||||||
|
if flower_density > 0.8:
|
||||||
|
flower_instance_range = rng.randi_range(1, 3)
|
||||||
|
elif flower_density > 0.6:
|
||||||
|
flower_instance_range = rng.randi_range(3, 4)
|
||||||
|
elif flower_density > 0.3:
|
||||||
|
flower_instance_range = rng.randi_range(4, 7)
|
||||||
|
else:
|
||||||
|
flower_instance_range = rng.randi_range(5, 10)
|
||||||
1
Entities/GroundTile/scripts/flowers.gd.uid
Normal file
1
Entities/GroundTile/scripts/flowers.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://18vxtm3ua4x0
|
||||||
|
|
@ -25,6 +25,8 @@ func setup_multimesh() -> void:
|
||||||
mm = MultiMesh.new()
|
mm = MultiMesh.new()
|
||||||
mm.transform_format = MultiMesh.TRANSFORM_3D
|
mm.transform_format = MultiMesh.TRANSFORM_3D
|
||||||
mm.mesh = grass_mesh
|
mm.mesh = grass_mesh
|
||||||
|
update_shader_parameter('top_color', ColorData.grass_materials[Season.current]['top'])
|
||||||
|
update_shader_parameter('bottom_color', ColorData.grass_materials[Season.current]['base'])
|
||||||
|
|
||||||
# Configure instance count
|
# Configure instance count
|
||||||
mm.instance_count = parent_node.grass_instance_range
|
mm.instance_count = parent_node.grass_instance_range
|
||||||
|
|
@ -51,3 +53,18 @@ func setup_multimesh() -> void:
|
||||||
|
|
||||||
multimesh = mm
|
multimesh = mm
|
||||||
cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
cast_shadow = GeometryInstance3D.SHADOW_CASTING_SETTING_OFF
|
||||||
|
|
||||||
|
|
||||||
|
func update_shader_parameter(param_name: String, value) -> void:
|
||||||
|
if material_override == null:
|
||||||
|
Log.pr("Error: No material override found")
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check if it's a ShaderMaterial
|
||||||
|
if material_override is ShaderMaterial:
|
||||||
|
var shader_material = material_override as ShaderMaterial
|
||||||
|
shader_material.set_shader_parameter(param_name, value)
|
||||||
|
else:
|
||||||
|
Log.pr("Error: Material override is not a ShaderMaterial")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,9 @@ extends Node3D
|
||||||
@onready var debug_text: Label = $DebugText/DebugTextViewport/DebugTextLabel
|
@onready var debug_text: Label = $DebugText/DebugTextViewport/DebugTextLabel
|
||||||
@onready var tree_spawner = $Trees
|
@onready var tree_spawner = $Trees
|
||||||
@onready var grass_spawner = $Grass
|
@onready var grass_spawner = $Grass
|
||||||
|
@onready var bush_spawner = $Bushes
|
||||||
|
@onready var flower_spawner = $Flowers
|
||||||
|
@onready var ground = $Ground
|
||||||
var grid_x: int
|
var grid_x: int
|
||||||
var grid_z: int
|
var grid_z: int
|
||||||
var cell_info: CellDataResource = null
|
var cell_info: CellDataResource = null
|
||||||
|
|
@ -19,6 +22,8 @@ func _ready() -> void:
|
||||||
spawn_content()
|
spawn_content()
|
||||||
update_text_label()
|
update_text_label()
|
||||||
|
|
||||||
|
ground.material_override.albedo_color = ColorData.grass_materials[Season.current]['base']
|
||||||
|
|
||||||
func get_rng() -> RandomClass:
|
func get_rng() -> RandomClass:
|
||||||
if cached_rng == null and cell_info:
|
if cached_rng == null and cell_info:
|
||||||
cached_rng = RandomClass.get_seeded_instance(cell_info.cell_seed)
|
cached_rng = RandomClass.get_seeded_instance(cell_info.cell_seed)
|
||||||
|
|
@ -44,6 +49,11 @@ func spawn_content():
|
||||||
tree_spawner.spawn_trees_for_cell(cell_info)
|
tree_spawner.spawn_trees_for_cell(cell_info)
|
||||||
if grass_spawner:
|
if grass_spawner:
|
||||||
grass_spawner.spawn_grass_for_cell(cell_info)
|
grass_spawner.spawn_grass_for_cell(cell_info)
|
||||||
|
if bush_spawner:
|
||||||
|
bush_spawner.spawn_bushes_for_cell(cell_info)
|
||||||
|
if flower_spawner:
|
||||||
|
flower_spawner.spawn_flowers_for_cell(cell_info)
|
||||||
|
|
||||||
|
|
||||||
func update_text_label() -> void:
|
func update_text_label() -> void:
|
||||||
debug_text.text = str(cell_info.vegetation_density)
|
debug_text.text = str(cell_info.vegetation_density)
|
||||||
BIN
Entities/Plant/assets/flower.res
Normal file
BIN
Entities/Plant/assets/flower.res
Normal file
Binary file not shown.
|
|
@ -4,12 +4,12 @@ importer="scene"
|
||||||
importer_version=1
|
importer_version=1
|
||||||
type="PackedScene"
|
type="PackedScene"
|
||||||
uid="uid://c8kl0a1nstbuc"
|
uid="uid://c8kl0a1nstbuc"
|
||||||
path="res://.godot/imported/flower_purpleB.glb-69a5b0606a51601fdd91762f296ce88b.scn"
|
path="res://.godot/imported/flower_tall.glb-105aa1c03f7501793bbf8ad0e150a0ed.scn"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
|
|
||||||
source_file="res://Entities/Tree/assets/temp/flower_purpleB.glb"
|
source_file="res://Entities/Plant/assets/flower_tall.glb"
|
||||||
dest_files=["res://.godot/imported/flower_purpleB.glb-69a5b0606a51601fdd91762f296ce88b.scn"]
|
dest_files=["res://.godot/imported/flower_tall.glb-105aa1c03f7501793bbf8ad0e150a0ed.scn"]
|
||||||
|
|
||||||
[params]
|
[params]
|
||||||
|
|
||||||
|
|
@ -32,6 +32,17 @@ animation/trimming=false
|
||||||
animation/remove_immutable_tracks=true
|
animation/remove_immutable_tracks=true
|
||||||
animation/import_rest_as_RESET=false
|
animation/import_rest_as_RESET=false
|
||||||
import_script/path=""
|
import_script/path=""
|
||||||
_subresources={}
|
_subresources={
|
||||||
|
"meshes": {
|
||||||
|
"flower_tall_Mesh flower_purpleB": {
|
||||||
|
"generate/lightmap_uv": 0,
|
||||||
|
"generate/lods": 0,
|
||||||
|
"generate/shadow_meshes": 0,
|
||||||
|
"lods/normal_merge_angle": 60.0,
|
||||||
|
"save_to_file/enabled": true,
|
||||||
|
"save_to_file/path": "res://Entities/Plant/assets/flower.res"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
gltf/naming_version=1
|
gltf/naming_version=1
|
||||||
gltf/embedded_image_handling=1
|
gltf/embedded_image_handling=1
|
||||||
BIN
Entities/Plant/assets/flower_tall.res
Normal file
BIN
Entities/Plant/assets/flower_tall.res
Normal file
Binary file not shown.
|
|
@ -104,5 +104,5 @@ func update_material_in_mesh_instance(mesh_instance: MeshInstance3D, material_na
|
||||||
|
|
||||||
|
|
||||||
func apply_material_with_queue(mesh_instance: MeshInstance3D, index: int, material: StandardMaterial3D):
|
func apply_material_with_queue(mesh_instance: MeshInstance3D, index: int, material: StandardMaterial3D):
|
||||||
ColorData.queue_material_application(mesh_instance, index, material)
|
MaterialManager.queue_material_application(mesh_instance, index, material)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ func spawn_model():
|
||||||
|
|
||||||
# Instantiate the model from the TreeDataResource
|
# Instantiate the model from the TreeDataResource
|
||||||
model_instance = tree_data.model.instantiate()
|
model_instance = tree_data.model.instantiate()
|
||||||
tree_data.apply_seasonal_colors(model_instance, "spring")
|
tree_data.apply_seasonal_colors(model_instance, Season.current)
|
||||||
add_child(model_instance)
|
add_child(model_instance)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,48 +3,44 @@ extends Node
|
||||||
|
|
||||||
var tree_collection = preload("res://Entities/Tree/Resources/TreeData.tres") as TreeDataCollection
|
var tree_collection = preload("res://Entities/Tree/Resources/TreeData.tres") as TreeDataCollection
|
||||||
var tree_materials: Dictionary = {}
|
var tree_materials: Dictionary = {}
|
||||||
var grass_materials: Dictionary = {"spring": {"base": Vector3(0.196, 0.392, 0.196), "top": Vector3(0.253, 0.492, 0.253), "bottom": Vector3(0.196, 0.392, 0.196)},
|
var grass_materials: Dictionary = {
|
||||||
"summer": {"base": null, "top": null, "bottom": null},
|
"spring": {
|
||||||
"autumn": {"base": null, "top": null, "bottom": null},
|
"bottom": Color(0.18, 0.35, 0.12), # #2e5920 - Dark forest base
|
||||||
"winter": {"base": null, "top": null, "bottom": null}}
|
"top": Color(0.18, 0.35, 0.12), # Color(0.35, 0.65, 0.25), # #59a640 - Bright spring green
|
||||||
|
"base": Color(0.12, 0.25, 0.08), # #1f4014 - Deep shadow green
|
||||||
|
"flower": Color(0.776, 0.835, 0.855) # rgb(198, 213, 218) - Spring flower color
|
||||||
## TODO - Move this out into its own class
|
},
|
||||||
var material_application_queue: Array = []
|
"summer": {
|
||||||
var max_materials_per_frame: int = 10 # Adjust based on performance
|
"bottom": Color(0.22, 0.45, 0.18), # #38732e - Rich summer base
|
||||||
|
"top": Color(0.22, 0.45, 0.18), # Color(0.4, 0.75, 0.3), # #66bf4d - Sun-kissed green
|
||||||
|
"base": Color(0.15, 0.3, 0.12), # #264d1f - Shaded summer base
|
||||||
|
"flower": Color(0.408, 0.537, 0.886) # rgb(104, 137, 226) - Summer flower color
|
||||||
|
},
|
||||||
|
"autumn": {
|
||||||
|
"bottom": Color(0.35, 0.4, 0.15), # #596626 - Yellowing grass
|
||||||
|
"top": Color(0.42, 0.45, 0.19), # #6b7330 - Muted autumn tips
|
||||||
|
"base": Color(0.25, 0.25, 0.1), # #40401a - Dying grass base
|
||||||
|
"flower": Color(0.820, 0.337, 0.318) # rgb(209, 86, 81) - Autumn flower color
|
||||||
|
},
|
||||||
|
"winter": {
|
||||||
|
"bottom": Color(0.25, 0.3, 0.2), # #404d33 - Dormant green-brown
|
||||||
|
"top": Color(0.35, 0.4, 0.3), # #59664d - Frost-touched tips
|
||||||
|
"base": Color(0.2, 0.2, 0.15), # #333326 - Winter soil color
|
||||||
|
"flower": Color(1.0, 0.8, 0.6) # #ffd9b3 - Winter flower color
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var bush_materials: Dictionary = {}
|
||||||
|
var flower_materials: Dictionary = {}
|
||||||
|
|
||||||
@export var tree_colours: Array
|
@export var tree_colours: Array
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
populate_tree_colors()
|
populate_tree_colors()
|
||||||
Log.pr("Tree colors populated: %d trees" % tree_materials.size())
|
Log.pr("Tree colors populated: %d trees" % tree_materials.size())
|
||||||
|
populate_bush_materials()
|
||||||
func _process(_delta):
|
Log.pr("Bush materials populated: %d seasons" % bush_materials.size())
|
||||||
# Process material applications gradually over multiple frames
|
populate_flower_materials()
|
||||||
process_material_queue()
|
Log.pr("Flower materials populated: %d seasons" % flower_materials.size())
|
||||||
|
|
||||||
func process_material_queue():
|
|
||||||
var processed = 0
|
|
||||||
while material_application_queue.size() > 0 and processed < max_materials_per_frame:
|
|
||||||
var task = material_application_queue.pop_front()
|
|
||||||
|
|
||||||
# Check if the mesh instance is still valid before applying
|
|
||||||
if is_instance_valid(task.mesh_instance) and task.mesh_instance != null:
|
|
||||||
apply_material_immediately(task.mesh_instance, task.surface_index, task.material)
|
|
||||||
# If invalid, just skip this task (object was freed)
|
|
||||||
|
|
||||||
processed += 1
|
|
||||||
|
|
||||||
func queue_material_application(mesh_instance: MeshInstance3D, surface_index: int, material: StandardMaterial3D):
|
|
||||||
material_application_queue.append({
|
|
||||||
"mesh_instance": mesh_instance,
|
|
||||||
"surface_index": surface_index,
|
|
||||||
"material": material
|
|
||||||
})
|
|
||||||
|
|
||||||
func apply_material_immediately(mesh_instance: MeshInstance3D, surface_index: int, material: StandardMaterial3D):
|
|
||||||
if is_instance_valid(mesh_instance):
|
|
||||||
mesh_instance.set_surface_override_material(surface_index, material)
|
|
||||||
|
|
||||||
# Create materials once at startup
|
# Create materials once at startup
|
||||||
func populate_tree_colors() -> void:
|
func populate_tree_colors() -> void:
|
||||||
|
|
@ -117,3 +113,53 @@ func get_random_trunk_material(tree_name: String, season: String) -> StandardMat
|
||||||
return trunk_materials[random_key]
|
return trunk_materials[random_key]
|
||||||
|
|
||||||
return create_material(Color(0.6, 0.4, 0.2), "fallback_trunk")
|
return create_material(Color(0.6, 0.4, 0.2), "fallback_trunk")
|
||||||
|
|
||||||
|
func populate_bush_materials() -> void:
|
||||||
|
for season in Season.seasons:
|
||||||
|
bush_materials[season] = {
|
||||||
|
"1": create_bush_material(grass_materials[season]["base"], grass_materials[season]["flower"].lightened(0.1), "bush_base_%s" % season)
|
||||||
|
}
|
||||||
|
Log.pr("Bush materials populated for seasons: %s" % bush_materials.keys())
|
||||||
|
|
||||||
|
func create_bush_material(color: Color, variation: Color, material_name: String) -> ShaderMaterial:
|
||||||
|
var material = ShaderMaterial.new()
|
||||||
|
|
||||||
|
var shader = load("res://leaves.gdshader")
|
||||||
|
|
||||||
|
material.shader = shader
|
||||||
|
material.resource_name = material_name
|
||||||
|
|
||||||
|
material.set_shader_parameter("base_color", color)
|
||||||
|
material.set_shader_parameter("variation_color", variation)
|
||||||
|
|
||||||
|
return material
|
||||||
|
|
||||||
|
func get_random_bush_material(season: String) -> ShaderMaterial:
|
||||||
|
if bush_materials.has(season):
|
||||||
|
var bush_materials_season = bush_materials[season]
|
||||||
|
var material_keys = bush_materials_season.keys()
|
||||||
|
if material_keys.size() > 0:
|
||||||
|
var random_key = material_keys[randi() % material_keys.size()]
|
||||||
|
return bush_materials_season[random_key]
|
||||||
|
|
||||||
|
Log.pr("No bush materials found for season: %s, returning fallback." % season)
|
||||||
|
return create_bush_material(Color.GREEN, Color.GREEN, "fallback_bush")
|
||||||
|
|
||||||
|
func populate_flower_materials() -> void:
|
||||||
|
for season in Season.seasons:
|
||||||
|
flower_materials[season] = {
|
||||||
|
"flower": create_material(grass_materials[season]['flower'], "flower_base_%s" % season),
|
||||||
|
"stem": create_material(grass_materials[season]["top"], "flower_stem_%s" % season),
|
||||||
|
}
|
||||||
|
Log.pr("Flower materials populated for seasons: %s" % flower_materials.keys())
|
||||||
|
|
||||||
|
func get_random_flower_material(season: String) -> StandardMaterial3D:
|
||||||
|
if flower_materials.has(season):
|
||||||
|
var flower_materials_season = flower_materials[season]
|
||||||
|
var material_keys = flower_materials_season.keys()
|
||||||
|
if material_keys.size() > 0:
|
||||||
|
var random_key = material_keys[randi() % material_keys.size()]
|
||||||
|
return flower_materials_season[random_key]
|
||||||
|
|
||||||
|
Log.pr("No flower materials found for season: %s, returning fallback." % season)
|
||||||
|
return create_material(Color(1.0, 1.0, 0.5), "fallback_flower")
|
||||||
|
|
|
||||||
30
Utilities/MaterialManager/MaterialManager.gd
Normal file
30
Utilities/MaterialManager/MaterialManager.gd
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
class_name MaterialManagerClass
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var material_application_queue: Array = []
|
||||||
|
var max_materials_per_frame: int = 20 # Adjust based on performance
|
||||||
|
|
||||||
|
func _process(_delta):
|
||||||
|
# Process material applications gradually over multiple frames
|
||||||
|
process_material_queue()
|
||||||
|
|
||||||
|
func process_material_queue():
|
||||||
|
var processed = 0
|
||||||
|
while material_application_queue.size() > 0 and processed < max_materials_per_frame:
|
||||||
|
var task = material_application_queue.pop_front()
|
||||||
|
|
||||||
|
if is_instance_valid(task.mesh_instance) and task.mesh_instance != null:
|
||||||
|
apply_material_immediately(task.mesh_instance, task.surface_index, task.material)
|
||||||
|
|
||||||
|
processed += 1
|
||||||
|
|
||||||
|
func queue_material_application(mesh_instance: MeshInstance3D, surface_index: int, material: StandardMaterial3D):
|
||||||
|
material_application_queue.append({
|
||||||
|
"mesh_instance": mesh_instance,
|
||||||
|
"surface_index": surface_index,
|
||||||
|
"material": material
|
||||||
|
})
|
||||||
|
|
||||||
|
func apply_material_immediately(mesh_instance: MeshInstance3D, surface_index: int, material: StandardMaterial3D):
|
||||||
|
if is_instance_valid(mesh_instance):
|
||||||
|
mesh_instance.set_surface_override_material(surface_index, material)
|
||||||
1
Utilities/MaterialManager/MaterialManager.gd.uid
Normal file
1
Utilities/MaterialManager/MaterialManager.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://hxkwqb71371n
|
||||||
11
Utilities/Seasons/seasons.gd
Normal file
11
Utilities/Seasons/seasons.gd
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
class_name SeasonController
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
var seasons: Array = [
|
||||||
|
"spring",
|
||||||
|
"summer",
|
||||||
|
"autumn",
|
||||||
|
"winter"
|
||||||
|
]
|
||||||
|
|
||||||
|
@export var current: String = "autumn"
|
||||||
1
Utilities/Seasons/seasons.gd.uid
Normal file
1
Utilities/Seasons/seasons.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://buj63lgb7ckto
|
||||||
23
leaves.gdshader
Normal file
23
leaves.gdshader
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
shader_type spatial;
|
||||||
|
uniform vec4 base_color : source_color = vec4(0.2, 0.6, 0.1, 1.0);
|
||||||
|
uniform vec4 variation_color : source_color = vec4(0.4, 0.8, 0.2, 1.0);
|
||||||
|
uniform float gradient_height : hint_range(0.1, 5.0) = 2.0;
|
||||||
|
uniform float gradient_offset : hint_range(-2.0, 2.0) = 0.0;
|
||||||
|
|
||||||
|
varying vec3 world_position;
|
||||||
|
|
||||||
|
void vertex() {
|
||||||
|
world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
// Use world Y position instead of UV
|
||||||
|
float gradient_factor = (world_position.y + gradient_offset) / gradient_height;
|
||||||
|
gradient_factor = clamp(gradient_factor, 0.0, 1.0);
|
||||||
|
|
||||||
|
vec3 final_color = mix(base_color.rgb, variation_color.rgb, gradient_factor);
|
||||||
|
|
||||||
|
ALBEDO = final_color;
|
||||||
|
ROUGHNESS = 0.8;
|
||||||
|
METALLIC = 0.0;
|
||||||
|
}
|
||||||
1
leaves.gdshader.uid
Normal file
1
leaves.gdshader.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://d0e60a0hdk02j
|
||||||
|
|
@ -25,6 +25,8 @@ BiomeData="*res://Utilities/BiomeGeneration/BiomeData.gd"
|
||||||
MapData="*res://Utilities/MapData/MapData.gd"
|
MapData="*res://Utilities/MapData/MapData.gd"
|
||||||
ColorData="*res://Utilities/ColorStorage/ColorStorage.gd"
|
ColorData="*res://Utilities/ColorStorage/ColorStorage.gd"
|
||||||
MapPopulation="*res://Utilities/MapData/MapPopulation.gd"
|
MapPopulation="*res://Utilities/MapData/MapPopulation.gd"
|
||||||
|
MaterialManager="*res://Utilities/MaterialManager/MaterialManager.gd"
|
||||||
|
Season="*res://Utilities/Seasons/seasons.gd"
|
||||||
|
|
||||||
[editor_plugins]
|
[editor_plugins]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
[gd_scene load_steps=45 format=4 uid="uid://bwsugg4p50fjr"]
|
[gd_scene load_steps=46 format=4 uid="uid://bwsugg4p50fjr"]
|
||||||
|
|
||||||
[ext_resource type="Environment" uid="uid://cm77bbr0io118" path="res://Stages/Test3D/new_environment.tres" id="1_8ph61"]
|
[ext_resource type="Environment" uid="uid://cm77bbr0io118" path="res://Stages/Test3D/new_environment.tres" id="1_8ph61"]
|
||||||
[ext_resource type="Script" uid="uid://bwed2dwogfmxv" path="res://Entities/Player/scripts/player.gd" id="1_d602n"]
|
[ext_resource type="Script" uid="uid://bwed2dwogfmxv" path="res://Entities/Player/scripts/player.gd" id="1_d602n"]
|
||||||
[ext_resource type="AnimationLibrary" uid="uid://bwnn7vpd0dqds" path="res://Common/animations/basic-movement.res" id="1_tfa5t"]
|
[ext_resource type="AnimationLibrary" uid="uid://bwnn7vpd0dqds" path="res://Common/animations/basic-movement.res" id="1_tfa5t"]
|
||||||
[ext_resource type="Script" uid="uid://bbjv6a7yg7m02" path="res://Stages/Test3D/camera_pivot.gd" id="2_sdmks"]
|
[ext_resource type="Script" uid="uid://bbjv6a7yg7m02" path="res://Stages/Test3D/camera_pivot.gd" id="2_sdmks"]
|
||||||
[ext_resource type="Shader" uid="uid://bsemnmdracd4m" path="res://Common/shaders/outline.gdshader" id="4_feu7y"]
|
[ext_resource type="Shader" uid="uid://bsemnmdracd4m" path="res://Common/shaders/outline.gdshader" id="4_feu7y"]
|
||||||
|
[ext_resource type="Script" uid="uid://bjco8musjqog4" path="res://Stages/Test3D/particles.gd" id="9_oiyue"]
|
||||||
[ext_resource type="Texture2D" uid="uid://c78jcjh8fjndd" path="res://Stages/Test3D/assets/3d/particles/flamelet_smooth.png" id="21_xvexm"]
|
[ext_resource type="Texture2D" uid="uid://c78jcjh8fjndd" path="res://Stages/Test3D/assets/3d/particles/flamelet_smooth.png" id="21_xvexm"]
|
||||||
[ext_resource type="Script" uid="uid://dglvt140rhg00" path="res://Stages/Test3D/omni_light_3d.gd" id="22_ukp6m"]
|
[ext_resource type="Script" uid="uid://dglvt140rhg00" path="res://Stages/Test3D/omni_light_3d.gd" id="22_ukp6m"]
|
||||||
[ext_resource type="PackedScene" uid="uid://mdxkaqaoybjv" path="res://Stages/Test3D/assets/tent-canvas.glb" id="23_5r2bu"]
|
[ext_resource type="PackedScene" uid="uid://mdxkaqaoybjv" path="res://Stages/Test3D/assets/tent-canvas.glb" id="23_5r2bu"]
|
||||||
|
|
@ -737,11 +738,11 @@ transform = Transform3D(0.707107, -0.408607, 0.577096, 0, 0.816138, 0.577857, -0
|
||||||
script = ExtResource("2_sdmks")
|
script = ExtResource("2_sdmks")
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot"]
|
[node name="Camera3D" type="Camera3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, -1.49012e-07, 0, 1.19209e-07, 1, 0.0410548, 0.237644, 3.45114)
|
transform = Transform3D(1, 0, 0, 0, 1, 1.78814e-07, 0, -3.27826e-07, 1, 0, 0, 7)
|
||||||
projection = 1
|
projection = 1
|
||||||
current = true
|
current = true
|
||||||
size = 3.0
|
size = 3.0
|
||||||
near = 0.005
|
near = 0.001
|
||||||
far = 100.0
|
far = 100.0
|
||||||
|
|
||||||
[node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"]
|
[node name="PostProcessing" type="MeshInstance3D" parent="SubViewportContainer/SubViewport/Player/CameraPivot/Camera3D"]
|
||||||
|
|
@ -759,10 +760,10 @@ mesh = SubResource("QuadMesh_tfa5t")
|
||||||
shape = SubResource("BoxShape3D_tfa5t")
|
shape = SubResource("BoxShape3D_tfa5t")
|
||||||
|
|
||||||
[node name="VFX" type="Node3D" parent="SubViewportContainer/SubViewport"]
|
[node name="VFX" type="Node3D" parent="SubViewportContainer/SubViewport"]
|
||||||
visible = false
|
|
||||||
|
|
||||||
[node name="Fire" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/VFX"]
|
[node name="Fire" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/VFX"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.08083, 0.0837402, 0.501403)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1.08083, 0.0837402, 0.501403)
|
||||||
|
visible = false
|
||||||
amount = 50
|
amount = 50
|
||||||
lifetime = 0.4
|
lifetime = 0.4
|
||||||
speed_scale = 0.4
|
speed_scale = 0.4
|
||||||
|
|
@ -772,7 +773,7 @@ draw_pass_1 = SubResource("QuadMesh_hvb1l")
|
||||||
[node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/VFX/Fire"]
|
[node name="OmniLight3D" type="OmniLight3D" parent="SubViewportContainer/SubViewport/VFX/Fire"]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.000509977, 0.121094, -0.00151992)
|
||||||
light_color = Color(0.89, 0.461613, 0.2136, 1)
|
light_color = Color(0.89, 0.461613, 0.2136, 1)
|
||||||
light_energy = 0.802091
|
light_energy = 0.590552
|
||||||
light_indirect_energy = 1.084
|
light_indirect_energy = 1.084
|
||||||
light_volumetric_fog_energy = 3.764
|
light_volumetric_fog_energy = 3.764
|
||||||
light_size = 0.105
|
light_size = 0.105
|
||||||
|
|
@ -794,6 +795,9 @@ trail_lifetime = 0.1
|
||||||
process_material = SubResource("ParticleProcessMaterial_p5fn2")
|
process_material = SubResource("ParticleProcessMaterial_p5fn2")
|
||||||
draw_pass_1 = SubResource("RibbonTrailMesh_5r2bu")
|
draw_pass_1 = SubResource("RibbonTrailMesh_5r2bu")
|
||||||
|
|
||||||
|
[node name="FloatingParticles" type="GPUParticles3D" parent="SubViewportContainer/SubViewport/VFX"]
|
||||||
|
script = ExtResource("9_oiyue")
|
||||||
|
|
||||||
[node name="TileGround" type="Node3D" parent="SubViewportContainer/SubViewport"]
|
[node name="TileGround" type="Node3D" parent="SubViewportContainer/SubViewport"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
script = ExtResource("24_vyi1v")
|
script = ExtResource("24_vyi1v")
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_lg8b7"]
|
[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_lg8b7"]
|
||||||
sky_horizon_color = Color(0.67451, 0.682353, 0.698039, 1)
|
sky_horizon_color = Color(0.67451, 0.682353, 0.698039, 1)
|
||||||
sky_curve = 0.0175
|
|
||||||
ground_bottom_color = Color(1, 1, 1, 1)
|
ground_bottom_color = Color(1, 1, 1, 1)
|
||||||
ground_curve = 0.171484
|
ground_curve = 0.171484
|
||||||
|
|
||||||
|
|
@ -10,7 +9,7 @@ ground_curve = 0.171484
|
||||||
sky_material = SubResource("ProceduralSkyMaterial_lg8b7")
|
sky_material = SubResource("ProceduralSkyMaterial_lg8b7")
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
background_mode = 1
|
background_mode = 2
|
||||||
background_color = Color(0.752941, 0.776471, 0.827451, 1)
|
background_color = Color(0.752941, 0.776471, 0.827451, 1)
|
||||||
sky = SubResource("Sky_7bk1c")
|
sky = SubResource("Sky_7bk1c")
|
||||||
ambient_light_source = 2
|
ambient_light_source = 2
|
||||||
|
|
@ -18,12 +17,12 @@ ambient_light_color = Color(0.662745, 0.694118, 0.772549, 1)
|
||||||
ambient_light_energy = 0.5
|
ambient_light_energy = 0.5
|
||||||
reflected_light_source = 2
|
reflected_light_source = 2
|
||||||
tonemap_mode = 2
|
tonemap_mode = 2
|
||||||
ssao_enabled = true
|
|
||||||
ssao_radius = 0.3
|
|
||||||
ssao_intensity = 0.5
|
|
||||||
ssao_power = 15.0
|
|
||||||
ssil_enabled = true
|
ssil_enabled = true
|
||||||
|
sdfgi_use_occlusion = true
|
||||||
glow_levels/2 = 0.6
|
glow_levels/2 = 0.6
|
||||||
glow_levels/3 = 0.6
|
glow_levels/3 = 0.6
|
||||||
glow_levels/5 = 0.0
|
glow_levels/5 = 0.0
|
||||||
glow_intensity = 2.0
|
glow_intensity = 2.0
|
||||||
|
fog_density = 0.0635
|
||||||
|
volumetric_fog_emission = Color(0.821925, 0.333878, 0.419207, 1)
|
||||||
|
volumetric_fog_ambient_inject = 16.0
|
||||||
|
|
|
||||||
79
stages/Test3D/particles.gd
Normal file
79
stages/Test3D/particles.gd
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
extends GPUParticles3D
|
||||||
|
|
||||||
|
@onready var player: Node3D = get_node("%Player")
|
||||||
|
var last_player_position: Vector3
|
||||||
|
var update_distance: float = 1
|
||||||
|
|
||||||
|
func _ready():
|
||||||
|
setup_floating_particles()
|
||||||
|
|
||||||
|
func _process(delta):
|
||||||
|
if player:
|
||||||
|
var current_player_pos = player.global_position
|
||||||
|
|
||||||
|
var target_pos = Vector3(
|
||||||
|
current_player_pos.x,
|
||||||
|
1.0,
|
||||||
|
current_player_pos.z
|
||||||
|
)
|
||||||
|
|
||||||
|
global_position = global_position.lerp(target_pos, delta * 3.0)
|
||||||
|
|
||||||
|
func setup_floating_particles():
|
||||||
|
# Basic particle setup
|
||||||
|
emitting = true
|
||||||
|
amount = 100
|
||||||
|
lifetime = 8.0
|
||||||
|
visibility_aabb = AABB(Vector3(-20, 0, -20), Vector3(40, 10, 40))
|
||||||
|
|
||||||
|
# Create material
|
||||||
|
var material = ParticleProcessMaterial.new()
|
||||||
|
|
||||||
|
# Emission
|
||||||
|
material.emission_shape = ParticleProcessMaterial.EMISSION_SHAPE_BOX
|
||||||
|
material.emission_box_extents = Vector3(5, 2, 5)
|
||||||
|
|
||||||
|
# Movement
|
||||||
|
material.direction = Vector3(0.1, 0.8, 0.1)
|
||||||
|
material.initial_velocity_min = 0.2
|
||||||
|
material.initial_velocity_max = 0.8
|
||||||
|
material.gravity = Vector3(0, -0.3, 0)
|
||||||
|
|
||||||
|
# Floating motion
|
||||||
|
material.orbit_velocity_min = 0.1
|
||||||
|
material.orbit_velocity_max = 0.3
|
||||||
|
material.radial_velocity_min = -0.2
|
||||||
|
material.radial_velocity_max = 0.2
|
||||||
|
|
||||||
|
# Size and fade
|
||||||
|
material.scale_min = 0.01
|
||||||
|
material.scale_max = 0.03
|
||||||
|
material.scale_over_velocity_min = 0.0
|
||||||
|
material.scale_over_velocity_max = 2.0
|
||||||
|
|
||||||
|
# Color (golden dust particles)
|
||||||
|
var gradient = Gradient.new()
|
||||||
|
gradient.add_point(0.0, Color(1.0, 0.9, 0.6, 0.0)) # Fade in
|
||||||
|
gradient.add_point(0.2, Color(1.0, 0.9, 0.6, 0.5)) # Full opacity
|
||||||
|
gradient.add_point(0.8, Color(1.0, 0.8, 0.4, 0.3)) # Slight color shift
|
||||||
|
gradient.add_point(1.0, Color(1.0, 0.7, 0.3, 0.0)) # Fade out
|
||||||
|
|
||||||
|
var gradient_texture = GradientTexture1D.new()
|
||||||
|
gradient_texture.gradient = gradient
|
||||||
|
material.color_ramp = gradient_texture
|
||||||
|
|
||||||
|
# Assign the material to the particle system
|
||||||
|
process_material = material
|
||||||
|
|
||||||
|
# Create and assign visual mesh (small billboard)
|
||||||
|
var quad_mesh = QuadMesh.new()
|
||||||
|
quad_mesh.size = Vector2(0.01, 0.01)
|
||||||
|
draw_pass_1 = quad_mesh
|
||||||
|
|
||||||
|
# Create a basic material for the particles to be visible
|
||||||
|
var particle_material = StandardMaterial3D.new()
|
||||||
|
particle_material.albedo_color = ColorData.grass_materials[Season.current]['top']
|
||||||
|
particle_material.flags_transparent = true
|
||||||
|
particle_material.flags_unshaded = true
|
||||||
|
particle_material.billboard_mode = BaseMaterial3D.BILLBOARD_ENABLED
|
||||||
|
material_override = particle_material
|
||||||
1
stages/Test3D/particles.gd.uid
Normal file
1
stages/Test3D/particles.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bjco8musjqog4
|
||||||
Loading…
Add table
Add a link
Reference in a new issue