Editor Terrain Brush #2

Merged
kayomn merged 27 commits from editor-terrain-brush into main 2023-01-19 01:51:25 +01:00
53 changed files with 358 additions and 323 deletions
Showing only changes of commit c7a0d6bce2 - Show all commits

BIN
black.png (Stored with Git LFS) Normal file

Binary file not shown.

34
black.png.import Normal file
View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cj72ibo3c6x8e"
path="res://.godot/imported/black.png-19a8df0b1a4edb74ea2eecb66d46d03d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://black.png"
dest_files=["res://.godot/imported/black.png-19a8df0b1a4edb74ea2eecb66d46d03d.ctex"]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

BIN
editor.scn (Stored with Git LFS)

Binary file not shown.

BIN
editor/brush_hard_circle_mask.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
[remap]
importer="image"
type="Image"
uid="uid://drok88h02tdre"
path="res://.godot/imported/brush_hard_circle_mask.png-e647df7b970f00cdf2f3f2ac38ad8257.image"
[deps]
source_file="res://editor/brush_hard_circle_mask.png"
dest_files=["res://.godot/imported/brush_hard_circle_mask.png-e647df7b970f00cdf2f3f2ac38ad8257.image"]
[params]

BIN
editor/edit_mode_button_group.res (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -9,10 +9,10 @@
config_version=5
_global_script_classes=[{
"base": "Node",
"class": &"EditableTerrain",
"base": "TerrainInstance3D",
"class": &"DynamicTerrainInstance3D",
"language": &"GDScript",
"path": "res://editor/editable_terrain.gd"
"path": "res://terrain/dynamic_terrain_instance_3d.gd"
}, {
"base": "Node3D",
"class": &"PlayerController",
@ -28,18 +28,25 @@ _global_script_classes=[{
"class": &"TerrainInstance3D",
"language": &"GDScript",
"path": "res://terrain/terrain_instance_3d.gd"
}, {
"base": "Resource",
"class": &"TerrainPaint",
"language": &"GDScript",
"path": "res://terrain/paints/terrain_paint.gd"
}]
_global_script_class_icons={
"EditableTerrain": "",
"DynamicTerrainInstance3D": "",
"PlayerController": "",
"Settings": "",
"TerrainInstance3D": ""
"TerrainInstance3D": "",
"TerrainPaint": ""
}
[application]
config/name="Protectorate"
run/main_scene="res://editor.scn"
config/use_custom_user_dir=true
config/features=PackedStringArray("4.0", "Forward Plus")
config/icon="res://icon.png"

View File

@ -1,70 +1,46 @@
class_name EditableTerrain extends Node
class_name DynamicTerrainInstance3D extends TerrainInstance3D
##
## Blank sample value.
##
const BLANK := Color(0.0, 0.0, 0.0, 0.0)
var _image := Image.create(1, 1, false, Image.FORMAT_RGBAF)
var _editable_image: Image
##
## Tracked [TerrainInstance3D] to echo all terrain editing changes to.
##
var instance: TerrainInstance3D = null:
get:
return instance
var _editable_texture: ImageTexture
set(value):
if (value != null) and (value != instance):
value.terrain_map = ImageTexture.create_from_image(_image)
instance = value
##
## Width and height of the editable terrain in units.
##
var size := Vector2i.ZERO:
get:
return size
set(value):
_image.resize(value.x, value.y)
if instance != null:
instance.size = value
instance.terrain_map = ImageTexture.create_from_image(_image)
size = value
func _get_brush_area(point: Vector2i, mask_size: Vector2i, scale: float) -> Rect2i:
func _get_brush_area(point: Vector2i, mask_size: Vector2i, mask_scale: float) -> Rect2i:
# Convert worldspace point to image-space coordinates for mask.
var scaled_mask_size := Vector2i(mask_size * scale)
var scaled_mask_size := Vector2i(mask_size * mask_scale)
return Rect2i((point + Vector2i(size * 0.5)) - Vector2i(scaled_mask_size * 0.5), scaled_mask_size)
return Rect2i((point + Vector2i(get_size() * 0.5)) - Vector2i(scaled_mask_size * 0.5), scaled_mask_size)
func _init() -> void:
clear(BLANK)
super._init()
_editable_image = Image.create(1, 1, false, Image.FORMAT_RGBAF)
_editable_texture = ImageTexture.create_from_image(_editable_image)
super.resize(Vector2i.ONE)
##
## Clears the image to the value of [code]clear_color[/code].
## Clears the terrain map to the value of [code]clear_elevation[/code].
##
func clear(clear_color: Color) -> void:
_image.fill(clear_color)
if instance != null:
instance.terrain_map.update(_image)
func clear(clear_elevation: float) -> void:
_editable_image.fill(Color(0.0, 0.0, 0.0, clampf(clear_elevation, 0.0, 1.0)))
_editable_texture.update(_editable_image)
##
##
##
func oscillate(point: Vector2i, level: float,
mask: Image, scale: float, intensity: float, delta: float) -> void:
mask: Image, mask_scale: float, intensity: float, delta: float) -> void:
var mask_size := mask.get_size()
var brush_source := _get_brush_area(point, mask_size, scale)
var brush_source := _get_brush_area(point, mask_size, mask_scale)
if brush_source.has_area():
var brush_target := Rect2i(Vector2i.ZERO, size).intersection(brush_source)
var brush_target := Rect2i(Vector2i.ZERO, get_size()).intersection(brush_source)
if brush_target.has_area():
var mask_ratio := mask_size / brush_source.size
@ -75,26 +51,25 @@ func oscillate(point: Vector2i, level: float,
for x in brush_target.size.x:
var coord := brush_target.position + Vector2i(x, y)
var pixel := _image.get_pixelv(coord)
var pixel := _editable_image.get_pixelv(coord)
_image.set_pixelv(coord, Color(pixel.r, pixel.g, pixel.b,
_editable_image.set_pixelv(coord, Color(pixel.r, pixel.g, pixel.b,
lerpf(pixel.a, level, intensity * delta *\
mask.get_pixel(int((offset.x + x) * mask_ratio.x), mask_y).a)).clamp())
if instance != null:
instance.terrain_map.update(_image)
_editable_texture.update(_editable_image)
##
##
##
func paint(point: Vector2i, color: Color,
mask: Image, scale: float, intensity: float, delta: float) -> void:
mask: Image, mask_scale: float, intensity: float, delta: float) -> void:
var mask_size := mask.get_size()
var brush_source := _get_brush_area(point, mask_size, scale)
var brush_source := _get_brush_area(point, mask_size, mask_scale)
if brush_source.has_area():
var brush_target := Rect2i(Vector2i.ZERO, size).intersection(brush_source)
var brush_target := Rect2i(Vector2i.ZERO, get_size()).intersection(brush_source)
if brush_target.has_area():
var mask_ratio := mask_size / brush_source.size
@ -105,18 +80,31 @@ func paint(point: Vector2i, color: Color,
for x in brush_target.size.x:
var coord := brush_target.position + Vector2i(x, y)
var pixel := _image.get_pixelv(coord)
var pixel := _editable_image.get_pixelv(coord)
var mask_intensity_delta := intensity * delta *\
mask.get_pixel(int((offset.x + x) * mask_ratio.x), mask_y).a
_image.set_pixelv(coord, Color(
_editable_image.set_pixelv(coord, Color(
lerpf(pixel.r, color.r, mask_intensity_delta),
lerpf(pixel.g, color.g, mask_intensity_delta),
lerpf(pixel.b, color.b, mask_intensity_delta), pixel.a).clamp())
if instance != null:
instance.terrain_map.update(_image)
_editable_texture.update(_editable_image)
##
##
##
func resize(size: Vector2i) -> void:
kayomn marked this conversation as resolved
Review

Missing doc comment.

Missing doc comment.
super.resize(size)
var actual_size := get_size()
_editable_image.resize(actual_size.x, actual_size.y)
_editable_texture = ImageTexture.create_from_image(_editable_image)
update_terrain(_editable_texture)
##
## Samples the color value in the editable terrain at the worldspace [code]point[/code], returning
@ -126,9 +114,10 @@ func paint(point: Vector2i, color: Color,
## instead.
##
func sample(point: Vector2i) -> Color:
var size := get_size()
var image_point := point + Vector2i(size * 0.5)
if Rect2i(Vector2i.ZERO, size).has_point(image_point):
return _image.get_pixelv(image_point)
return _editable_image.get_pixelv(image_point)
return BLANK

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://jcmf7j3qo6ea"
path="res://.godot/imported/arid_grass_albedo.png-cac7ceff15cf65e54d8ee36a70e05853.ctex"
path="res://.godot/imported/arid_grass_albedo.png-532bc188063dc524e2c08228bed13fa7.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/arid_grass_albedo.png"
dest_files=["res://.godot/imported/arid_grass_albedo.png-cac7ceff15cf65e54d8ee36a70e05853.ctex"]
source_file="res://terrain/paints/arid_grass_albedo.png"
dest_files=["res://.godot/imported/arid_grass_albedo.png-532bc188063dc524e2c08228bed13fa7.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://co0jompch208v"
path="res://.godot/imported/arid_grass_displacement.png-66c8c71a36e11168aed23cd0531ba7bd.ctex"
path="res://.godot/imported/arid_grass_displacement.png-cad938b62195c0b0f41099d596594b8b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/arid_grass_displacement.png"
dest_files=["res://.godot/imported/arid_grass_displacement.png-66c8c71a36e11168aed23cd0531ba7bd.ctex"]
source_file="res://terrain/paints/arid_grass_displacement.png"
dest_files=["res://.godot/imported/arid_grass_displacement.png-cad938b62195c0b0f41099d596594b8b.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bh141jkgbmya8"
path="res://.godot/imported/arid_grass_normal.png-6cfb96e0a0b1eac890998accab9c7109.ctex"
path="res://.godot/imported/arid_grass_normal.png-7bf9fdf5f927fea47a2f86a9ffab326e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/arid_grass_normal.png"
dest_files=["res://.godot/imported/arid_grass_normal.png-6cfb96e0a0b1eac890998accab9c7109.ctex"]
source_file="res://terrain/paints/arid_grass_normal.png"
dest_files=["res://.godot/imported/arid_grass_normal.png-7bf9fdf5f927fea47a2f86a9ffab326e.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://jdq8kwjo3uap"
path="res://.godot/imported/arid_grass_roughness.png-8ff0f34a3348350d0edc5e43b43bcd0e.ctex"
path="res://.godot/imported/arid_grass_roughness.png-40299cbb0e24b392d013d45af79f5444.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/arid_grass_roughness.png"
dest_files=["res://.godot/imported/arid_grass_roughness.png-8ff0f34a3348350d0edc5e43b43bcd0e.ctex"]
source_file="res://terrain/paints/arid_grass_roughness.png"
dest_files=["res://.godot/imported/arid_grass_roughness.png-40299cbb0e24b392d013d45af79f5444.ctex"]
[params]

BIN
terrain/paints/arid_grass_terrain_paint.res (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://cs06oiwrord6t"
path="res://.godot/imported/cobbled_limestone_albedo.png-cbafb40d3c6fc43ce00d68cb02456536.ctex"
path="res://.godot/imported/cobblestone_albedo.png-f0ce6b9d25b0c6c4130e70ff660bcbd6.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/cobbled_limestone_albedo.png"
dest_files=["res://.godot/imported/cobbled_limestone_albedo.png-cbafb40d3c6fc43ce00d68cb02456536.ctex"]
source_file="res://terrain/paints/cobblestone_albedo.png"
dest_files=["res://.godot/imported/cobblestone_albedo.png-f0ce6b9d25b0c6c4130e70ff660bcbd6.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://mkxbjfwdwkaq"
path="res://.godot/imported/cobbled_limestone_displacement.png-8e8b27438ff815a9d58d4a490e04203c.ctex"
path="res://.godot/imported/cobblestone_displacement.png-bcf2e2194862b85cb002d9559d57903b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/cobbled_limestone_displacement.png"
dest_files=["res://.godot/imported/cobbled_limestone_displacement.png-8e8b27438ff815a9d58d4a490e04203c.ctex"]
source_file="res://terrain/paints/cobblestone_displacement.png"
dest_files=["res://.godot/imported/cobblestone_displacement.png-bcf2e2194862b85cb002d9559d57903b.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://ukk0161x3eg2"
path="res://.godot/imported/cobbled_limestone_normal.png-4d7b2eb9c070e06256eb42d408ff4a14.ctex"
path="res://.godot/imported/cobblestone_normal.png-5130e667fa81f7452d15808908f4cb99.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/cobbled_limestone_normal.png"
dest_files=["res://.godot/imported/cobbled_limestone_normal.png-4d7b2eb9c070e06256eb42d408ff4a14.ctex"]
source_file="res://terrain/paints/cobblestone_normal.png"
dest_files=["res://.godot/imported/cobblestone_normal.png-5130e667fa81f7452d15808908f4cb99.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bcybapft8tl2x"
path="res://.godot/imported/cobbled_limestone_roughness.png-f78cac7004d15ddc2a00fd10f74b8c10.ctex"
path="res://.godot/imported/cobblestone_roughness.png-2f09da1d7000b898b80d7b177062e509.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/cobbled_limestone_roughness.png"
dest_files=["res://.godot/imported/cobbled_limestone_roughness.png-f78cac7004d15ddc2a00fd10f74b8c10.ctex"]
source_file="res://terrain/paints/cobblestone_roughness.png"
dest_files=["res://.godot/imported/cobblestone_roughness.png-2f09da1d7000b898b80d7b177062e509.ctex"]
[params]

BIN
terrain/paints/cobblestone_terrain_paint.res (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -3,8 +3,8 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bgpk15qrqxly8"
path.s3tc="res://.godot/imported/default_albedo.png-92a6d62c2ead547c4c35766bdeaf9065.s3tc.ctex"
path.etc2="res://.godot/imported/default_albedo.png-92a6d62c2ead547c4c35766bdeaf9065.etc2.ctex"
path.s3tc="res://.godot/imported/default_albedo.png-ec7b9bee606a4c8482c5f21d50eaafb2.s3tc.ctex"
path.etc2="res://.godot/imported/default_albedo.png-ec7b9bee606a4c8482c5f21d50eaafb2.etc2.ctex"
metadata={
"imported_formats": ["s3tc", "etc2"],
"vram_texture": true
@ -12,8 +12,8 @@ metadata={
[deps]
source_file="res://terrain/default_albedo.png"
dest_files=["res://.godot/imported/default_albedo.png-92a6d62c2ead547c4c35766bdeaf9065.s3tc.ctex", "res://.godot/imported/default_albedo.png-92a6d62c2ead547c4c35766bdeaf9065.etc2.ctex"]
source_file="res://terrain/paints/default_albedo.png"
dest_files=["res://.godot/imported/default_albedo.png-ec7b9bee606a4c8482c5f21d50eaafb2.s3tc.ctex", "res://.godot/imported/default_albedo.png-ec7b9bee606a4c8482c5f21d50eaafb2.etc2.ctex"]
[params]

BIN
terrain/paints/default_terrain_paint.res (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://b8cv4q43fsglu"
path="res://.godot/imported/desert_sand_albedo.png-5307ce3455129127b5c6f3a135f5cbc7.ctex"
path="res://.godot/imported/desert_sand_albedo.png-1f8394c37b6df0b83ddc4964049fe1fb.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/desert_sand_albedo.png"
dest_files=["res://.godot/imported/desert_sand_albedo.png-5307ce3455129127b5c6f3a135f5cbc7.ctex"]
source_file="res://terrain/paints/desert_sand_albedo.png"
dest_files=["res://.godot/imported/desert_sand_albedo.png-1f8394c37b6df0b83ddc4964049fe1fb.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bdacir1igfinb"
path="res://.godot/imported/desert_sand_displacement.png-3674eb6c274d21b1ddd14b8c6ce982fe.ctex"
path="res://.godot/imported/desert_sand_displacement.png-de6822961a581feed0d45f5f34fbb048.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/desert_sand_displacement.png"
dest_files=["res://.godot/imported/desert_sand_displacement.png-3674eb6c274d21b1ddd14b8c6ce982fe.ctex"]
source_file="res://terrain/paints/desert_sand_displacement.png"
dest_files=["res://.godot/imported/desert_sand_displacement.png-de6822961a581feed0d45f5f34fbb048.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://c40cc5b5sq4yu"
path="res://.godot/imported/desert_sand_normal.png-9b37ed7fc3712ce013db97500f604934.ctex"
path="res://.godot/imported/desert_sand_normal.png-4882d77c1942a502a8d07cd8761a392c.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/desert_sand_normal.png"
dest_files=["res://.godot/imported/desert_sand_normal.png-9b37ed7fc3712ce013db97500f604934.ctex"]
source_file="res://terrain/paints/desert_sand_normal.png"
dest_files=["res://.godot/imported/desert_sand_normal.png-4882d77c1942a502a8d07cd8761a392c.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bwkcsnjetn5wr"
path="res://.godot/imported/desert_sand_roughness.png-c85e29a6965b06eac0c712e74b047821.ctex"
path="res://.godot/imported/desert_sand_roughness.png-0c32daf878e9b29d36631441877f21ac.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/desert_sand_roughness.png"
dest_files=["res://.godot/imported/desert_sand_roughness.png-c85e29a6965b06eac0c712e74b047821.ctex"]
source_file="res://terrain/paints/desert_sand_roughness.png"
dest_files=["res://.godot/imported/desert_sand_roughness.png-0c32daf878e9b29d36631441877f21ac.ctex"]
[params]

BIN
terrain/paints/desert_sand_terrain_paint.res (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://eqbk8dx3px02"
path="res://.godot/imported/dry_mud_albedo.png-0fe12d446fc4e93e2a42ccc9303ac693.ctex"
path="res://.godot/imported/dry_mud_albedo.png-6844f23cea910070ff2cf0d2e02e4e06.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/dry_mud_albedo.png"
dest_files=["res://.godot/imported/dry_mud_albedo.png-0fe12d446fc4e93e2a42ccc9303ac693.ctex"]
source_file="res://terrain/paints/dry_mud_albedo.png"
dest_files=["res://.godot/imported/dry_mud_albedo.png-6844f23cea910070ff2cf0d2e02e4e06.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bwqtubithbfsy"
path="res://.godot/imported/dry_mud_displacement.png-459305492d2f8cba90344ad67808cc02.ctex"
path="res://.godot/imported/dry_mud_displacement.png-84ac0ae4e00848577ccfe89d2c4787e8.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/dry_mud_displacement.png"
dest_files=["res://.godot/imported/dry_mud_displacement.png-459305492d2f8cba90344ad67808cc02.ctex"]
source_file="res://terrain/paints/dry_mud_displacement.png"
dest_files=["res://.godot/imported/dry_mud_displacement.png-84ac0ae4e00848577ccfe89d2c4787e8.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://c86r5niid1hp1"
path="res://.godot/imported/dry_mud_normal.png-bbedc7a55f837a837bfdab39fcbc7272.ctex"
path="res://.godot/imported/dry_mud_normal.png-6211d1992b291d2e0174ec9de201218d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/dry_mud_normal.png"
dest_files=["res://.godot/imported/dry_mud_normal.png-bbedc7a55f837a837bfdab39fcbc7272.ctex"]
source_file="res://terrain/paints/dry_mud_normal.png"
dest_files=["res://.godot/imported/dry_mud_normal.png-6211d1992b291d2e0174ec9de201218d.ctex"]
[params]

View File

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://7xnkstxa6q65"
path="res://.godot/imported/dry_mud_roughness.png-0d5a4572411f8d454ef69ed8b252672b.ctex"
path="res://.godot/imported/dry_mud_roughness.png-35dfe15111e09484a06efd2f6e55b73b.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://terrain/dry_mud_roughness.png"
dest_files=["res://.godot/imported/dry_mud_roughness.png-0d5a4572411f8d454ef69ed8b252672b.ctex"]
source_file="res://terrain/paints/dry_mud_roughness.png"
dest_files=["res://.godot/imported/dry_mud_roughness.png-35dfe15111e09484a06efd2f6e55b73b.ctex"]
[params]

BIN
terrain/paints/dry_mud_terrain_paint.res (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,13 @@
class_name TerrainPaint extends Resource
##
##
##
@export
var albedo_map: Texture2D = null
kayomn marked this conversation as resolved
Review

Missing doc comment.

Missing doc comment.
##
##
##
@export
var normal_map: Texture2D = null
kayomn marked this conversation as resolved
Review

Missing doc comment.

Missing doc comment.

57
terrain/terrain.gdshader Normal file
View File

@ -0,0 +1,57 @@
shader_type spatial;
const int MAP_COUNT = 4;
uniform sampler2D[MAP_COUNT] ALBEDO_MAPS;
uniform float MAX_HEIGHT = 100.0;
uniform sampler2D[MAP_COUNT] NORMAL_MAPS;
uniform vec2 SIZE;
uniform sampler2D TERRAIN_MAP : hint_default_transparent, repeat_disable;
void fragment() {
vec2 uv = UV * (SIZE / 2.0);
vec2 uv_alt = uv * -0.5;
vec3 splat_map = texture(TERRAIN_MAP, UV).rgb;
float blank = clamp(1.0 - splat_map.r - splat_map.g - splat_map.b, 0.0, 1.0);
ALBEDO = blank * 0.5 * (texture(ALBEDO_MAPS[0], uv).rgb + texture(ALBEDO_MAPS[0], uv_alt).rgb);
for (int i = 0; i < (MAP_COUNT - 1); i += 1) {
int map_index = i + 1;
ALBEDO += splat_map[i] * 0.5 * (texture(ALBEDO_MAPS[map_index], uv).rgb +
texture(ALBEDO_MAPS[map_index], uv_alt).rgb);
}
NORMAL_MAP = blank * 0.5 *
(texture(NORMAL_MAPS[0], uv).rgb + texture(NORMAL_MAPS[0], uv_alt).rgb);
for (int i = 0; i < (MAP_COUNT - 1); i += 1) {
int map_index = i + 1;
NORMAL_MAP += splat_map[i] * 0.5 * (texture(NORMAL_MAPS[map_index], uv).rgb +
texture(NORMAL_MAPS[map_index], uv_alt).rgb);
}
}
float height(vec2 uv) {
return MAX_HEIGHT * texture(TERRAIN_MAP, uv).a;
}
void vertex() {
VERTEX.y = height(UV);
vec2 texel_size = UV / SIZE;
vec4 h = vec4(
height(UV + (texel_size * vec2(0, -1))),
height(UV + (texel_size * vec2(-1, 0))),
height(UV + (texel_size * vec2( 1, 0))),
height(UV + (texel_size * vec2( 0, 1))));
NORMAL = normalize(vec3(h.y - h.z, 2.0, h.x - h.w));
}

View File

@ -1,169 +1,87 @@
@tool
class_name TerrainInstance3D extends GeometryInstance3D
##
## Identifier constant for a paint slot channel.
##
enum PaintSlot {
ERASE,
RED,
GREEN,
BLUE,
}
const _DETAIL := 2
var _mesh := PlaneMesh.new()
var _albedo_map_textures: Array[Texture2D] = [null, null, null, null]
var _material := ShaderMaterial.new()
var _normal_map_textures: Array[Texture2D] = [null, null, null, null]
var _mesh := PlaneMesh.new()
##
##
## The height scale range that is used to determine the minimums and maximums of the terrain map.
##
@export
var size: Vector2i = Vector2i.ZERO:
var height_scale := 100.0:
get:
return size
return height_scale
set(value):
var width := maxi(value.x, 0)
var height := maxi(value.y, 0)
_material.set_shader_parameter("MAX_HEIGHT", value)
if (width != size.x) or (height != size.y):
if (width == 0) and (height == 0):
RenderingServer.instance_set_base(self.get_instance(), RID())
height_scale = max(value, 0.0)
else:
self._mesh.subdivide_width = width * _DETAIL
self._mesh.subdivide_depth = height * _DETAIL
self._mesh.size = value
self._material.set_shader_parameter("SIZE", Vector2(value))
RenderingServer.instance_set_base(self.get_instance(), self._mesh)
size = value
##
##
##
@export
var albedo_map: Texture2D = null:
get:
return albedo_map
set(value):
self._material.set_shader_parameter("ALBEDO_MAP_0", value)
albedo_map = value
##
##
##
@export
var albedo_map_b: Texture2D = null:
get:
return albedo_map_b
set(value):
self._material.set_shader_parameter("ALBEDO_MAP_B", value)
albedo_map_b = value
##
##
##
@export
var albedo_map_g: Texture2D = null:
get:
return albedo_map_g
set(value):
self._material.set_shader_parameter("ALBEDO_MAP_G", value)
albedo_map_g = value
##
##
##
@export
var albedo_map_r: Texture2D = null:
get:
return albedo_map_r
set(value):
self._material.set_shader_parameter("ALBEDO_MAP_R", value)
albedo_map_r = value
##
##
##
@export
var normal_map: Texture2D = null:
get:
return normal_map
set(value):
self._material.set_shader_parameter("NORMAL_MAP_0", value)
normal_map = value
##
##
##
@export
var normal_map_b: Texture2D = null:
get:
return normal_map_b
set(value):
self._material.set_shader_parameter("NORMAL_MAP_B", value)
normal_map_b = value
##
##
##
@export
var normal_map_g: Texture2D = null:
get:
return normal_map_g
set(value):
self._material.set_shader_parameter("NORMAL_MAP_G", value)
normal_map_g = value
##
##
##
@export
var normal_map_r: Texture2D = null:
get:
return normal_map_r
set(value):
self._material.set_shader_parameter("NORMAL_MAP_R", value)
normal_map_r = value
##
##
##
@export
var terrain_map: Texture2D = null:
get:
return terrain_map
set(value):
self._material.set_shader_parameter("TERRAIN_MAP", value)
terrain_map = value
##
##
##
@export
var max_height := 100.0:
get:
return max_height
set(value):
self._material.set_shader_parameter("MAX_HEIGHT", value)
max_height = max(value, 0.0)
var _size := Vector2i.ZERO
func _init() -> void:
self._material.shader = preload("res://terrain/terrain_shader.gdshader")
_material.shader = preload("res://terrain/terrain.gdshader")
self._mesh.surface_set_material(0, self._material)
RenderingServer.instance_set_base(get_instance(), _mesh)
_mesh.surface_set_material(0, _material)
##
## Returns the size of the terrain mesh (as in-engine units).
##
func get_size() -> Vector2i:
return _size
##
## Attempts to resize the terrain to be equal to [code]size[/code] (in-engine units), with
## [code]Vector2i.ONE[/code] as the minimum size.
##
func resize(size: Vector2i) -> void:
var width := maxi(size.x, 1)
var height := maxi(size.y, 1)
if (width != _size.x) or (height != _size.y):
_mesh.subdivide_width = width * _DETAIL
_mesh.subdivide_depth = height * _DETAIL
_mesh.size = size
_material.set_shader_parameter("SIZE", Vector2(size))
_size = size
##
## Updates the paint used by the paint channel identified by [code]paint_slot[/code] to
## [code]terrain_paint[/code].
##
func update_paint(paint_slot: PaintSlot, paint: TerrainPaint) -> void:
if paint == null:
_albedo_map_textures[paint_slot] = null
_normal_map_textures[paint_slot] = null
else:
_albedo_map_textures[paint_slot] = paint.albedo_map
_normal_map_textures[paint_slot] = paint.normal_map
_material.set_shader_parameter("ALBEDO_MAPS", _albedo_map_textures)
_material.set_shader_parameter("NORMAL_MAPS", _normal_map_textures)
##
## Updates the terrain map to [code]terrain_map[/code].
##
func update_terrain(terrain_map: Texture2D) -> void:
_material.set_shader_parameter("TERRAIN_MAP", terrain_map)

View File

@ -1,58 +0,0 @@
shader_type spatial;
uniform sampler2D ALBEDO_MAP_0 : hint_default_black;
uniform sampler2D ALBEDO_MAP_R : hint_default_black;
uniform sampler2D ALBEDO_MAP_G : hint_default_black;
uniform sampler2D ALBEDO_MAP_B : hint_default_black;
uniform float MAX_HEIGHT = 100.0;
uniform sampler2D NORMAL_MAP_0 : hint_default_black;
uniform sampler2D NORMAL_MAP_R : hint_default_black;
uniform sampler2D NORMAL_MAP_G : hint_default_black;
uniform sampler2D NORMAL_MAP_B : hint_default_black;
uniform vec2 SIZE;
uniform sampler2D TERRAIN_MAP : hint_default_transparent, repeat_disable;
void fragment() {
vec2 uv = UV * (SIZE / 2.0);
vec2 uv_alt = uv * -0.5;
vec3 splat_map = texture(TERRAIN_MAP, UV).rgb;
float blank = clamp(1.0 - splat_map.r - splat_map.g - splat_map.b, 0.0, 1.0);
ALBEDO = blank * 0.5 * (texture(ALBEDO_MAP_0, uv).rgb + texture(ALBEDO_MAP_0, uv_alt).rgb);
ALBEDO += splat_map.r * 0.5 * (texture(ALBEDO_MAP_R, uv).rgb + texture(ALBEDO_MAP_R, uv_alt).rgb);
ALBEDO += splat_map.g * 0.5 * (texture(ALBEDO_MAP_G, uv).rgb + texture(ALBEDO_MAP_G, uv_alt).rgb);
ALBEDO += splat_map.b * 0.5 * (texture(ALBEDO_MAP_B, uv).rgb + texture(ALBEDO_MAP_B, uv_alt).rgb);
NORMAL_MAP = blank * 0.5 * (texture(NORMAL_MAP_0, uv).rgb + texture(NORMAL_MAP_0, uv_alt).rgb);
NORMAL_MAP += splat_map.r * 0.5 * (texture(NORMAL_MAP_R, uv).rgb + texture(NORMAL_MAP_R, uv_alt).rgb);
NORMAL_MAP += splat_map.g * 0.5 * (texture(NORMAL_MAP_G, uv).rgb + texture(NORMAL_MAP_G, uv_alt).rgb);
NORMAL_MAP += splat_map.b * 0.5 * (texture(NORMAL_MAP_B, uv).rgb + texture(NORMAL_MAP_B, uv_alt).rgb);
}
float height(vec2 uv) {
return MAX_HEIGHT * texture(TERRAIN_MAP, uv).a;
}
void vertex() {
VERTEX.y = height(UV);
vec2 texel_size = UV / SIZE;
vec4 h = vec4(
height(UV + (texel_size * vec2(0, -1))),
height(UV + (texel_size * vec2(-1, 0))),
height(UV + (texel_size * vec2( 1, 0))),
height(UV + (texel_size * vec2( 0, 1))));
NORMAL = normalize(vec3(h.y - h.z, 2.0, h.x - h.w));
}

BIN
user_interface/screen_cursor.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://crt8tmxbpu1hl"
path="res://.godot/imported/screen_cursor.png-46ebd33cd7dfb4c0211a698e6d39e483.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://user_interface/screen_cursor.png"
dest_files=["res://.godot/imported/screen_cursor.png-46ebd33cd7dfb4c0211a698e6d39e483.ctex"]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/bptc_ldr=0
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1