game/terrain/terrain_instance_3d.gd

87 lines
2.1 KiB
GDScript

@tool
class_name TerrainInstance3D extends GeometryInstance3D
const _DETAIL := 2
const _SHADER := preload("res://terrain/terrain.gdshader")
##
## Slots representing the paintable channels.
##
enum PaintSlot {
ERASE,
PAINT_1,
PAINT_2,
PAINT_3,
}
var _albedo_maps: Array[Texture2D] = []
var _material := ShaderMaterial.new()
var _mesh := PlaneMesh.new()
var _normal_maps: Array[Texture2D] = []
##
## Range of the height channel value, ranging from [code]0.0[/code] to [code]100.0[/code].
##
@export
var height_scale := 100.0:
set(value):
value = maxf(value, 1.0)
if not(is_equal_approx(value, height_scale)):
_material.set_shader_parameter("HEIGHT_SCALE", value)
height_scale = value
##
## Size of the terrain geometry (in engine units).
##
@export
var size := Vector2i.ONE:
set(value):
value = Vector2i(maxi(value.x, 1), maxi(value.y, 1))
if (value.x != size.x) or (value.y != size.y):
_mesh.subdivide_width = value.x * _DETAIL
_mesh.subdivide_depth = value.y * _DETAIL
_mesh.size = value
_material.set_shader_parameter("SIZE", value)
size = value
func _init() -> void:
var paint_channels := PaintSlot.values().size()
_albedo_maps.resize(paint_channels)
_normal_maps.resize(paint_channels)
_material.shader = _SHADER
_mesh.surface_set_material(0, _material)
RenderingServer.instance_set_base(get_instance(), _mesh)
##
## Updates the terrain map being used by the terrain to be [code]terrain_map[/code].
##
func update_map(terrain_map: Texture2D) -> void:
_material.set_shader_parameter("TERRAIN_MAP", terrain_map)
##
## Updates the [TerrainPaint] being used by the terrain in [code]paint_slot[/code] to be
## [code]terrain_paint[/code].
##
func update_paint(paint_slot: PaintSlot, terrain_paint: TerrainPaint) -> void:
if _albedo_maps[paint_slot] != terrain_paint.albedo_map:
_albedo_maps[paint_slot] = terrain_paint.albedo_map
_material.set_shader_parameter("ALBEDO_MAPS", _albedo_maps)
if _normal_maps[paint_slot] != terrain_paint.normal_map:
_normal_maps[paint_slot] = terrain_paint.normal_map
_material.set_shader_parameter("NORMAL_MAPS", _normal_maps)