feat: full cel treatment for Neon Alley — flat toon colors + ink outlines
- LevelMaterials.flat(): toon-banded FLAT color material (no greybox grid texture) for dressed maps; cached per tint, rim/spec off - Neon Alley overrides _box_static: every structure renders flat cel color; prop-scale pieces (<10m) get an inverted-hull ink outline scaled to their size. Building-scale boxes skip the hull — the inflated plates smear into black voids at close range (found via fixed street-camera capture) - Pylon wires render as flat ink lines; warmer wood + hotter vermilion for flat shading (the grid multiply used to brighten tints) - visual_capture: deterministic street-level shot after the aerial for style comparisons Street capture now reads properly BoomerangX: flat lavender asphalt, hard light bands, torii framed down the underpass, neon strips + sign glow. Co-Authored-By: Claude Fable 5 <[email protected]>
This commit is contained in:
co-authored by
Claude Fable 5
parent
0813d0b40d
commit
233f88aee3
@@ -48,6 +48,13 @@ func _process(_delta: float) -> bool:
|
||||
aerial.current = true
|
||||
elif _frames == 340:
|
||||
_shot("aerial")
|
||||
# Fixed street-level view for deterministic style comparisons
|
||||
var cam := root.get_camera_3d()
|
||||
if cam:
|
||||
cam.global_position = Vector3(3, 2.2, 20)
|
||||
cam.look_at(Vector3(-8, 4, -18), Vector3.UP)
|
||||
elif _frames == 360:
|
||||
_shot("street")
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
@@ -51,6 +51,26 @@ static func tinted(tint: Color, dark: bool = false) -> Material:
|
||||
return mat
|
||||
|
||||
|
||||
static var _flat_cache: Dictionary = {}
|
||||
|
||||
## Flat cel color: toon banding with NO grid texture — the full stylized
|
||||
## look for dressed maps (vs. tinted()'s greybox grid for blockouts).
|
||||
## Rim/specular stay off (they blob on large level surfaces).
|
||||
static func flat(tint: Color) -> Material:
|
||||
var key := tint.to_html()
|
||||
if _flat_cache.has(key):
|
||||
return _flat_cache[key]
|
||||
var mat := ShaderMaterial.new()
|
||||
mat.shader = load(TOON_SHADER)
|
||||
mat.set_shader_parameter("has_texture", false)
|
||||
mat.set_shader_parameter("use_triplanar", false)
|
||||
mat.set_shader_parameter("albedo_color", tint)
|
||||
mat.set_shader_parameter("rim_strength", 0.0)
|
||||
mat.set_shader_parameter("specular_strength", 0.0)
|
||||
_flat_cache[key] = mat
|
||||
return mat
|
||||
|
||||
|
||||
## Toon version of an arbitrary material (usually a character's imported
|
||||
## StandardMaterial3D): keeps its albedo texture/color, swaps the shading.
|
||||
static func toonify(src: Material) -> Material:
|
||||
|
||||
@@ -21,9 +21,9 @@ const ASPHALT := Color(0.24, 0.24, 0.31)
|
||||
const PAVING := Color(0.4, 0.38, 0.44)
|
||||
const CONCRETE := Color(0.52, 0.5, 0.55)
|
||||
const CONCRETE_DARK := Color(0.38, 0.37, 0.44)
|
||||
const WOOD := Color(0.45, 0.3, 0.18)
|
||||
const WOOD_DARK := Color(0.32, 0.21, 0.13)
|
||||
const VERMILION := Color(0.82, 0.25, 0.16) # torii / shrine red
|
||||
const WOOD := Color(0.52, 0.34, 0.2)
|
||||
const WOOD_DARK := Color(0.36, 0.24, 0.15)
|
||||
const VERMILION := Color(0.88, 0.26, 0.16) # torii / shrine red
|
||||
const METAL := Color(0.42, 0.46, 0.52)
|
||||
const GLASS := Color(0.6, 0.78, 0.82)
|
||||
const ROOF_TILE := Color(0.25, 0.3, 0.42)
|
||||
@@ -39,6 +39,23 @@ const SPAWNS: Array[Vector3] = [
|
||||
]
|
||||
|
||||
|
||||
## Full cel treatment: every structure gets a FLAT toon color (no greybox
|
||||
## grid texture) plus an ink outline hull scaled to its size — the same
|
||||
## inked-silhouette language as the characters. Ground-scale slabs skip the
|
||||
## outline (a hull around an 80m floor just z-fights the sidewalks).
|
||||
func _box_static(pos: Vector3, size: Vector3, color: Color, node_name: String = "",
|
||||
acoustic: String = "") -> StaticBody3D:
|
||||
var body := super._box_static(pos, size, color, node_name, acoustic)
|
||||
for mi in body.find_children("*", "MeshInstance3D", false, false):
|
||||
mi.mesh.surface_set_material(0, LevelMaterials.flat(color))
|
||||
# Ink outlines on prop-scale pieces only: on building-scale boxes the
|
||||
# inflated hull plates read as smears at close range.
|
||||
if maxf(size.x, maxf(size.y, size.z)) < 10.0:
|
||||
var w := clampf(maxf(size.x, maxf(size.y, size.z)) * 0.008, 0.02, 0.05)
|
||||
mi.material_overlay = LevelMaterials.outline(w)
|
||||
return body
|
||||
|
||||
|
||||
func _build_environment() -> void:
|
||||
var env := LevelEnvironment.add_to(self, "sunset")
|
||||
# The sunset sky is too dark to light street canyons — use a fixed dusk
|
||||
@@ -242,7 +259,7 @@ func _build_pylons() -> void:
|
||||
var wire := MeshInstance3D.new()
|
||||
var wm := BoxMesh.new()
|
||||
wm.size = Vector3(0.06, 0.06, 16.0)
|
||||
wm.material = LevelMaterials.tinted(Color(0.1, 0.1, 0.12))
|
||||
wm.material = LevelMaterials.flat(Color(0.08, 0.07, 0.1)) # ink line in the sky
|
||||
wire.mesh = wm
|
||||
wire.position = Vector3(x - 7.5 * side, 10.0, z + 9.0)
|
||||
add_child(wire)
|
||||
|
||||
Reference in New Issue
Block a user