straywild/world/environment/precipitation_occlusion.gd

56 lines
1.8 KiB
GDScript

class_name PrecipitationOcclusion
extends RefCounted
## A secondary visual layer used only when building the local rain height field.
## Canopy meshes remain on layer 1 for ordinary cameras.
const RENDER_LAYER_NUMBER: int = 20
const RENDER_LAYER_MASK: int = 1 << (RENDER_LAYER_NUMBER - 1)
const CANOPY_MATERIAL_NAMES: Array[String] = [
"leaf",
"leaf_light",
"leaf_mid",
"leaf_dark",
"pine",
"tree",
]
static func mark_canopy_meshes(root_node: Node) -> int:
if root_node == null:
return 0
var marked_count: int = 0
var mesh_instance := root_node as MeshInstance3D
if mesh_instance != null and _has_canopy_material(mesh_instance):
mesh_instance.layers |= RENDER_LAYER_MASK
marked_count += 1
for child: Node in root_node.get_children():
marked_count += mark_canopy_meshes(child)
return marked_count
## Generated tree definitions are already explicit terrain metadata, so every
## mesh in their visual scene can safely participate. This also supports older
## combined tree meshes whose imported material name does not identify leaves.
static func mark_tree_meshes(root_node: Node) -> int:
if root_node == null:
return 0
var marked_count: int = 0
var mesh_instance := root_node as MeshInstance3D
if mesh_instance != null:
mesh_instance.layers |= RENDER_LAYER_MASK
marked_count += 1
for child: Node in root_node.get_children():
marked_count += mark_tree_meshes(child)
return marked_count
static func _has_canopy_material(mesh_instance: MeshInstance3D) -> bool:
if mesh_instance == null or mesh_instance.mesh == null:
return false
for surface_index: int in mesh_instance.mesh.get_surface_count():
var material := mesh_instance.mesh.surface_get_material(surface_index)
if material == null:
continue
if material.resource_name.to_lower() in CANOPY_MATERIAL_NAMES:
return true
return false