diff --git a/terrain/jajce/assets.tres b/terrain/jajce/assets.tres index 84a65dd..0bb7ee5 100644 --- a/terrain/jajce/assets.tres +++ b/terrain/jajce/assets.tres @@ -1,4 +1,4 @@ -[gd_resource type="Terrain3DAssets" load_steps=13 format=3] +[gd_resource type="Terrain3DAssets" load_steps=14 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"] @@ -6,12 +6,13 @@ [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"] +[ext_resource type="Texture2D" path="res://terrain/jajce/textures/neutral_normal.png" id="7_normal"] [sub_resource type="Terrain3DTextureAsset" id="Texture_rock"] name = "Limestone" id = 0 albedo_texture = ExtResource("1_rock") -normal_texture = ExtResource("1_rock") +normal_texture = ExtResource("7_normal") normal_depth = 0.0 uv_scale = 0.18 detiling_rotation = 0.12 @@ -20,7 +21,7 @@ detiling_rotation = 0.12 name = "Valley Grass" id = 1 albedo_texture = ExtResource("2_grass") -normal_texture = ExtResource("2_grass") +normal_texture = ExtResource("7_normal") normal_depth = 0.0 uv_scale = 0.16 detiling_rotation = 0.18 @@ -29,7 +30,7 @@ detiling_rotation = 0.18 name = "Warm Soil" id = 2 albedo_texture = ExtResource("3_soil") -normal_texture = ExtResource("3_soil") +normal_texture = ExtResource("7_normal") normal_depth = 0.0 uv_scale = 0.2 detiling_rotation = 0.1 @@ -38,7 +39,7 @@ detiling_rotation = 0.1 name = "Dirt Path" id = 3 albedo_texture = ExtResource("4_dirt") -normal_texture = ExtResource("4_dirt") +normal_texture = ExtResource("7_normal") normal_depth = 0.0 uv_scale = 0.22 detiling_rotation = 0.08 @@ -47,7 +48,7 @@ detiling_rotation = 0.08 name = "Riverbank Stone" id = 4 albedo_texture = ExtResource("5_river") -normal_texture = ExtResource("5_river") +normal_texture = ExtResource("7_normal") normal_depth = 0.0 uv_scale = 0.12 detiling_rotation = 0.15 @@ -56,7 +57,7 @@ detiling_rotation = 0.15 name = "Compacted Ground" id = 5 albedo_texture = ExtResource("6_compact") -normal_texture = ExtResource("6_compact") +normal_texture = ExtResource("7_normal") normal_depth = 0.0 uv_scale = 0.2 detiling_rotation = 0.08 diff --git a/terrain/jajce/textures/compacted_ground_albedo.png.import b/terrain/jajce/textures/compacted_ground_albedo.png.import index dd9701c..62ccec8 100644 --- a/terrain/jajce/textures/compacted_ground_albedo.png.import +++ b/terrain/jajce/textures/compacted_ground_albedo.png.import @@ -23,7 +23,7 @@ compress/rdo_quality_loss=0.0 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 -mipmaps/generate=false +mipmaps/generate=true mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" diff --git a/terrain/jajce/textures/dirt_path_albedo.png.import b/terrain/jajce/textures/dirt_path_albedo.png.import index ed3e291..8507bf8 100644 --- a/terrain/jajce/textures/dirt_path_albedo.png.import +++ b/terrain/jajce/textures/dirt_path_albedo.png.import @@ -23,7 +23,7 @@ compress/rdo_quality_loss=0.0 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 -mipmaps/generate=false +mipmaps/generate=true mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" diff --git a/terrain/jajce/textures/neutral_normal.png b/terrain/jajce/textures/neutral_normal.png new file mode 100644 index 0000000..8aabb62 Binary files /dev/null and b/terrain/jajce/textures/neutral_normal.png differ diff --git a/terrain/jajce/textures/neutral_normal.png.import b/terrain/jajce/textures/neutral_normal.png.import new file mode 100644 index 0000000..aee1d65 --- /dev/null +++ b/terrain/jajce/textures/neutral_normal.png.import @@ -0,0 +1,40 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bjcbxamqe7yji" +path="res://.godot/imported/neutral_normal.png-6607918f21cb99be0fd06ece8d18c3c7.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://terrain/jajce/textures/neutral_normal.png" +dest_files=["res://.godot/imported/neutral_normal.png-6607918f21cb99be0fd06ece8d18c3c7.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=1 +compress/channel_pack=0 +mipmaps/generate=true +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 diff --git a/terrain/jajce/textures/riverbank_stone_albedo.png.import b/terrain/jajce/textures/riverbank_stone_albedo.png.import index 538e264..83d6004 100644 --- a/terrain/jajce/textures/riverbank_stone_albedo.png.import +++ b/terrain/jajce/textures/riverbank_stone_albedo.png.import @@ -23,7 +23,7 @@ compress/rdo_quality_loss=0.0 compress/hdr_compression=1 compress/normal_map=0 compress/channel_pack=0 -mipmaps/generate=false +mipmaps/generate=true mipmaps/limit=-1 roughness/mode=0 roughness/src_normal="" diff --git a/tests/jajce_world_scaffold_test.gd b/tests/jajce_world_scaffold_test.gd index 2969092..6742b4f 100644 --- a/tests/jajce_world_scaffold_test.gd +++ b/tests/jajce_world_scaffold_test.gd @@ -11,6 +11,8 @@ func _run() -> void: var camera := Camera3D.new() camera.current = true root.add_child(camera) + var configured_assets: Terrain3DAssets = load("res://terrain/jajce/assets.tres") + var configured_texture_count := configured_assets.get_texture_count() var world: Node3D = load("res://world/jajce/JajceWorld.tscn").instantiate() root.add_child(world) @@ -25,12 +27,26 @@ func _run() -> void: "Terrain3D should use dedicated Jajce data" ) _check( - terrain.assets.get_texture_count() >= 3, + configured_texture_count == 6, ( - "Jajce terrain should expose at least three materials (found %s)" - % terrain.assets.get_texture_count() + "Jajce terrain should define the bounded six-material palette (found %s)" + % configured_texture_count ) ) + var texture_contract_valid := true + for texture_index in configured_texture_count: + var texture_asset: Terrain3DTextureAsset = configured_assets.get_texture(texture_index) + texture_contract_valid = ( + texture_contract_valid + and texture_asset.albedo_texture != null + and texture_asset.normal_texture != null + and texture_asset.albedo_texture.get_image().has_mipmaps() + and texture_asset.normal_texture.get_image().has_mipmaps() + ) + _check( + texture_contract_valid, + "All Terrain3D texture assets should provide matching mipmapped maps" + ) _check( absf(terrain.data.get_height(Vector3.ZERO)) < 0.1, "Central gameplay area should remain level for current navigation" @@ -52,6 +68,11 @@ func _run() -> void: world.has_node("WaterRoot/WaterfallMist"), "WaterRoot should include waterfall mist particles" ) + var waterfall_mist: GPUParticles3D = world.get_node("WaterRoot/WaterfallMist") + _check( + waterfall_mist.draw_pass_1 != null, + "Waterfall mist particles should have visible billboard geometry" + ) _check(world.has_node("WaterRoot/RiverSurface"), "WaterRoot should include a river surface") var environment: Environment = ( (world.get_node("WorldEnvironment") as WorldEnvironment).environment @@ -67,6 +88,9 @@ func _run() -> void: var smoke_count := 0 for suffix in ["House_01", "House_02", "House_03"]: if world.has_node("VillageRoot/%s/Smoke" % suffix): + var smoke: GPUParticles3D = world.get_node("VillageRoot/%s/Smoke" % suffix) + if smoke.draw_pass_1 == null: + continue smoke_count += 1 _check( smoke_count >= 2, diff --git a/tools/generate_jajce_terrain.gd b/tools/generate_jajce_terrain.gd index 3f760af..a78636e 100644 --- a/tools/generate_jajce_terrain.gd +++ b/tools/generate_jajce_terrain.gd @@ -16,6 +16,7 @@ func _generate() -> void: _generate_texture("grass_albedo.png", Color("#516f36"), Color("#79924c"), 17) _generate_texture("soil_albedo.png", Color("#65513b"), Color("#92734d"), 29) _generate_texture("rock_albedo.png", Color("#55534f"), Color("#89847b"), 43) + _generate_neutral_normal() var terrain := Terrain3D.new() terrain.region_size = 256 @@ -82,3 +83,13 @@ func _generate_texture( var error := image.save_png(path) if error != OK: push_error("Could not write terrain texture: " + path) + + +func _generate_neutral_normal() -> void: + var image := Image.create_empty(256, 256, false, Image.FORMAT_RGBA8) + image.fill(Color(0.5, 0.5, 1.0, 0.86)) + image.generate_mipmaps() + var path := TEXTURE_DIRECTORY.path_join("neutral_normal.png") + var error := image.save_png(path) + if error != OK: + push_error("Could not write terrain normal texture: " + path) diff --git a/world/jajce/ChimneySmoke.tscn b/world/jajce/ChimneySmoke.tscn index d55026b..192496c 100644 --- a/world/jajce/ChimneySmoke.tscn +++ b/world/jajce/ChimneySmoke.tscn @@ -1,12 +1,4 @@ -[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") +[gd_scene load_steps=4 format=3] [sub_resource type="ParticleProcessMaterial" id="3"] emission_shape = 1 @@ -17,7 +9,6 @@ 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="StandardMaterial3D" id="4"] albedo_color = Color(1, 1, 1, 1) diff --git a/world/jajce/WaterfallMist.tscn b/world/jajce/WaterfallMist.tscn index aff2247..7bad3bf 100644 --- a/world/jajce/WaterfallMist.tscn +++ b/world/jajce/WaterfallMist.tscn @@ -1,7 +1,4 @@ -[gd_scene load_steps=3 format=3] - -[sub_resource type="Curve" id="Curve_alpha"] -_data = [Vector2(0, 1), Vector2(1, 0)] +[gd_scene load_steps=4 format=3] [sub_resource type="ParticleProcessMaterial" id="ParticleProcessMaterial_mist"] lifetime_randomness = 0.2 @@ -12,10 +9,20 @@ 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) +[sub_resource type="StandardMaterial3D" id="Material_mist"] +albedo_color = Color(0.85, 0.95, 0.95, 0.35) +transparency = 1 +shading_mode = 0 +billboard_mode = 1 +cull_mode = 0 + +[sub_resource type="QuadMesh" id="Mesh_mist"] +material = SubResource("Material_mist") +size = Vector2(1.5, 1.5) + [node name="WaterfallMist" type="GPUParticles3D"] emitting = true amount = 48 @@ -26,3 +33,4 @@ speed_scale = 1.0 local_coords = true draw_order = 0 process_material = SubResource("ParticleProcessMaterial_mist") +draw_pass_1 = SubResource("Mesh_mist")