feat(art): add storybook meadow and woodland villagers
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
[gd_scene load_steps=9 format=3]
|
||||
[gd_scene load_steps=10 format=3]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_deck"]
|
||||
albedo_color = Color(0.61, 0.53, 0.42, 1)
|
||||
roughness = 0.94
|
||||
[ext_resource type="Shader" path="res://world/presentation/materials/storybook_surface.gdshader" id="story_surface"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="Material_deck"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.61, 0.53, 0.42, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_deck"]
|
||||
material = SubResource("Material_deck")
|
||||
size = Vector3(15.2, 0.32, 3.15)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_stone"]
|
||||
albedo_color = Color(0.48, 0.47, 0.41, 1)
|
||||
roughness = 0.98
|
||||
[sub_resource type="ShaderMaterial" id="Material_stone"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.48, 0.47, 0.41, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_abutment"]
|
||||
material = SubResource("Material_stone")
|
||||
@@ -20,9 +22,9 @@ size = Vector3(2.25, 1.45, 4.2)
|
||||
material = SubResource("Material_stone")
|
||||
size = Vector3(1.05, 1.65, 3.7)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_rail"]
|
||||
albedo_color = Color(0.2, 0.115, 0.055, 1)
|
||||
roughness = 0.92
|
||||
[sub_resource type="ShaderMaterial" id="Material_rail"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.2, 0.115, 0.055, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_rail"]
|
||||
material = SubResource("Material_rail")
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
[gd_scene load_steps=19 format=3]
|
||||
[gd_scene load_steps=21 format=3]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_rock"]
|
||||
albedo_color = Color(0.25, 0.27, 0.24, 1)
|
||||
roughness = 1.0
|
||||
[ext_resource type="Shader" path="res://world/presentation/materials/storybook_surface.gdshader" id="story_surface"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="Material_rock"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.25, 0.27, 0.24, 1)
|
||||
|
||||
[sub_resource type="CylinderMesh" id="Mesh_rock_plinth"]
|
||||
material = SubResource("Material_rock")
|
||||
@@ -11,13 +13,13 @@ bottom_radius = 10.2
|
||||
height = 3.2
|
||||
radial_segments = 9
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_stone"]
|
||||
albedo_color = Color(0.47, 0.47, 0.43, 1)
|
||||
roughness = 0.96
|
||||
[sub_resource type="ShaderMaterial" id="Material_stone"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.47, 0.47, 0.43, 1)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_stone_light"]
|
||||
albedo_color = Color(0.57, 0.56, 0.51, 1)
|
||||
roughness = 0.95
|
||||
[sub_resource type="ShaderMaterial" id="Material_stone_light"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.57, 0.56, 0.51, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_keep"]
|
||||
material = SubResource("Material_stone_light")
|
||||
@@ -57,9 +59,9 @@ size = Vector3(1.25, 3.7, 1.7)
|
||||
material = SubResource("Material_stone_light")
|
||||
size = Vector3(4.6, 1.05, 1.7)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_gate"]
|
||||
albedo_color = Color(0.18, 0.11, 0.065, 1)
|
||||
roughness = 0.9
|
||||
[sub_resource type="ShaderMaterial" id="Material_gate"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.18, 0.11, 0.065, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_gate"]
|
||||
material = SubResource("Material_gate")
|
||||
@@ -72,17 +74,17 @@ bottom_radius = 0.09
|
||||
height = 4.2
|
||||
radial_segments = 8
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_banner"]
|
||||
albedo_color = Color(0.58, 0.1, 0.08, 1)
|
||||
roughness = 0.76
|
||||
[sub_resource type="ShaderMaterial" id="Material_banner"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.58, 0.1, 0.08, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_banner"]
|
||||
material = SubResource("Material_banner")
|
||||
size = Vector3(0.12, 2.2, 1.35)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_window_slit"]
|
||||
albedo_color = Color(0.12, 0.14, 0.13, 1)
|
||||
roughness = 0.98
|
||||
[sub_resource type="ShaderMaterial" id="Material_window_slit"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.12, 0.14, 0.13, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_window_slit"]
|
||||
material = SubResource("Material_window_slit")
|
||||
|
||||
@@ -1,18 +1,45 @@
|
||||
extends Node
|
||||
|
||||
const SHADER_INTERACTOR_LIMIT := 8
|
||||
const CLEARING_LIMIT := 4
|
||||
|
||||
@export var grass_material: ShaderMaterial
|
||||
@export_range(1, SHADER_INTERACTOR_LIMIT, 1) var max_interactors := 8
|
||||
@export_range(0.02, 0.5, 0.01) var update_interval := 0.08
|
||||
@export var path_clearings: Array[NodePath] = []
|
||||
|
||||
var _elapsed := 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# JajceWorld first isolates its mutable materials in the parent's _ready().
|
||||
call_deferred("_configure_path_clearings")
|
||||
_refresh_interactors()
|
||||
|
||||
|
||||
func _configure_path_clearings() -> void:
|
||||
if grass_material == null:
|
||||
return
|
||||
var segments := PackedVector4Array()
|
||||
segments.resize(CLEARING_LIMIT)
|
||||
var widths := Vector4.ZERO
|
||||
var count := 0
|
||||
for path in path_clearings.slice(0, CLEARING_LIMIT):
|
||||
var strip := get_node_or_null(path) as MeshInstance3D
|
||||
if strip == null or not strip.mesh is BoxMesh:
|
||||
continue
|
||||
var box := strip.mesh as BoxMesh
|
||||
var half_length := strip.global_basis.z * box.size.z * 0.5
|
||||
var start := strip.global_position - half_length
|
||||
var end := strip.global_position + half_length
|
||||
segments[count] = Vector4(start.x, start.z, end.x, end.z)
|
||||
widths[count] = strip.global_basis.x.length() * box.size.x * 0.5 + 0.12
|
||||
count += 1
|
||||
grass_material.set_shader_parameter("clearing_count", count)
|
||||
grass_material.set_shader_parameter("clearing_segments", segments)
|
||||
grass_material.set_shader_parameter("clearing_half_widths", widths)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_elapsed += delta
|
||||
if _elapsed < update_interval:
|
||||
|
||||
+17
-16
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=62 format=3]
|
||||
[gd_scene load_steps=68 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"]
|
||||
@@ -31,6 +31,9 @@
|
||||
[ext_resource type="PackedScene" path="res://world/animals/goat/dunja_habitat.tscn" id="29_habitat"]
|
||||
[ext_resource type="PackedScene" path="res://world/animals/goat/zora_shelter.tscn" id="30_zora_shelter"]
|
||||
|
||||
[ext_resource type="ArrayMesh" path="res://assets/storybook/meadow_grass.res" id="31_meadow"]
|
||||
[ext_resource type="Shader" path="res://world/jajce/materials/storybook_sky.gdshader" id="32_sky"]
|
||||
|
||||
[sub_resource type="Terrain3DMaterial" id="Terrain3DMaterial_jajce"]
|
||||
_shader_parameters = {
|
||||
"auto_base_texture": 0,
|
||||
@@ -38,8 +41,8 @@ _shader_parameters = {
|
||||
"auto_slope": 0.62,
|
||||
"blend_sharpness": 0.88,
|
||||
"enable_macro_variation": true,
|
||||
"macro_variation1": Color(0.78, 0.9, 0.42, 1),
|
||||
"macro_variation2": Color(0.55, 0.75, 0.38, 1),
|
||||
"macro_variation1": Color(0.84, 0.95, 0.73, 1),
|
||||
"macro_variation2": Color(0.60, 0.79, 0.61, 1),
|
||||
"macro_variation_slope": 0.48
|
||||
}
|
||||
world_background = 0
|
||||
@@ -172,13 +175,9 @@ size = Vector3(0.42, 0.08, 0.3)
|
||||
material = SubResource("Material_site_canvas")
|
||||
size = Vector3(2.9, 0.08, 1.4)
|
||||
|
||||
[sub_resource type="ProceduralSkyMaterial" id="SkyMaterial_jajce"]
|
||||
[sub_resource type="ShaderMaterial" id="SkyMaterial_jajce"]
|
||||
resource_local_to_scene = true
|
||||
sky_top_color = Color(0.28, 0.52, 0.72, 1)
|
||||
sky_horizon_color = Color(0.88, 0.74, 0.52, 1)
|
||||
ground_bottom_color = Color(0.18, 0.24, 0.14, 1)
|
||||
ground_horizon_color = Color(0.68, 0.6, 0.44, 1)
|
||||
sun_angle_max = 18.0
|
||||
shader = ExtResource("32_sky")
|
||||
|
||||
[sub_resource type="Sky" id="Sky_jajce"]
|
||||
resource_local_to_scene = true
|
||||
@@ -196,17 +195,17 @@ reflected_light_source = 2
|
||||
tonemap_mode = 2
|
||||
glow_enabled = true
|
||||
glow_normalized = true
|
||||
glow_intensity = 0.5
|
||||
glow_intensity = 0.18
|
||||
glow_strength = 0.9
|
||||
glow_bloom = 0.12
|
||||
glow_bloom = 0.03
|
||||
fog_enabled = true
|
||||
fog_light_color = Color(0.88, 0.84, 0.7, 1)
|
||||
fog_light_energy = 0.78
|
||||
fog_density = 0.002
|
||||
fog_height = -2.0
|
||||
fog_height_density = 0.08
|
||||
fog_aerial_perspective = 0.35
|
||||
fog_sky_affect = 0.28
|
||||
fog_aerial_perspective = 0.5
|
||||
fog_sky_affect = 0.12
|
||||
volumetric_fog_enabled = false
|
||||
volumetric_fog_density = 0.0035
|
||||
volumetric_fog_albedo = Color(0.82, 0.9, 0.82, 1)
|
||||
@@ -215,9 +214,9 @@ volumetric_fog_emission_energy = 0.12
|
||||
volumetric_fog_length = 96.0
|
||||
volumetric_fog_detail_spread = 1.6
|
||||
adjustment_enabled = true
|
||||
adjustment_brightness = 1.08
|
||||
adjustment_contrast = 1.04
|
||||
adjustment_saturation = 1.08
|
||||
adjustment_brightness = 1.0
|
||||
adjustment_contrast = 1.03
|
||||
adjustment_saturation = 1.04
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_guard"]
|
||||
albedo_color = Color(0.55, 0.45, 0.35, 1)
|
||||
@@ -269,6 +268,7 @@ rows = 34
|
||||
amount = 1156
|
||||
process_fixed_fps = 24
|
||||
process_material = ExtResource("25_grass_process")
|
||||
mesh = ExtResource("31_meadow")
|
||||
shadow_mode = 0
|
||||
mesh_material_override = ExtResource("20_grass_material")
|
||||
min_draw_distance = 36.0
|
||||
@@ -277,6 +277,7 @@ particle_count = 10404
|
||||
[node name="GrassInteractionController" type="Node" parent="TerrainRoot"]
|
||||
script = ExtResource("21_grass_controller")
|
||||
grass_material = ExtResource("20_grass_material")
|
||||
path_clearings = Array[NodePath]([NodePath("../../VillageRoot/Path_Village_Spine"), NodePath("../../VillageRoot/Path_Pantry_Worksites"), NodePath("../../VillageRoot/Path_River_Bridge"), NodePath("../../VillageRoot/Path_Forest_Edge")])
|
||||
|
||||
[node name="FortressBlockout" type="Node3D" parent="."]
|
||||
position = Vector3(-25, 7, 9)
|
||||
|
||||
@@ -1,33 +1,35 @@
|
||||
[gd_scene load_steps=15 format=3]
|
||||
[gd_scene load_steps=17 format=3]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_foundation"]
|
||||
albedo_color = Color(0.43, 0.42, 0.36, 1)
|
||||
roughness = 0.98
|
||||
[ext_resource type="Shader" path="res://world/presentation/materials/storybook_surface.gdshader" id="story_surface"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="Material_foundation"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.43, 0.42, 0.36, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_foundation"]
|
||||
material = SubResource("Material_foundation")
|
||||
size = Vector3(4.35, 0.65, 5.35)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_walls"]
|
||||
albedo_color = Color(0.78, 0.7, 0.56, 1)
|
||||
roughness = 0.94
|
||||
[sub_resource type="ShaderMaterial" id="Material_walls"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.78, 0.7, 0.56, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_walls"]
|
||||
material = SubResource("Material_walls")
|
||||
size = Vector3(4, 2.75, 5)
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_roof"]
|
||||
albedo_color = Color(0.48, 0.2, 0.12, 1)
|
||||
roughness = 0.9
|
||||
[sub_resource type="ShaderMaterial" id="Material_roof"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.48, 0.2, 0.12, 1)
|
||||
|
||||
[sub_resource type="PrismMesh" id="Mesh_roof"]
|
||||
material = SubResource("Material_roof")
|
||||
size = Vector3(4.65, 1.7, 5.65)
|
||||
left_to_right = 0.5
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_timber"]
|
||||
albedo_color = Color(0.2, 0.105, 0.05, 1)
|
||||
roughness = 0.92
|
||||
[sub_resource type="ShaderMaterial" id="Material_timber"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.2, 0.105, 0.05, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="Mesh_beam_vertical"]
|
||||
material = SubResource("Material_timber")
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
[gd_scene load_steps=7 format=3]
|
||||
[gd_scene load_steps=8 format=3]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="Material_body"]
|
||||
albedo_color = Color(0.55, 0.38, 0.22, 1)
|
||||
roughness = 0.8
|
||||
[ext_resource type="Shader" path="res://world/presentation/materials/storybook_surface.gdshader" id="story_surface"]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="Material_body"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.55, 0.38, 0.22, 1)
|
||||
|
||||
[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="ShaderMaterial" id="Material_roof"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.55, 0.30, 0.18, 1)
|
||||
|
||||
[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="ShaderMaterial" id="Material_wheel"]
|
||||
shader = ExtResource("story_surface")
|
||||
shader_parameter/albedo = Color(0.20, 0.12, 0.06, 1)
|
||||
|
||||
[sub_resource type="CylinderMesh" id="Mesh_wheel"]
|
||||
material = SubResource("Material_wheel")
|
||||
|
||||
@@ -7,9 +7,9 @@ enum CanopyVariant {
|
||||
}
|
||||
|
||||
const COLORS := {
|
||||
CanopyVariant.GREEN: Color(0.18, 0.39, 0.16),
|
||||
CanopyVariant.DARK_GREEN: Color(0.10, 0.28, 0.12),
|
||||
CanopyVariant.YELLOW_GREEN: Color(0.34, 0.47, 0.16),
|
||||
CanopyVariant.GREEN: Color(0.32, 0.51, 0.29),
|
||||
CanopyVariant.DARK_GREEN: Color(0.22, 0.41, 0.30),
|
||||
CanopyVariant.YELLOW_GREEN: Color(0.49, 0.60, 0.28),
|
||||
}
|
||||
|
||||
const WIND_SHADER := preload("res://world/jajce/materials/wind.gdshader")
|
||||
@@ -25,7 +25,7 @@ func _ready() -> void:
|
||||
var rng := RandomNumberGenerator.new()
|
||||
rng.seed = hash_seed
|
||||
var canopy_variant := rng.randi() % COLORS.size() as CanopyVariant
|
||||
var canopy_radius := 1.0 + rng.randf() * 0.55
|
||||
var canopy_radius := 1.25 + rng.randf() * 0.6
|
||||
var wind_phase := rng.randf_range(0.0, TAU)
|
||||
|
||||
var trunk_mesh := CylinderMesh.new()
|
||||
|
||||
@@ -7,17 +7,17 @@ extends Node
|
||||
|
||||
const TO_RAD := PI / 180.0
|
||||
|
||||
const DAY_SKY_TOP := Color(0.23, 0.43, 0.62, 1)
|
||||
const DAY_SKY_HORIZON := Color(0.82, 0.68, 0.5, 1)
|
||||
const DAY_SKY_TOP := Color(0.27, 0.57, 0.74, 1)
|
||||
const DAY_SKY_HORIZON := Color(0.79, 0.88, 0.82, 1)
|
||||
const DAY_GROUND_BOTTOM := Color(0.12, 0.17, 0.12, 1)
|
||||
const DAY_GROUND_HORIZON := Color(0.62, 0.55, 0.42, 1)
|
||||
const DAY_AMBIENT := Color(0.91, 0.85, 0.72, 1)
|
||||
const DAY_AMBIENT_ENERGY := 0.7
|
||||
const DAY_FOG_LIGHT := Color(0.82, 0.78, 0.66, 1)
|
||||
const DAY_FOG_LIGHT_ENERGY := 0.72
|
||||
const DAY_FOG_DENSITY := 0.002
|
||||
const DAY_LIGHT_COLOR := Color(1, 0.87, 0.72, 1)
|
||||
const DAY_LIGHT_ENERGY := 1.45
|
||||
const DAY_GROUND_HORIZON := Color(0.56, 0.69, 0.57, 1)
|
||||
const DAY_AMBIENT := Color(0.72, 0.83, 0.88, 1)
|
||||
const DAY_AMBIENT_ENERGY := 0.55
|
||||
const DAY_FOG_LIGHT := Color(0.70, 0.83, 0.81, 1)
|
||||
const DAY_FOG_LIGHT_ENERGY := 0.8
|
||||
const DAY_FOG_DENSITY := 0.0015
|
||||
const DAY_LIGHT_COLOR := Color(1, 0.94, 0.79, 1)
|
||||
const DAY_LIGHT_ENERGY := 1.2
|
||||
|
||||
const NIGHT_SKY_TOP := Color(0.04, 0.04, 0.12, 1)
|
||||
const NIGHT_SKY_HORIZON := Color(0.08, 0.06, 0.14, 1)
|
||||
@@ -123,6 +123,19 @@ func _apply_environment(cycle: float) -> void:
|
||||
mat.sky_horizon_color = _lerp_color(NIGHT_SKY_HORIZON, DAY_SKY_HORIZON, day_factor)
|
||||
mat.ground_bottom_color = _lerp_color(NIGHT_GROUND_BOTTOM, DAY_GROUND_BOTTOM, day_factor)
|
||||
mat.ground_horizon_color = _lerp_color(NIGHT_GROUND_HORIZON, DAY_GROUND_HORIZON, day_factor)
|
||||
elif sky != null and sky.sky_material is ShaderMaterial:
|
||||
var mat := sky.sky_material as ShaderMaterial
|
||||
mat.set_shader_parameter("sky_top_color", NIGHT_SKY_TOP.lerp(DAY_SKY_TOP, day_factor))
|
||||
mat.set_shader_parameter(
|
||||
"sky_horizon_color", NIGHT_SKY_HORIZON.lerp(DAY_SKY_HORIZON, day_factor)
|
||||
)
|
||||
mat.set_shader_parameter(
|
||||
"ground_bottom_color", NIGHT_GROUND_BOTTOM.lerp(DAY_GROUND_BOTTOM, day_factor)
|
||||
)
|
||||
mat.set_shader_parameter(
|
||||
"ground_horizon_color", NIGHT_GROUND_HORIZON.lerp(DAY_GROUND_HORIZON, day_factor)
|
||||
)
|
||||
mat.set_shader_parameter("daylight", day_factor)
|
||||
|
||||
|
||||
func _find_simulation_node() -> void:
|
||||
|
||||
@@ -1,70 +1,66 @@
|
||||
// Adapted for The Steward from the bundled Terrain3D particle-grass example.
|
||||
// Original Blender tuft. Opaque blades avoid alpha overdraw and sorting.
|
||||
shader_type spatial;
|
||||
|
||||
render_mode skip_vertex_transform, cull_disabled, blend_mix;
|
||||
render_mode skip_vertex_transform, cull_disabled, specular_disabled;
|
||||
|
||||
const int MAX_INTERACTORS = 8;
|
||||
|
||||
uniform vec2 wind_direction = vec2(1.0, 0.7);
|
||||
uniform vec3 base_color : source_color = vec3(0.16, 0.31, 0.08);
|
||||
uniform vec3 tip_color : source_color = vec3(0.54, 0.68, 0.24);
|
||||
uniform float wind_amount : hint_range(0.0, 1.0) = 0.34;
|
||||
uniform vec3 base_color : source_color = vec3(0.23, 0.40, 0.22);
|
||||
uniform vec3 tip_color : source_color = vec3(0.53, 0.67, 0.35);
|
||||
uniform float wind_amount : hint_range(0.0, 1.0) = 0.24;
|
||||
uniform int interactor_count : hint_range(0, 8) = 0;
|
||||
uniform vec3 interactor_positions[MAX_INTERACTORS];
|
||||
uniform float interaction_radius : hint_range(0.25, 4.0) = 1.8;
|
||||
uniform float interaction_strength : hint_range(0.0, 2.0) = 0.75;
|
||||
|
||||
varying vec4 grass_data;
|
||||
uniform float interaction_strength : hint_range(0.0, 2.0) = 0.55;
|
||||
uniform int clearing_count = 0;
|
||||
uniform vec4 clearing_segments[4];
|
||||
uniform vec4 clearing_half_widths = vec4(0.0);
|
||||
varying float blade_height;
|
||||
varying float shade_variation;
|
||||
varying float pressed_weight;
|
||||
|
||||
|
||||
void vertex() {
|
||||
grass_data[2] = VERTEX.y + 0.55;
|
||||
grass_data[2] *= grass_data[2];
|
||||
VERTEX.xz *= 1.0 - grass_data[2];
|
||||
COLOR = mix(COLOR, vec4(1.0), smoothstep(0.9, 1.0, grass_data[2]));
|
||||
COLOR *= INSTANCE_CUSTOM[3] < 0.35 ? 1.0 : mix(1.0, 0.75, smoothstep(0.35, 0.0, grass_data[2]));
|
||||
grass_data.rg = INSTANCE_CUSTOM.rg;
|
||||
|
||||
blade_height = UV.y;
|
||||
float tip_weight = blade_height * blade_height;
|
||||
vec3 anchor = MODEL_MATRIX[3].xyz;
|
||||
float clearing_scale = 1.0;
|
||||
for (int index = 0; index < 4; index++) {
|
||||
if (index >= clearing_count) { break; }
|
||||
vec2 start = clearing_segments[index].xy;
|
||||
vec2 line = clearing_segments[index].zw - start;
|
||||
float along = clamp(dot(anchor.xz - start, line) / max(dot(line, line), 0.001), 0.0, 1.0);
|
||||
float distance_to_path = length(anchor.xz - start - line * along);
|
||||
clearing_scale *= smoothstep(clearing_half_widths[index], clearing_half_widths[index] + 0.20, distance_to_path);
|
||||
}
|
||||
VERTEX *= clearing_scale;
|
||||
tip_weight *= clearing_scale;
|
||||
vec3 world_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||
float scale = pow(INSTANCE_CUSTOM[3] * INSTANCE_CUSTOM[3], 0.707);
|
||||
float force = INSTANCE_CUSTOM[2] * grass_data[2] * scale * wind_amount;
|
||||
force -= fract(force * 256.0) * force * 0.05;
|
||||
force = pow(max(force, 0.0), 0.707);
|
||||
float lateral_wobble = sin(TIME * 2.0 * (1.0 + grass_data.r + grass_data.g)) * 0.2 * (1.0 - INSTANCE_CUSTOM[2]);
|
||||
vec2 direction = normalize(wind_direction);
|
||||
world_vertex.xz -= (vec2(-direction.y, direction.x) * lateral_wobble + direction) * force;
|
||||
world_vertex.y -= INSTANCE_CUSTOM[2] * force * grass_data[2];
|
||||
grass_data[3] = force;
|
||||
|
||||
float phase = dot(anchor.xz, vec2(0.38, 0.29));
|
||||
float gust = sin(TIME * 1.15 + phase) * 0.65 + sin(TIME * 0.58 + phase * 0.42) * 0.35;
|
||||
world_vertex.xz += normalize(wind_direction) * gust * wind_amount * tip_weight;
|
||||
shade_variation = sin(anchor.x * 0.30 + anchor.z * 0.21) * 0.5 + 0.5;
|
||||
pressed_weight = 0.0;
|
||||
for (int index = 0; index < MAX_INTERACTORS; index++) {
|
||||
if (index >= interactor_count) {
|
||||
break;
|
||||
}
|
||||
vec2 offset = world_vertex.xz - interactor_positions[index].xz;
|
||||
if (index >= interactor_count) { break; }
|
||||
vec2 offset = anchor.xz - interactor_positions[index].xz;
|
||||
float distance_to_actor = length(offset);
|
||||
float influence = 1.0 - smoothstep(0.25, interaction_radius, distance_to_actor);
|
||||
vec2 away = offset / max(distance_to_actor, 0.08);
|
||||
world_vertex.xz += away * influence * interaction_strength * grass_data[2];
|
||||
world_vertex.y -= influence * 0.28 * grass_data[2];
|
||||
world_vertex.xz += away * influence * interaction_strength * tip_weight;
|
||||
world_vertex.y -= influence * 0.18 * tip_weight;
|
||||
pressed_weight = max(pressed_weight, influence);
|
||||
}
|
||||
|
||||
VERTEX = (VIEW_MATRIX * vec4(world_vertex, 1.0)).xyz;
|
||||
NORMAL = MODELVIEW_NORMAL_MATRIX * NORMAL;
|
||||
BINORMAL = MODELVIEW_NORMAL_MATRIX * BINORMAL;
|
||||
TANGENT = MODELVIEW_NORMAL_MATRIX * TANGENT;
|
||||
NORMAL = normalize((VIEW_MATRIX * vec4(0.0, 1.0, 0.0, 0.0)).xyz);
|
||||
}
|
||||
|
||||
|
||||
void fragment() {
|
||||
vec3 color = mix(base_color, tip_color, grass_data[2] * 0.62);
|
||||
color.rg *= grass_data.rg * 0.18 + 0.91;
|
||||
color *= pow(COLOR.rgb, vec3(2.2));
|
||||
ALBEDO = mix(color, base_color * 0.72, pressed_weight * 0.42);
|
||||
float specular_roughness = clamp(max(grass_data[2], grass_data[3]), 0.0, 1.0);
|
||||
ROUGHNESS = 1.0 - specular_roughness * 0.22;
|
||||
SPECULAR = clamp(specular_roughness * 0.2, 0.0, 0.12);
|
||||
BACKLIGHT = tip_color * 0.24;
|
||||
vec3 color = mix(base_color, tip_color, smoothstep(0.05, 1.0, blade_height) * 0.78);
|
||||
color *= mix(0.90, 1.09, shade_variation);
|
||||
ALBEDO = mix(color, base_color, pressed_weight * 0.15);
|
||||
ROUGHNESS = 1.0;
|
||||
}
|
||||
|
||||
void light() {
|
||||
float band = smoothstep(0.05, 0.16, dot(NORMAL, LIGHT));
|
||||
DIFFUSE_LIGHT += mix(vec3(0.46, 0.60, 0.52), vec3(1.0, 0.98, 0.85), band) * LIGHT_COLOR * ATTENUATION / PI;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@ resource_local_to_scene = true
|
||||
render_priority = 0
|
||||
shader = ExtResource("1_grass")
|
||||
shader_parameter/wind_direction = Vector2(1, 0.7)
|
||||
shader_parameter/base_color = Color(0.16, 0.31, 0.08, 1)
|
||||
shader_parameter/tip_color = Color(0.54, 0.68, 0.24, 1)
|
||||
shader_parameter/wind_amount = 0.34
|
||||
shader_parameter/base_color = Color(0.23, 0.40, 0.22, 1)
|
||||
shader_parameter/tip_color = Color(0.53, 0.67, 0.35, 1)
|
||||
shader_parameter/wind_amount = 0.24
|
||||
shader_parameter/interactor_count = 0
|
||||
shader_parameter/interactor_positions = PackedVector3Array(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
|
||||
shader_parameter/interaction_radius = 1.8
|
||||
shader_parameter/interaction_strength = 0.75
|
||||
shader_parameter/interaction_strength = 0.55
|
||||
|
||||
@@ -16,13 +16,13 @@ resource_local_to_scene = true
|
||||
shader = ExtResource("1_process_shader")
|
||||
shader_parameter/main_noise = SubResource("NoiseTexture_grass")
|
||||
shader_parameter/main_noise_scale = 0.012
|
||||
shader_parameter/position_offset = Vector3(0, 0.22, 0)
|
||||
shader_parameter/position_offset = Vector3(0, 0.015, 0)
|
||||
shader_parameter/align_to_normal = true
|
||||
shader_parameter/normal_strength = 0.22
|
||||
shader_parameter/random_rotation = true
|
||||
shader_parameter/random_spacing = 0.72
|
||||
shader_parameter/min_scale = Vector3(0.09, 0.22, 0.09)
|
||||
shader_parameter/max_scale = Vector3(0.13, 0.48, 0.13)
|
||||
shader_parameter/min_scale = Vector3(0.72, 0.28, 0.72)
|
||||
shader_parameter/max_scale = Vector3(1.15, 0.48, 1.15)
|
||||
shader_parameter/noise_scale = 0.0041
|
||||
shader_parameter/wind_speed = 0.022
|
||||
shader_parameter/wind_strength = 0.6
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
shader_type sky;
|
||||
uniform vec3 sky_top_color : source_color = vec3(0.27, 0.57, 0.74);
|
||||
uniform vec3 sky_horizon_color : source_color = vec3(0.79, 0.88, 0.82);
|
||||
uniform vec3 ground_bottom_color : source_color = vec3(0.12, 0.17, 0.12);
|
||||
uniform vec3 ground_horizon_color : source_color = vec3(0.56, 0.69, 0.57);
|
||||
uniform float daylight : hint_range(0.0, 1.0) = 1.0;
|
||||
|
||||
float hash21(vec2 p) { return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453); }
|
||||
float noise(vec2 p) {
|
||||
vec2 i = floor(p);
|
||||
vec2 f = fract(p);
|
||||
f = f * f * (3.0 - 2.0 * f);
|
||||
return mix(mix(hash21(i), hash21(i + vec2(1.0, 0.0)), f.x), mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0)), f.x), f.y);
|
||||
}
|
||||
|
||||
void sky() {
|
||||
float height = max(EYEDIR.y, 0.0);
|
||||
vec3 sky_color = mix(sky_horizon_color, sky_top_color, pow(height, 0.48));
|
||||
vec2 p = EYEDIR.xz / max(0.17, height) * 1.15;
|
||||
float cloud = noise(p) * 0.65 + noise(p * 2.1 + 7.3) * 0.25 + noise(p * 4.3) * 0.10;
|
||||
float mask = smoothstep(0.55, 0.64, cloud) * smoothstep(0.02, 0.20, height);
|
||||
vec3 cloud_shadow = mix(vec3(0.08, 0.10, 0.19), vec3(0.70, 0.80, 0.80), daylight);
|
||||
vec3 cloud_light = mix(vec3(0.15, 0.18, 0.29), vec3(1.0, 0.98, 0.87), daylight);
|
||||
vec3 cloud_color = mix(cloud_shadow, cloud_light, smoothstep(0.61, 0.77, cloud));
|
||||
sky_color = mix(sky_color, cloud_color, mask);
|
||||
COLOR = EYEDIR.y >= 0.0 ? sky_color : mix(ground_horizon_color, ground_bottom_color, pow(-EYEDIR.y, 0.4));
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c10spbmnnwwto
|
||||
@@ -10,8 +10,10 @@ uniform float flutter_strength : hint_range(0.0, 0.05) = 0.012;
|
||||
uniform float wind_phase : hint_range(0.0, 6.2832) = 0.0;
|
||||
uniform vec3 albedo : source_color = vec3(0.19, 0.38, 0.17);
|
||||
uniform float roughness : hint_range(0.0, 1.0) = 0.9;
|
||||
varying vec3 paint_position;
|
||||
|
||||
void vertex() {
|
||||
paint_position = 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;
|
||||
@@ -29,6 +31,17 @@ void vertex() {
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
ALBEDO = albedo;
|
||||
float patches = sin(paint_position.x * 6.0 + sin(paint_position.z * 7.0)) * sin(paint_position.y * 5.0);
|
||||
float top = smoothstep(-0.65, 0.8, paint_position.y);
|
||||
ALBEDO = albedo * mix(0.85, 1.17, top) * (1.0 + smoothstep(0.2, 0.4, patches) * 0.10);
|
||||
ROUGHNESS = roughness;
|
||||
SPECULAR = 0.0;
|
||||
}
|
||||
|
||||
void light() {
|
||||
float band = smoothstep(0.08, 0.18, dot(NORMAL, LIGHT));
|
||||
float highlight = smoothstep(0.62, 0.74, dot(NORMAL, LIGHT));
|
||||
vec3 tone = mix(vec3(0.32, 0.48, 0.39), vec3(0.87, 0.92, 0.72), band);
|
||||
tone = mix(tone, vec3(1.12, 1.08, 0.82), highlight);
|
||||
DIFFUSE_LIGHT += tone * ATTENUATION * LIGHT_COLOR / PI;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
class_name AnimalAppearance
|
||||
extends RefCounted
|
||||
## Disposable woodland identities, rebuilt from stable NPC IDs. No simulation RNG.
|
||||
|
||||
const CEL_SHADER := preload("res://world/presentation/materials/storybook_cel.gdshader")
|
||||
const SPECIES: Array[StringName] = [&"fox", &"rabbit", &"badger", &"otter"]
|
||||
const MODELS: Array[PackedScene] = [
|
||||
preload("res://assets/storybook/fox.glb"),
|
||||
preload("res://assets/storybook/rabbit.glb"),
|
||||
preload("res://assets/storybook/badger.glb"),
|
||||
preload("res://assets/storybook/otter.glb"),
|
||||
]
|
||||
const PARTS: Array[StringName] = [
|
||||
&"Body", &"Head", &"Hair", &"ArmLeft", &"ArmRight", &"LegLeft", &"LegRight", &"Tail"
|
||||
]
|
||||
|
||||
|
||||
static func apply_to(root: Node3D, identity: int, npc_body := false) -> void:
|
||||
var index := posmod(identity, MODELS.size())
|
||||
var source := MODELS[index].instantiate()
|
||||
var material := ShaderMaterial.new()
|
||||
material.shader = CEL_SHADER
|
||||
root.set_meta("animal_species", SPECIES[index])
|
||||
for part in PARTS:
|
||||
var source_mesh := source.find_child(String(part), true, false) as MeshInstance3D
|
||||
var target_name := "MeshInstance3D" if npc_body and part == &"Body" else String(part)
|
||||
var target := root.get_node(target_name) as MeshInstance3D
|
||||
assert(source_mesh != null, "Missing Blender animation part: " + String(part))
|
||||
target.mesh = source_mesh.mesh
|
||||
target.material_override = material
|
||||
source.free()
|
||||
|
||||
|
||||
static func set_profession_color(root: Node3D, color: Color) -> void:
|
||||
var body := root.get_node("MeshInstance3D") as MeshInstance3D
|
||||
var material := body.material_override as ShaderMaterial
|
||||
material.set_shader_parameter("coat_color", color)
|
||||
material.set_shader_parameter("profession_tint", 0.28)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dfb2a5yut45av
|
||||
@@ -0,0 +1,23 @@
|
||||
shader_type spatial;
|
||||
render_mode specular_disabled;
|
||||
|
||||
// Opaque vertex-painted models: alpha is a clothing mask, never transparency.
|
||||
uniform vec4 coat_color : source_color = vec4(1.0);
|
||||
uniform float profession_tint : hint_range(0.0, 1.0) = 0.0;
|
||||
uniform vec3 shadow_color : source_color = vec3(0.55, 0.64, 0.70);
|
||||
uniform float band_softness : hint_range(0.005, 0.2) = 0.045;
|
||||
|
||||
void fragment() {
|
||||
ALBEDO = mix(COLOR.rgb, COLOR.rgb * coat_color.rgb * 1.6, COLOR.a * profession_tint);
|
||||
ROUGHNESS = 1.0;
|
||||
SPECULAR = 0.0;
|
||||
}
|
||||
|
||||
void light() {
|
||||
float diffuse = dot(NORMAL, LIGHT);
|
||||
float mid = smoothstep(-0.15 - band_softness, -0.15 + band_softness, diffuse);
|
||||
float sun = smoothstep(0.50 - band_softness, 0.50 + band_softness, diffuse);
|
||||
vec3 tone = mix(shadow_color * 0.36, vec3(0.70), mid);
|
||||
tone = mix(tone, vec3(1.0, 0.97, 0.87), sun);
|
||||
DIFFUSE_LIGHT += tone * ATTENUATION * LIGHT_COLOR / PI;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bs1ip7dyu7jy8
|
||||
@@ -0,0 +1,24 @@
|
||||
shader_type spatial;
|
||||
render_mode specular_disabled;
|
||||
uniform vec3 albedo : source_color = vec3(0.8, 0.72, 0.52);
|
||||
uniform float paint_strength : hint_range(0.0, 0.2) = 0.04;
|
||||
varying vec3 paint_position;
|
||||
|
||||
void vertex() {
|
||||
paint_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
|
||||
}
|
||||
|
||||
void fragment() {
|
||||
float brush = sin(paint_position.x * 2.1 + sin(paint_position.y * 3.0)) * sin(paint_position.z * 2.8 + paint_position.y);
|
||||
ALBEDO = albedo * (1.0 + brush * paint_strength);
|
||||
ROUGHNESS = 1.0;
|
||||
}
|
||||
|
||||
void light() {
|
||||
float ndl = dot(NORMAL, LIGHT);
|
||||
float middle = smoothstep(-0.10, 0.03, ndl);
|
||||
float sunny = smoothstep(0.48, 0.58, ndl);
|
||||
vec3 shade = mix(vec3(0.26, 0.34, 0.40), vec3(0.74), middle);
|
||||
shade = mix(shade, vec3(1.0, 0.97, 0.88), sunny);
|
||||
DIFFUSE_LIGHT += shade * ATTENUATION * LIGHT_COLOR / PI;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c8biomtfwtf4w
|
||||
Reference in New Issue
Block a user