Files
Blockline/scripts/quarry_realism.gd
T

117 lines
5.2 KiB
GDScript
Raw Normal View History

2026-09-12 11:01:37 +02:00
class_name QuarryRealism
extends RefCounted
const ASSETS := "res://assets/scan/quarry_realism/"
static var scenes: Dictionary = {}
static func place(parent: Node3D, id: String, bottom: Vector3, dimensions: Vector3, yaw: float = 0.0) -> Node3D:
if not scenes.has(id): scenes[id] = load(ASSETS + id + "/model.scn")
var model: Node3D = scenes[id].instantiate()
var entries: Array = []
QuarryLandscape.collect(model, Transform3D.IDENTITY, entries)
var bounds := AABB()
var first := true
for entry: Array in entries:
var aabb: AABB = entry[1] * entry[0].get_aabb()
bounds = aabb if first else bounds.merge(aabb)
first = false
var fit := dimensions / bounds.size
model.scale = fit
model.position = -Vector3(bounds.get_center().x, bounds.position.y, bounds.get_center().z) * fit
var anchor := Node3D.new()
anchor.name = "Scan_" + id
anchor.position = bottom
anchor.rotation.y = yaw
parent.add_child(anchor)
anchor.add_child(model)
for mesh in model.find_children("*", "MeshInstance3D", true, false):
mesh.visibility_range_end = 85
mesh.visibility_range_end_margin = 10
return anchor
static func apply(arena: RelayArena) -> void:
if arena.map_id != "quarry" or DisplayServer.get_name() == "headless": return
var replacements: Dictionary = {}
for key: String in UrbanMaterials.cache:
var asset := ""
if key.begins_with("asphalt"): asset = "aerial_asphalt_01"
elif key.begins_with("concrete") or key.begins_with("plaster"): asset = "concrete_wall_007"
elif key.begins_with("metal"): asset = "rusty_metal_02"
if asset.is_empty(): continue
var source: StandardMaterial3D = UrbanMaterials.cache[key]
var mat := (load("res://assets/textures/quarry_realism/" + asset + "/surface.tres") as StandardMaterial3D).duplicate() as StandardMaterial3D
mat.albedo_color = source.albedo_color.lerp(Color.WHITE, 0.5)
if asset == "rusty_metal_02": mat.albedo_color = source.albedo_color.darkened(0.3)
if asset == "aerial_asphalt_01":
mat.albedo_color = Color("757575")
mat.normal_scale = 0.45
replacements[source.get_instance_id()] = mat
for node in arena.find_children("*", "MeshInstance3D", true, false):
for surface in node.mesh.get_surface_count():
var original: Material = node.get_active_material(surface)
if original != null and replacements.has(original.get_instance_id()):
if node.material_override != null:
node.material_override = replacements[original.get_instance_id()]
else: node.set_surface_override_material(surface, replacements[original.get_instance_id()])
var detail := Node3D.new()
detail.name = "PhotogrammetryDressing"
arena.add_child(detail)
# Replace only the art enclosed by existing solid cover bounds.
for child in arena.get_children():
if not child is Node3D: continue
if str(child.name).begins_with("UrbanSaloon"):
child.visible = false
place(detail, "covered_car", child.position, Vector3(2.29,1.91,4.58))
if child.visible and child.find_child("ConcreteBarrier*", true, false) != null:
child.visible = false
place(detail, "concrete_road_barrier", child.position - Vector3(0,0.7,0), Vector3(3.2,1.4,1.5))
for origin in arena.building_origins:
place(detail, "portable_generator", origin + Vector3(-2,0,0), Vector3(1.65,1.28,2.3), 0)
# Recessed against a solid facade pier: never inside an entrance opening.
place(detail, "Barrel_02", origin + Vector3(3.35,0.03,5.38), Vector3(0.58,0.88,0.58), origin.z)
# Low, flat discarded tyres hug exterior wall piers, away from doorways.
place(detail, "old_tyre", origin + Vector3(3.9,0.04,5.95), Vector3(0.65,0.16,0.65), origin.x)
var freight := arena.get_node_or_null("DepotDetails")
if freight != null:
for location: Vector3 in DepotDetails.FREIGHT_POSITIONS:
# Scanned timber replaces the visually repeated flat cargo faces.
for side in [-1,1]:
place(detail, "wooden_crate_02", location + Vector3(side * 0.8,-0.7,0), Vector3(1.58,1.4,1.5))
lighting(arena)
static func lighting(arena: RelayArena) -> void:
var world := arena.get_node("DistrictAtmosphere") as WorldEnvironment
var env := world.environment
var sky := Sky.new()
var panorama := PanoramaSkyMaterial.new()
panorama.panorama = load("res://assets/sky/relay_clouds.hdr")
sky.sky_material = panorama
sky.radiance_size = Sky.RADIANCE_SIZE_256
env.sky = sky
env.sky_rotation = Vector3(0,0.8,0)
env.background_energy_multiplier = 0.85
env.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
env.ambient_light_sky_contribution = 1.0
env.ambient_light_energy = 0.3
env.tonemap_exposure = 0.9
env.ssao_radius = 1.0
env.ssao_intensity = 1.1
env.ssao_detail = 0.65
env.fog_density = 0.0008
env.fog_light_color = Color("bac6cd")
env.fog_aerial_perspective = 0.35
var sun := arena.get_node("LateAfternoonSun") as DirectionalLight3D
sun.light_color = Color("fff3de")
sun.light_energy = 1.35
sun.light_angular_distance = 0.8
sun.shadow_normal_bias = 0.3
static func quality(arena: RelayArena, level: int) -> void:
if arena.map_id != "quarry": return
var world := arena.get_node_or_null("DistrictAtmosphere") as WorldEnvironment
if world == null: return
var forward := RenderingServer.get_current_rendering_method() == "forward_plus"
world.environment.ssil_enabled = forward and level == 2
world.environment.ssil_intensity = 0.65
world.environment.ssr_enabled = forward and level == 2