game/terrain/terrain_instance_3d.gd

87 lines
2.1 KiB
GDScript3
Raw Normal View History

2023-01-23 19:28:14 +01:00
@tool
2023-01-16 19:25:35 +01:00
class_name TerrainInstance3D extends GeometryInstance3D
2023-01-23 19:28:14 +01:00
const _DETAIL := 2
const _SHADER := preload("res://terrain/terrain.gdshader")
2023-01-23 21:29:43 +01:00
##
## Slots representing the paintable channels.
##
2023-01-18 18:15:41 +01:00
enum PaintSlot {
ERASE,
PAINT_1,
PAINT_2,
PAINT_3,
2023-01-18 18:15:41 +01:00
}
2023-01-16 19:25:35 +01:00
var _albedo_maps: Array[Texture2D] = []
2023-01-16 19:25:35 +01:00
2023-01-18 18:15:41 +01:00
var _material := ShaderMaterial.new()
2023-01-16 19:25:35 +01:00
2023-01-18 18:15:41 +01:00
var _mesh := PlaneMesh.new()
2023-01-16 19:25:35 +01:00
var _normal_maps: Array[Texture2D] = []
2023-01-23 19:28:14 +01:00
##
2023-01-23 21:29:43 +01:00
## Range of the height channel value, ranging from [code]0.0[/code] to [code]100.0[/code].
2023-01-16 19:25:35 +01:00
##
@export
2023-01-18 18:15:41 +01:00
var height_scale := 100.0:
2023-01-23 19:28:14 +01:00
set(value):
value = maxf(value, 1.0)
if not(is_equal_approx(value, height_scale)):
_material.set_shader_parameter("HEIGHT_SCALE", value)
2023-01-16 19:25:35 +01:00
2023-01-23 19:28:14 +01:00
height_scale = value
##
## Size of the terrain geometry (in engine units).
##
@export
var size := Vector2i.ONE:
2023-01-16 19:25:35 +01:00
set(value):
2023-01-23 19:28:14 +01:00
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
2023-01-16 19:25:35 +01:00
2023-01-23 19:28:14 +01:00
_material.set_shader_parameter("SIZE", value)
2023-01-16 19:25:35 +01:00
2023-01-23 19:28:14 +01:00
size = value
2023-01-16 19:25:35 +01:00
2023-01-18 18:15:41 +01:00
func _init() -> void:
var paint_channels := PaintSlot.values().size()
_albedo_maps.resize(paint_channels)
_normal_maps.resize(paint_channels)
2023-01-23 19:28:14 +01:00
_material.shader = _SHADER
2023-01-16 19:25:35 +01:00
2023-01-18 18:15:41 +01:00
_mesh.surface_set_material(0, _material)
2023-01-23 19:28:14 +01:00
RenderingServer.instance_set_base(get_instance(), _mesh)
2023-01-16 19:25:35 +01:00
##
2023-01-23 19:28:14 +01:00
## Updates the terrain map being used by the terrain to be [code]terrain_map[/code].
2023-01-16 19:25:35 +01:00
##
2023-01-23 19:28:14 +01:00
func update_map(terrain_map: Texture2D) -> void:
_material.set_shader_parameter("TERRAIN_MAP", terrain_map)
2023-01-16 19:25:35 +01:00
##
2023-01-23 19:28:14 +01:00
## Updates the [TerrainPaint] being used by the terrain in [code]paint_slot[/code] to be
2023-01-18 18:15:41 +01:00
## [code]terrain_paint[/code].
2023-01-16 19:25:35 +01:00
##
2023-01-23 19:28:14 +01:00
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
2023-01-16 19:25:35 +01:00
2023-01-23 19:28:14 +01:00
_material.set_shader_parameter("ALBEDO_MAPS", _albedo_maps)
2023-01-16 19:25:35 +01:00
2023-01-23 19:28:14 +01:00
if _normal_maps[paint_slot] != terrain_paint.normal_map:
_normal_maps[paint_slot] = terrain_paint.normal_map
2023-01-16 19:25:35 +01:00
2023-01-23 19:28:14 +01:00
_material.set_shader_parameter("NORMAL_MAPS", _normal_maps)