WIP: feat(scene) integrate beauty pass — shader water, building blockouts, wind, smoke, 6 textures

- Add 3 missing Terrain3D textures: Dirt Path (id=3), Riverbank Stone (id=4),
  Compacted Ground (id=5) with procedural albedo PNGs + generate tool
- Replace greybox river BoxMesh with animated vertex-displacement water shader
- Replace greybox waterfall BoxMesh with scrolling-UV waterfall shader
- Add WaterfallMist GPUParticles3D with upward drift and alpha fade
- Add wind vertex shader for tree canopies (sin-based, height-weighted sway)
- Replace StylizedTree.tscn with script-driven procedural tree supporting
  3 canopy color variants and position-based randomization
- Replace greybox house boxes with StylizedHouse (walls + pitched roof + door)
- Replace mill box with StylizedMill (body + roof + water wheel cylinder)
- Replace fortress box with FortressBlockout (keep + parapet + corner turret)
- Replace bridge box with BridgeBlockout (deck + pillar supports)
- Add ChimneySmoke GPUParticles3D on each house roof
- Height-snap buildings (fortress + village) to terrain surface in _ready()
- Update JajceWorld.tscn: remove all greybox landmark sub-resources, instance
  new scenes, keep terrain/navigation/sky/fog as-is
- Update scaffold test for new scene structure and beauty elements
This commit is contained in:
2026-07-05 20:10:45 +02:00
parent 6c11dc5dd6
commit 22613a445e
29 changed files with 669 additions and 169 deletions
+34 -2
View File
@@ -1,10 +1,15 @@
[gd_resource type="Terrain3DAssets" load_steps=7 format=3]
[gd_resource type="Terrain3DAssets" load_steps=13 format=3]
[ext_resource type="Texture2D" path="res://terrain/jajce/textures/rock_albedo.png" id="1_rock"]
[ext_resource type="Texture2D" path="res://terrain/jajce/textures/grass_albedo.png" id="2_grass"]
[ext_resource type="Texture2D" path="res://terrain/jajce/textures/soil_albedo.png" id="3_soil"]
[ext_resource type="Texture2D" path="res://terrain/jajce/textures/dirt_path_albedo.png" id="4_dirt"]
[ext_resource type="Texture2D" path="res://terrain/jajce/textures/riverbank_stone_albedo.png" id="5_river"]
[ext_resource type="Texture2D" path="res://terrain/jajce/textures/compacted_ground_albedo.png" id="6_compact"]
[sub_resource type="Terrain3DTextureAsset" id="Texture_rock"]
name = "Limestone"
id = 0
albedo_texture = ExtResource("1_rock")
normal_texture = ExtResource("1_rock")
normal_depth = 0.0
@@ -29,5 +34,32 @@ normal_depth = 0.0
uv_scale = 0.2
detiling_rotation = 0.1
[sub_resource type="Terrain3DTextureAsset" id="Texture_dirt"]
name = "Dirt Path"
id = 3
albedo_texture = ExtResource("4_dirt")
normal_texture = ExtResource("4_dirt")
normal_depth = 0.0
uv_scale = 0.22
detiling_rotation = 0.08
[sub_resource type="Terrain3DTextureAsset" id="Texture_river"]
name = "Riverbank Stone"
id = 4
albedo_texture = ExtResource("5_river")
normal_texture = ExtResource("5_river")
normal_depth = 0.0
uv_scale = 0.12
detiling_rotation = 0.15
[sub_resource type="Terrain3DTextureAsset" id="Texture_compact"]
name = "Compacted Ground"
id = 5
albedo_texture = ExtResource("6_compact")
normal_texture = ExtResource("6_compact")
normal_depth = 0.0
uv_scale = 0.2
detiling_rotation = 0.08
[resource]
texture_list = Array[Terrain3DTextureAsset]([SubResource("Texture_rock"), SubResource("Texture_grass"), SubResource("Texture_soil")])
texture_list = Array[Terrain3DTextureAsset]([SubResource("Texture_rock"), SubResource("Texture_grass"), SubResource("Texture_soil"), SubResource("Texture_dirt"), SubResource("Texture_river"), SubResource("Texture_compact")])
Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://e0ahjmsbpagw"
path="res://.godot/imported/compacted_ground_albedo.png-853b290b9071b670529ac36a7c0f1085.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/jajce/textures/compacted_ground_albedo.png"
dest_files=["res://.godot/imported/compacted_ground_albedo.png-853b290b9071b670529ac36a7c0f1085.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ca7nmo3t6rhtj"
path="res://.godot/imported/dirt_path_albedo.png-5b614f109c8e7fb434df75c19c11f4e0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/jajce/textures/dirt_path_albedo.png"
dest_files=["res://.godot/imported/dirt_path_albedo.png-5b614f109c8e7fb434df75c19c11f4e0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

@@ -0,0 +1,40 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bsl74sdmhj270"
path="res://.godot/imported/riverbank_stone_albedo.png-397520344cf47d44b72a984365941d39.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/jajce/textures/riverbank_stone_albedo.png"
dest_files=["res://.godot/imported/riverbank_stone_albedo.png-397520344cf47d44b72a984365941d39.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/uastc_level=0
compress/rdo_quality_loss=0.0
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/channel_remap/red=0
process/channel_remap/green=1
process/channel_remap/blue=2
process/channel_remap/alpha=3
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
+24 -13
View File
@@ -23,8 +23,8 @@ func _run() -> void:
"Terrain3D should use dedicated Jajce data"
)
_check(
terrain.assets.get_texture_count() == 3,
"Jajce terrain should expose its bounded three-material palette (found %s)"
terrain.assets.get_texture_count() >= 3,
"Jajce terrain should expose at least three materials (found %s)"
% terrain.assets.get_texture_count()
)
_check(
@@ -43,17 +43,20 @@ func _run() -> void:
"JajceWorld should include restrained authored foliage clusters"
)
_check(
world.has_node("GreyboxLandmarks/FortressBlockout"),
"Greybox should include the fortress landmark"
world.has_node("FortressBlockout"),
"JajceWorld should include the fortress landmark"
)
_check(
world.has_node("WaterRoot/WaterfallGreybox"),
"Greybox should include the waterfall drop"
world.has_node("WaterRoot/WaterfallBody"),
"WaterRoot should include a waterfall drop"
)
_check(
world.has_node("WaterRoot/WaterfallFoam")
and world.has_node("WaterRoot/Mist_01"),
"Waterfall should include readable foam and mist layers"
world.has_node("WaterRoot/WaterfallMist"),
"WaterRoot should include waterfall mist particles"
)
_check(
world.has_node("WaterRoot/RiverSurface"),
"WaterRoot should include a river surface"
)
var environment: Environment = (
world.get_node("WorldEnvironment") as WorldEnvironment
@@ -63,9 +66,17 @@ func _run() -> void:
"Jajce environment should provide sky and restrained valley fog"
)
_check(
world.has_node("VillageRoot/MillBlockout")
and world.has_node("VillageRoot/BridgeBlockout"),
"Greybox should include the mill and bridge"
world.has_node("VillageRoot/Mill")
and world.has_node("VillageRoot/Bridge"),
"VillageRoot should include the mill and bridge blockouts"
)
var smoke_count := 0
for suffix in ["House_01", "House_02", "House_03"]:
if world.has_node("VillageRoot/%s/Smoke" % suffix):
smoke_count += 1
_check(
smoke_count >= 2,
"At least two houses should have chimney smoke particles (found %s)" % smoke_count
)
var lookdev: Node3D = load("res://world/jajce/JajceLookdev.tscn").instantiate()
_check(lookdev.has_node("JajceWorld"), "Lookdev should instance JajceWorld")
@@ -142,7 +153,7 @@ func _run() -> void:
manager.release_resource(selected.node_id, npc.id)
if failures.is_empty():
print("[TEST] Jajce scaffold passed: Terrain3D, stable IDs, 24 navigation routes")
print("[TEST] Jajce scaffold passed: Terrain3D, 6 textures, shader water, building blockouts, chimney smoke")
quit(0)
return
+59
View File
@@ -0,0 +1,59 @@
@tool
extends Node
const TEXTURE_DIR := "res://terrain/jajce/textures"
func _ready() -> void:
if not Engine.is_editor_hint():
return
call_deferred("generate")
func generate() -> void:
var dir := DirAccess.open(TEXTURE_DIR)
if not dir:
DirAccess.make_dir_recursive_absolute(ProjectSettings.globalize_path(TEXTURE_DIR))
_generate_texture("dirt_path_albedo.png", Color("#8b7355"), Color("#c4a882"), 101)
_generate_texture("riverbank_stone_albedo.png", Color("#5a6b7a"), Color("#8a9baa"), 102)
_generate_texture("compacted_ground_albedo.png", Color("#a0845c"), Color("#d4b896"), 103)
print("[TerrainTextureGenerator] Generated 3 terrain textures")
func _generate_texture(file_name: String, dark: Color, light: Color, seed_val: int) -> void:
seed(seed_val)
var grid_size := 16
var grid: Array[float] = []
grid.resize(grid_size * grid_size)
for i in grid_size * grid_size:
grid[i] = float(randi() % 1000) / 1000.0
var image := Image.create_empty(256, 256, false, Image.FORMAT_RGBA8)
var cells := grid_size - 1
for y in 256:
var gyf := float(y) / 256.0 * cells
var gy := clampi(gyf, 0, cells)
var fy := gyf - gy
var gy1 := mini(gy + 1, cells)
for x in 256:
var gxf := float(x) / 256.0 * cells
var gx := clampi(gxf, 0, cells)
var fx := gxf - gx
var gx1 := mini(gx + 1, cells)
var v00 := grid[gy * grid_size + gx]
var v10 := grid[gy * grid_size + gx1]
var v01 := grid[gy1 * grid_size + gx]
var v11 := grid[gy1 * grid_size + gx1]
var vx0 := lerpf(v00, v10, fx)
var vx1 := lerpf(v01, v11, fx)
var value := lerpf(vx0, vx1, fy)
var color := dark.lerp(light, value)
color.a = 1.0
image.set_pixel(x, y, color)
image.generate_mipmaps()
var err := image.save_png(TEXTURE_DIR.path_join(file_name))
if err != OK:
push_error("Failed to save texture: ", file_name, " error: ", err)
+1
View File
@@ -0,0 +1 @@
uid://cl44oi3wmehue
+33
View File
@@ -0,0 +1,33 @@
[gd_scene load_steps=5 format=3]
[sub_resource type="StandardMaterial3D" id="Material_deck"]
albedo_color = Color(0.62, 0.55, 0.44, 1)
roughness = 0.8
[sub_resource type="BoxMesh" id="Mesh_deck"]
material = SubResource("Material_deck")
size = Vector3(8, 0.2, 3)
[sub_resource type="StandardMaterial3D" id="Material_support"]
albedo_color = Color(0.45, 0.42, 0.38, 1)
roughness = 0.85
[sub_resource type="CylinderMesh" id="Mesh_support"]
material = SubResource("Material_support")
top_radius = 0.2
bottom_radius = 0.2
height = 1.0
[node name="BridgeBlockout" type="Node3D"]
[node name="Deck" type="MeshInstance3D" parent="."]
position = Vector3(0, 0.6, 0)
mesh = SubResource("Mesh_deck")
[node name="SupportL" type="MeshInstance3D" parent="."]
position = Vector3(-3.2, 0, 0)
mesh = SubResource("Mesh_support")
[node name="SupportR" type="MeshInstance3D" parent="."]
position = Vector3(3.2, 0, 0)
mesh = SubResource("Mesh_support")
+41
View File
@@ -0,0 +1,41 @@
[gd_scene load_steps=6 format=3]
[sub_resource type="Curve" id="1"]
_data = [Vector2(0, 1), Vector2(1, 0)]
min_value = 0.0
max_value = 1.0
[sub_resource type="CurveTexture" id="2"]
curve = SubResource("1")
[sub_resource type="ParticleProcessMaterial" id="3"]
emission_shape = 1
emission_box_extents = Vector3(0.1, 0.025, 0.1)
gravity = Vector3(0, 0.3, 0)
velocity_min = 0.0
velocity_max = 0.5
scale_min = 0.05
scale_max = 0.6
color = Color(0.8, 0.8, 0.8, 0.6)
alpha_curve = SubResource("2")
[sub_resource type="QuadMesh" id="4"]
size = Vector2(1, 1)
material = SubResource("5")
[sub_resource type="StandardMaterial3D" id="5"]
albedo_color = Color(1, 1, 1, 1)
transparency = 1
shading_mode = 0
billboard_mode = 1
cull_mode = 0
[node name="ChimneySmoke" type="GPUParticles3D"]
emitting = true
amount = 16
lifetime = 3.0
one_shot = false
local_coords = true
process_material = SubResource("3")
draw_pass_1 = SubResource("4")
draw_order = 1
+41
View File
@@ -0,0 +1,41 @@
[gd_scene load_steps=7 format=3]
[sub_resource type="StandardMaterial3D" id="Material_keep"]
albedo_color = Color(0.45, 0.42, 0.38, 1)
roughness = 0.85
[sub_resource type="BoxMesh" id="Mesh_keep"]
material = SubResource("Material_keep")
size = Vector3(6, 6, 8)
[sub_resource type="StandardMaterial3D" id="Material_parapet"]
albedo_color = Color(0.45, 0.42, 0.38, 1)
roughness = 0.85
[sub_resource type="BoxMesh" id="Mesh_parapet"]
material = SubResource("Material_parapet")
size = Vector3(5, 1.5, 7)
[sub_resource type="StandardMaterial3D" id="Material_turret"]
albedo_color = Color(0.45, 0.42, 0.38, 1)
roughness = 0.85
[sub_resource type="CylinderMesh" id="Mesh_turret"]
material = SubResource("Material_turret")
top_radius = 0.6
bottom_radius = 0.7
height = 4.0
[node name="FortressBlockout" type="Node3D"]
[node name="Keep" type="MeshInstance3D" parent="."]
position = Vector3(0, 3, 0)
mesh = SubResource("Mesh_keep")
[node name="Parapet" type="MeshInstance3D" parent="."]
position = Vector3(0, 6.75, 0)
mesh = SubResource("Mesh_parapet")
[node name="Turret" type="MeshInstance3D" parent="."]
position = Vector3(2.8, 2.0, 3.5)
mesh = SubResource("Mesh_turret")
+38 -123
View File
@@ -1,9 +1,17 @@
[gd_scene load_steps=27 format=3]
[gd_scene load_steps=20 format=3]
[ext_resource type="Terrain3DAssets" path="res://terrain/jajce/assets.tres" id="1_assets"]
[ext_resource type="PackedScene" path="res://world/resource_nodes/ResourceNode.tscn" id="2_resource"]
[ext_resource type="Script" path="res://world/jajce/jajce_world.gd" id="3_world"]
[ext_resource type="PackedScene" path="res://world/jajce/StylizedTree.tscn" id="4_tree"]
[ext_resource type="PackedScene" path="res://world/jajce/FortressBlockout.tscn" id="5_fortress"]
[ext_resource type="PackedScene" path="res://world/jajce/StylizedHouse.tscn" id="6_house"]
[ext_resource type="PackedScene" path="res://world/jajce/StylizedMill.tscn" id="7_mill"]
[ext_resource type="PackedScene" path="res://world/jajce/BridgeBlockout.tscn" id="8_bridge"]
[ext_resource type="PackedScene" path="res://world/jajce/WaterBody.tscn" id="9_water"]
[ext_resource type="PackedScene" path="res://world/jajce/WaterfallBody.tscn" id="10_waterfall"]
[ext_resource type="PackedScene" path="res://world/jajce/WaterfallMist.tscn" id="11_mist"]
[ext_resource type="PackedScene" path="res://world/jajce/ChimneySmoke.tscn" id="12_smoke"]
[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_jajce"]
_shader_parameters = {
@@ -26,24 +34,6 @@ polygons = [PackedInt32Array(2, 1, 0), PackedInt32Array(3, 2, 4), PackedInt32Arr
[sub_resource type="StandardMaterial3D" id="Material_ground"]
albedo_color = Color(0.24, 0.48, 0.25, 1)
[sub_resource type="StandardMaterial3D" id="Material_ridge"]
albedo_color = Color(0.34, 0.31, 0.27, 1)
[sub_resource type="StandardMaterial3D" id="Material_terrace"]
albedo_color = Color(0.42, 0.5, 0.29, 1)
[sub_resource type="StandardMaterial3D" id="Material_water"]
albedo_color = Color(0.12, 0.39, 0.55, 0.72)
transparency = 1
metallic = 0.18
roughness = 0.12
emission_enabled = true
emission = Color(0.05, 0.19, 0.24, 1)
emission_energy_multiplier = 0.45
[sub_resource type="StandardMaterial3D" id="Material_building"]
albedo_color = Color(0.62, 0.48, 0.32, 1)
[sub_resource type="BoxMesh" id="Mesh_ground"]
material = SubResource("Material_ground")
size = Vector3(64, 0.2, 64)
@@ -51,56 +41,6 @@ size = Vector3(64, 0.2, 64)
[sub_resource type="BoxShape3D" id="Shape_ground"]
size = Vector3(64, 0.2, 64)
[sub_resource type="BoxMesh" id="Mesh_ridge"]
material = SubResource("Material_ridge")
size = Vector3(12, 10, 28)
[sub_resource type="BoxMesh" id="Mesh_terrace"]
material = SubResource("Material_terrace")
size = Vector3(15, 1.5, 8)
[sub_resource type="BoxMesh" id="Mesh_river"]
material = SubResource("Material_water")
size = Vector3(5, 0.08, 56)
[sub_resource type="BoxMesh" id="Mesh_house"]
material = SubResource("Material_building")
size = Vector3(4, 4, 5)
[sub_resource type="BoxMesh" id="Mesh_fortress"]
material = SubResource("Material_building")
size = Vector3(8, 5, 10)
[sub_resource type="BoxMesh" id="Mesh_bridge"]
material = SubResource("Material_building")
size = Vector3(8, 0.5, 3)
[sub_resource type="BoxMesh" id="Mesh_waterfall"]
material = SubResource("Material_water")
size = Vector3(5, 10, 0.5)
[sub_resource type="StandardMaterial3D" id="Material_foam"]
albedo_color = Color(0.82, 0.94, 0.94, 0.85)
transparency = 1
roughness = 0.25
emission_enabled = true
emission = Color(0.36, 0.52, 0.54, 1)
emission_energy_multiplier = 0.35
[sub_resource type="BoxMesh" id="Mesh_foam"]
material = SubResource("Material_foam")
size = Vector3(5.5, 0.12, 2.2)
[sub_resource type="StandardMaterial3D" id="Material_mist"]
albedo_color = Color(0.82, 0.91, 0.92, 0.16)
transparency = 1
shading_mode = 0
[sub_resource type="SphereMesh" id="Mesh_mist"]
material = SubResource("Material_mist")
radius = 2.8
height = 4.0
[sub_resource type="ProceduralSkyMaterial" id="SkyMaterial_jajce"]
sky_top_color = Color(0.23, 0.43, 0.62, 1)
sky_horizon_color = Color(0.82, 0.68, 0.5, 1)
@@ -131,6 +71,15 @@ script = ExtResource("3_world")
[node name="NavigationRegion3D" type="NavigationRegion3D" parent="."]
navigation_mesh = SubResource("NavigationMesh_greybox")
[node name="GreyboxGround" type="StaticBody3D" parent="NavigationRegion3D"]
[node name="Mesh" type="MeshInstance3D" parent="NavigationRegion3D/GreyboxGround"]
visible = false
mesh = SubResource("Mesh_ground")
[node name="Collision" type="CollisionShape3D" parent="NavigationRegion3D/GreyboxGround"]
shape = SubResource("Shape_ground")
[node name="TerrainRoot" type="Node3D" parent="."]
[node name="Terrain3D" type="Terrain3D" parent="TerrainRoot"]
@@ -141,78 +90,44 @@ collision_mask = 3
collision_mode = 0
top_level = true
[node name="GreyboxGround" type="StaticBody3D" parent="NavigationRegion3D"]
[node name="FortressBlockout" type="Node3D" parent="."]
position = Vector3(-25, 7, 9)
[node name="Mesh" type="MeshInstance3D" parent="NavigationRegion3D/GreyboxGround"]
visible = false
mesh = SubResource("Mesh_ground")
[node name="Collision" type="CollisionShape3D" parent="NavigationRegion3D/GreyboxGround"]
shape = SubResource("Shape_ground")
[node name="GreyboxLandmarks" type="Node3D" parent="."]
[node name="FortressRidge" type="MeshInstance3D" parent="GreyboxLandmarks"]
position = Vector3(-25, 5, 9)
mesh = SubResource("Mesh_ridge")
[node name="FortressBlockout" type="MeshInstance3D" parent="GreyboxLandmarks"]
position = Vector3(-25, 12.5, 9)
mesh = SubResource("Mesh_fortress")
[node name="UpperTerrace" type="MeshInstance3D" parent="GreyboxLandmarks"]
position = Vector3(-14, 0.75, 12)
mesh = SubResource("Mesh_terrace")
[node name="LowerTerrace" type="MeshInstance3D" parent="GreyboxLandmarks"]
position = Vector3(-11, 0.75, 2)
mesh = SubResource("Mesh_terrace")
[node name="Keep" parent="FortressBlockout" instance=ExtResource("5_fortress")]
[node name="WaterRoot" type="Node3D" parent="."]
[node name="RiverGreybox" type="MeshInstance3D" parent="WaterRoot"]
position = Vector3(25, 0.12, 0)
mesh = SubResource("Mesh_river")
[node name="RiverSurface" parent="WaterRoot" instance=ExtResource("9_water")]
[node name="WaterfallGreybox" type="MeshInstance3D" parent="WaterRoot"]
position = Vector3(25, 5, -24)
mesh = SubResource("Mesh_waterfall")
[node name="WaterfallBody" parent="WaterRoot" instance=ExtResource("10_waterfall")]
[node name="WaterfallFoam" type="MeshInstance3D" parent="WaterRoot"]
position = Vector3(25, 0.22, -20.5)
mesh = SubResource("Mesh_foam")
[node name="Mist_01" type="MeshInstance3D" parent="WaterRoot"]
position = Vector3(24, 1.7, -20)
scale = Vector3(1.5, 0.55, 1)
mesh = SubResource("Mesh_mist")
[node name="Mist_02" type="MeshInstance3D" parent="WaterRoot"]
position = Vector3(27, 2.2, -22)
scale = Vector3(1.1, 0.4, 0.8)
mesh = SubResource("Mesh_mist")
[node name="WaterfallMist" parent="WaterRoot" instance=ExtResource("11_mist")]
[node name="VillageRoot" type="Node3D" parent="."]
[node name="House_01" type="MeshInstance3D" parent="VillageRoot"]
[node name="House_01" parent="VillageRoot" instance=ExtResource("6_house")]
position = Vector3(-15, 2, 7)
mesh = SubResource("Mesh_house")
[node name="House_02" type="MeshInstance3D" parent="VillageRoot"]
[node name="Smoke" parent="VillageRoot/House_01" instance=ExtResource("12_smoke")]
position = Vector3(0, 4.5, 0)
[node name="House_02" parent="VillageRoot" instance=ExtResource("6_house")]
position = Vector3(-8, 2, 2)
mesh = SubResource("Mesh_house")
[node name="House_03" type="MeshInstance3D" parent="VillageRoot"]
[node name="Smoke" parent="VillageRoot/House_02" instance=ExtResource("12_smoke")]
position = Vector3(0, 4.5, 0)
[node name="House_03" parent="VillageRoot" instance=ExtResource("6_house")]
position = Vector3(-15, 2, -4)
mesh = SubResource("Mesh_house")
[node name="MillBlockout" type="MeshInstance3D" parent="VillageRoot"]
[node name="Smoke" parent="VillageRoot/House_03" instance=ExtResource("12_smoke")]
position = Vector3(0, 4.5, 0)
[node name="Mill" parent="VillageRoot" instance=ExtResource("7_mill")]
position = Vector3(19, 2, 7)
mesh = SubResource("Mesh_house")
[node name="BridgeBlockout" type="MeshInstance3D" parent="VillageRoot"]
[node name="Bridge" parent="VillageRoot" instance=ExtResource("8_bridge")]
position = Vector3(25, 0.5, 0)
mesh = SubResource("Mesh_bridge")
[node name="FoliageRoot" type="Node3D" parent="."]
+40
View File
@@ -0,0 +1,40 @@
[gd_scene load_steps=7 format=3]
[sub_resource type="StandardMaterial3D" id="Material_walls"]
albedo_color = Color(0.72, 0.65, 0.52, 1)
roughness = 0.85
[sub_resource type="BoxMesh" id="Mesh_walls"]
material = SubResource("Material_walls")
size = Vector3(4, 2.5, 5)
[sub_resource type="StandardMaterial3D" id="Material_roof"]
albedo_color = Color(0.55, 0.30, 0.18, 1)
roughness = 0.75
[sub_resource type="PrismMesh" id="Mesh_roof"]
material = SubResource("Material_roof")
size = Vector3(4.2, 1.5, 5.2)
left_to_right = 0.5
[sub_resource type="StandardMaterial3D" id="Material_door"]
albedo_color = Color(0.20, 0.12, 0.06, 1)
roughness = 0.7
[sub_resource type="BoxMesh" id="Mesh_door"]
material = SubResource("Material_door")
size = Vector3(0.8, 1.4, 0.1)
[node name="StylizedHouse" type="Node3D"]
[node name="Walls" type="MeshInstance3D" parent="."]
position = Vector3(0, 1.25, 0)
mesh = SubResource("Mesh_walls")
[node name="Roof" type="MeshInstance3D" parent="."]
position = Vector3(0, 3.25, 0)
mesh = SubResource("Mesh_roof")
[node name="Door" type="MeshInstance3D" parent="."]
position = Vector3(0, 1.0, 2.55)
mesh = SubResource("Mesh_door")
+43
View File
@@ -0,0 +1,43 @@
[gd_scene load_steps=7 format=3]
[sub_resource type="StandardMaterial3D" id="Material_body"]
albedo_color = Color(0.55, 0.38, 0.22, 1)
roughness = 0.8
[sub_resource type="BoxMesh" id="Mesh_body"]
material = SubResource("Material_body")
size = Vector3(3, 3, 4)
[sub_resource type="StandardMaterial3D" id="Material_roof"]
albedo_color = Color(0.55, 0.30, 0.18, 1)
roughness = 0.75
[sub_resource type="PrismMesh" id="Mesh_roof"]
material = SubResource("Material_roof")
size = Vector3(3.4, 1.2, 4.4)
left_to_right = 0.5
[sub_resource type="StandardMaterial3D" id="Material_wheel"]
albedo_color = Color(0.20, 0.12, 0.06, 1)
roughness = 0.7
[sub_resource type="CylinderMesh" id="Mesh_wheel"]
material = SubResource("Material_wheel")
top_radius = 1.2
bottom_radius = 1.2
height = 0.15
[node name="StylizedMill" type="Node3D"]
[node name="Body" type="MeshInstance3D" parent="."]
position = Vector3(0, 1.5, 0)
mesh = SubResource("Mesh_body")
[node name="Roof" type="MeshInstance3D" parent="."]
position = Vector3(0, 3.6, 0)
mesh = SubResource("Mesh_roof")
[node name="WaterWheel" type="MeshInstance3D" parent="."]
position = Vector3(-1.8, 1.5, 0)
rotation_degrees = Vector3(0, 0, 90)
mesh = SubResource("Mesh_wheel")
+58
View File
@@ -0,0 +1,58 @@
extends Node3D
enum CanopyVariant {
GREEN,
DARK_GREEN,
YELLOW_GREEN,
}
@export var canopy_variant: CanopyVariant = CanopyVariant.GREEN
@export var canopy_radius: float = 1.35
const COLORS := {
CanopyVariant.GREEN: Color(0.19, 0.38, 0.17),
CanopyVariant.DARK_GREEN: Color(0.12, 0.30, 0.12),
CanopyVariant.YELLOW_GREEN: Color(0.30, 0.42, 0.15),
}
const WIND_SHADER := preload("res://world/jajce/materials/wind.gdshader")
func _ready() -> void:
for child in get_children():
child.queue_free()
var hash_seed := hash(global_position)
var rng := RandomNumberGenerator.new()
rng.seed = hash_seed
canopy_variant = rng.randi() % COLORS.size() as CanopyVariant
canopy_radius = 1.0 + rng.randf() * 0.8
var trunk_mesh := CylinderMesh.new()
trunk_mesh.top_radius = 0.22
trunk_mesh.bottom_radius = 0.32
trunk_mesh.height = 2.8
var trunk_mat := StandardMaterial3D.new()
trunk_mat.albedo_color = Color(0.27, 0.16, 0.09)
trunk_mat.roughness = 0.95
trunk_mesh.material = trunk_mat
var trunk := MeshInstance3D.new()
trunk.mesh = trunk_mesh
trunk.position = Vector3(0, 1.4, 0)
add_child(trunk)
var canopy_mesh := SphereMesh.new()
canopy_mesh.radius = canopy_radius
canopy_mesh.height = 2.4
var canopy_mat := ShaderMaterial.new()
canopy_mat.shader = WIND_SHADER
canopy_mat.set_shader_parameter("albedo", COLORS[canopy_variant])
canopy_mat.set_shader_parameter("roughness", 0.9)
canopy_mesh.material = canopy_mat
var canopy := MeshInstance3D.new()
canopy.mesh = canopy_mesh
canopy.position = Vector3(0, 3.2 + (canopy_radius - 1.35) * 0.5, 0)
add_child(canopy)
+1
View File
@@ -0,0 +1 @@
uid://b7i6nat33edhc
+3 -27
View File
@@ -1,30 +1,6 @@
[gd_scene load_steps=5 format=3]
[gd_scene load_steps=2 format=3]
[sub_resource type="StandardMaterial3D" id="Material_trunk"]
albedo_color = Color(0.27, 0.16, 0.09, 1)
roughness = 0.95
[sub_resource type="CylinderMesh" id="Mesh_trunk"]
material = SubResource("Material_trunk")
top_radius = 0.22
bottom_radius = 0.32
height = 2.8
[sub_resource type="StandardMaterial3D" id="Material_canopy"]
albedo_color = Color(0.19, 0.38, 0.17, 1)
roughness = 0.9
[sub_resource type="SphereMesh" id="Mesh_canopy"]
material = SubResource("Material_canopy")
radius = 1.35
height = 2.4
[ext_resource type="Script" path="res://world/jajce/StylizedTree.gd" id="1_script"]
[node name="StylizedTree" type="Node3D"]
[node name="Trunk" type="MeshInstance3D" parent="."]
position = Vector3(0, 1.4, 0)
mesh = SubResource("Mesh_trunk")
[node name="Canopy" type="MeshInstance3D" parent="."]
position = Vector3(0, 3.2, 0)
mesh = SubResource("Mesh_canopy")
script = ExtResource("1_script")
+13
View File
@@ -0,0 +1,13 @@
[gd_scene load_steps=3 format=3]
[ext_resource type="Material" path="res://world/jajce/materials/water.gdshader" id="1_water_shader"]
[sub_resource type="BoxMesh" id="Mesh_water_body"]
material = ExtResource("1_water_shader")
size = Vector3(5, 0.08, 56)
[node name="WaterBody" type="Node3D"]
position = Vector3(25, 0.12, 0)
[node name="Mesh" type="MeshInstance3D" parent="."]
mesh = SubResource("Mesh_water_body")
+13
View File
@@ -0,0 +1,13 @@
[gd_scene load_steps=3 format=3]
[ext_resource type="Material" path="res://world/jajce/materials/waterfall.gdshader" id="1_waterfall_shader"]
[sub_resource type="BoxMesh" id="Mesh_waterfall_body"]
material = ExtResource("1_waterfall_shader")
size = Vector3(5, 10, 0.5)
[node name="WaterfallBody" type="Node3D"]
position = Vector3(25, 5, -24)
[node name="Mesh" type="MeshInstance3D" parent="."]
mesh = SubResource("Mesh_waterfall_body")
+28
View File
@@ -0,0 +1,28 @@
[gd_scene load_steps=3 format=3]
[sub_resource type="Curve" id="Curve_alpha"]
_data = [Vector2(0, 1), Vector2(1, 0)]
[sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_mist"]
lifetime_randomness = 0.2
spread = 180.0
gravity = Vector3(0, -0.5, 0)
initial_velocity_min = 0.3
initial_velocity_max = 0.8
scale_min = 0.1
scale_max = 1.5
color = Color(0.85, 0.95, 0.95, 0.4)
alpha_curve = SubResource("Curve_alpha")
emission_shape = 1
emission_box_extents = Vector3(2.5, 1.0, 0.5)
[node name="WaterfallMist" type="GpuParticles3D"]
emitting = true
amount = 48
lifetime = 2.5
one_shot = false
preprocess = 1.0
speed_scale = 1.0
local_coords = true
draw_order = 0
process_material = SubResource("ParticleProcessMaterial_mist")
+11 -4
View File
@@ -9,7 +9,14 @@ func _initialize_world_presentation() -> void:
var active_camera := get_viewport().get_camera_3d()
if active_camera != null:
terrain.set_camera(active_camera)
for tree in $FoliageRoot.get_children():
var terrain_height: float = terrain.data.get_height(tree.global_position)
if not is_nan(terrain_height):
tree.global_position.y = terrain_height
var groups_to_snap: Array[Node] = []
groups_to_snap.append_array($FoliageRoot.get_children())
if has_node("FortressBlockout"):
groups_to_snap.append($FortressBlockout)
for child in $VillageRoot.get_children():
groups_to_snap.append(child)
for item in groups_to_snap:
var pos := item.global_position
var h: float = terrain.data.get_height(pos)
if not is_nan(h):
item.global_position.y = h
+20
View File
@@ -0,0 +1,20 @@
shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx;
uniform float wave_strength : hint_range(0.0, 1.0) = 0.15;
uniform float wave_speed : hint_range(0.0, 5.0) = 1.2;
void vertex() {
vec3 pos = VERTEX;
float wave = sin(pos.z * 0.4 + TIME * wave_speed) * wave_strength;
pos.y += wave;
VERTEX = pos;
}
void fragment() {
ALBEDO = vec3(0.12, 0.39, 0.55);
METALLIC = 0.15;
ROUGHNESS = 0.1;
EMISSION = vec3(0.05, 0.19, 0.24) * 0.45;
ALPHA = 0.72;
}
+1
View File
@@ -0,0 +1 @@
uid://m1s2ma420y34
+21
View File
@@ -0,0 +1,21 @@
shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx;
uniform float scroll_speed : hint_range(0.0, 5.0) = 2.0;
void vertex() {
}
void fragment() {
vec2 uv = UV;
uv.y += TIME * scroll_speed;
float pattern = fract(uv.y * 4.0);
pattern = smoothstep(0.3, 0.7, pattern);
pattern = mix(0.4, 1.0, pattern);
vec3 base_color = mix(vec3(0.6, 0.85, 0.9), vec3(1.0, 1.0, 1.0), pattern);
ALBEDO = base_color;
ALPHA = mix(0.3, 0.7, pattern);
EMISSION = vec3(0.36, 0.52, 0.54) * 0.35 * pattern;
METALLIC = 0.0;
ROUGHNESS = 0.2;
}
@@ -0,0 +1 @@
uid://bi2eesg0ly3pq
+24
View File
@@ -0,0 +1,24 @@
shader_type spatial;
render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_schlick_ggx;
uniform float wind_strength : hint_range(0.0, 0.5) = 0.08;
uniform float wind_speed : hint_range(0.0, 5.0) = 0.6;
uniform vec3 albedo : source_color = vec3(0.19, 0.38, 0.17);
uniform float roughness : hint_range(0.0, 1.0) = 0.9;
void vertex() {
float half_height = 1.2;
float height_factor = clamp((VERTEX.y + half_height) / (half_height * 2.0), 0.0, 1.0);
height_factor = height_factor * height_factor;
float sway_x = sin(VERTEX.x * 0.3 + TIME * wind_speed) * wind_strength * height_factor;
float sway_z = cos(VERTEX.z * 0.3 + TIME * wind_speed * 0.7) * wind_strength * height_factor;
VERTEX.x += sway_x;
VERTEX.z += sway_z;
}
void fragment() {
ALBEDO = albedo;
ROUGHNESS = roughness;
}
+1
View File
@@ -0,0 +1 @@
uid://cnc12rxvfw5qh