From 866fd1139983c5b968fa2c1db376b7690c15a056 Mon Sep 17 00:00:00 2001 From: Martin Felis Date: Sun, 21 May 2023 17:24:37 +0200 Subject: [PATCH] Heightmap and Colormap generation kind of works now. --- materials/IslandColorRampShader.tres | 57 +------ materials/IslandHeightmapFalloffShader.tres | 6 + materials/shader/HexToTexture.gdshader | 2 +- .../shader/IslandColorRampShader.gdshader | 52 +++++++ .../IslandHeightmapFalloffShader.gdshader | 52 +++++++ project.godot | 8 +- scenes/Game.cs | 21 ++- scenes/TileWorld.cs | 144 ++++++++++-------- scenes/TileWorld.tscn | 25 ++- 9 files changed, 236 insertions(+), 131 deletions(-) create mode 100644 materials/IslandHeightmapFalloffShader.tres create mode 100644 materials/shader/IslandColorRampShader.gdshader create mode 100644 materials/shader/IslandHeightmapFalloffShader.gdshader diff --git a/materials/IslandColorRampShader.tres b/materials/IslandColorRampShader.tres index 0a6e142..adcdfdd 100644 --- a/materials/IslandColorRampShader.tres +++ b/materials/IslandColorRampShader.tres @@ -1,59 +1,6 @@ [gd_resource type="ShaderMaterial" load_steps=2 format=2] -[sub_resource type="Shader" id=1] -code = "shader_type canvas_item; -render_mode skip_vertex_transform; - -void vertex() { - VERTEX = (WORLD_MATRIX * (EXTRA_MATRIX * vec4(VERTEX, 0.0, 1.0))).xy; -} - -vec3 color_ramp(float h) { - if (h < 0.4f) { - return vec3(0, 0, 0.6); - } else if (h < 0.45f) { - return vec3(0, 0, 0.7); - } else if (h < 0.5f) { - return vec3(0, 0, 1); - } else if (h < 0.55){ - return vec3(0.8, 0.8, 0.1); - } else if (h < 0.6){ - return vec3(0, 0.6, 0); - } else if (h < 0.68){ - return vec3(0, 0.4, 0); - } else if (h <= 0.78){ - return vec3(0.6, 0.6, 0.6); - } else if (h < 1.0){ - return vec3(0.8, 0.8, 0.8); - } - - return vec3(1.0); -} - -vec3 rgbToGrayscale(vec3 color) { - return vec3(dot(color.rgb, vec3(0.299, 0.587, 0.144))); -} - -float borderFalloff(vec2 uv) { - return min( - (0.5 - abs(-uv.x + 0.5)) * 2.0, - (0.5 - abs(-uv.y + 0.5)) * 2.0); -} - -float borderFalloffCircle(vec2 uv) { - return (0.5 - length(vec2(uv - vec2(0.5, 0.5)))) * 2.0; -} - -void fragment() { - vec4 texture_color = texture(TEXTURE, UV); - - - COLOR.rgb = vec3(abs(UV.x - 0.5) * 2.0); - //COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8); - COLOR.rgb = color_ramp(texture_color.r * borderFalloff(UV) * 1.8); -} - -" +[ext_resource path="res://materials/shader/IslandColorRampShader.gdshader" type="Shader" id=1] [resource] -shader = SubResource( 1 ) +shader = ExtResource( 1 ) diff --git a/materials/IslandHeightmapFalloffShader.tres b/materials/IslandHeightmapFalloffShader.tres new file mode 100644 index 0000000..03cd8ab --- /dev/null +++ b/materials/IslandHeightmapFalloffShader.tres @@ -0,0 +1,6 @@ +[gd_resource type="ShaderMaterial" load_steps=2 format=2] + +[ext_resource path="res://materials/shader/IslandHeightmapFalloffShader.gdshader" type="Shader" id=1] + +[resource] +shader = ExtResource( 1 ) diff --git a/materials/shader/HexToTexture.gdshader b/materials/shader/HexToTexture.gdshader index e78ae48..a6d2f19 100644 --- a/materials/shader/HexToTexture.gdshader +++ b/materials/shader/HexToTexture.gdshader @@ -47,7 +47,7 @@ void vertex() { } void fragment() { - ALBEDO = texture(MapAlbedoTexture, map_coord).rgb; + ALBEDO = pow(texture(MapAlbedoTexture, map_coord).rgb, vec3(2.4)); } void light() { diff --git a/materials/shader/IslandColorRampShader.gdshader b/materials/shader/IslandColorRampShader.gdshader new file mode 100644 index 0000000..002ac4f --- /dev/null +++ b/materials/shader/IslandColorRampShader.gdshader @@ -0,0 +1,52 @@ +shader_type canvas_item; +render_mode skip_vertex_transform; + +void vertex() { + VERTEX = (WORLD_MATRIX * (EXTRA_MATRIX * vec4(VERTEX, 0.0, 1.0))).xy; +} + +vec3 color_ramp(float h) { + if (h < 0.4f) { + return vec3(0, 0, 0.6); + } else if (h < 0.45f) { + return vec3(0, 0, 0.7); + } else if (h < 0.5f) { + return vec3(0, 0, 1); + } else if (h < 0.55){ + return vec3(0.8, 0.8, 0.1); + } else if (h < 0.6){ + return vec3(0, 0.6, 0); + } else if (h < 0.68){ + return vec3(0, 0.4, 0); + } else if (h <= 0.78){ + return vec3(0.6, 0.6, 0.6); + } else if (h < 1.0){ + return vec3(0.8, 0.8, 0.8); + } + + return vec3(1.0); +} + +vec3 rgbToGrayscale(vec3 color) { + return vec3(dot(color.rgb, vec3(0.299, 0.587, 0.144))); +} + +float borderFalloff(vec2 uv) { + return min( + (0.5 - abs(-uv.x + 0.5)) * 2.0, + (0.5 - abs(-uv.y + 0.5)) * 2.0); +} + +float borderFalloffCircle(vec2 uv) { + return (0.5 - length(vec2(uv - vec2(0.5, 0.5)))) * 2.0; +} + +void fragment() { + vec4 texture_color = texture(TEXTURE, UV); + + + COLOR.rgb = vec3(abs(UV.x - 0.5) * 2.0); + //COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8); + COLOR.rgb = color_ramp(texture_color.r); +} + diff --git a/materials/shader/IslandHeightmapFalloffShader.gdshader b/materials/shader/IslandHeightmapFalloffShader.gdshader new file mode 100644 index 0000000..edf272d --- /dev/null +++ b/materials/shader/IslandHeightmapFalloffShader.gdshader @@ -0,0 +1,52 @@ +shader_type canvas_item; +render_mode skip_vertex_transform; + +void vertex() { + VERTEX = (WORLD_MATRIX * (EXTRA_MATRIX * vec4(VERTEX, 0.0, 1.0))).xy; +} + +vec3 color_ramp(float h) { + if (h < 0.4f) { + return vec3(0, 0, 0.6); + } else if (h < 0.45f) { + return vec3(0, 0, 0.7); + } else if (h < 0.5f) { + return vec3(0, 0, 1); + } else if (h < 0.55){ + return vec3(0.8, 0.8, 0.1); + } else if (h < 0.6){ + return vec3(0, 0.6, 0); + } else if (h < 0.68){ + return vec3(0, 0.4, 0); + } else if (h <= 0.78){ + return vec3(0.6, 0.6, 0.6); + } else if (h < 1.0){ + return vec3(0.8, 0.8, 0.8); + } + + return vec3(1.0); +} + +vec3 rgbToGrayscale(vec3 color) { + return vec3(dot(color.rgb, vec3(0.299, 0.587, 0.144))); +} + +float borderFalloff(vec2 uv) { + return min( + (0.5 - abs(-uv.x + 0.5)) * 2.0, + (0.5 - abs(-uv.y + 0.5)) * 2.0); +} + +float borderFalloffCircle(vec2 uv) { + return (0.5 - length(vec2(uv - vec2(0.5, 0.5)))) * 2.0; +} + +void fragment() { + vec4 texture_color = texture(TEXTURE, UV); + + + COLOR.rgb = vec3(abs(UV.x - 0.5) * 2.0); + //COLOR.rgb = color_ramp(texture_color.r * borderFalloffCircle(UV) * 1.8); + COLOR.rgb = vec3(texture_color.r * borderFalloff(UV) * 1.8); +} + diff --git a/project.godot b/project.godot index bd0be60..afb22bb 100644 --- a/project.godot +++ b/project.godot @@ -9,17 +9,17 @@ config_version=4 _global_script_classes=[ { -"base": "Node", +"base": "Reference", "class": "ClickableComponent", "language": "GDScript", "path": "res://components/ClickableComponent.gd" }, { -"base": "KinematicBody2D", +"base": "Reference", "class": "CollisionLine", "language": "GDScript", "path": "res://utils/CollisionLine.gd" }, { -"base": "Node", +"base": "Reference", "class": "ColorComponent", "language": "GDScript", "path": "res://components/ColorComponent.gd" @@ -54,7 +54,7 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://utils/SpringDamper.gd" }, { -"base": "Sprite", +"base": "Reference", "class": "TintedSpriteComponent", "language": "GDScript", "path": "res://components/TintedSpriteComponent.gd" diff --git a/scenes/Game.cs b/scenes/Game.cs index d4ccd1f..a823013 100644 --- a/scenes/Game.cs +++ b/scenes/Game.cs @@ -244,26 +244,33 @@ public class Game : Spatial } + public void ResetGameState() + { + Transform playerStartTransform = Transform.Identity; + float height = _tileWorld.GetHeightAtOffset(new Vector2(0, 0)); + playerStartTransform.origin.y = height; + _player.Transform = playerStartTransform; + _player.TaskQueueComponent.Reset(); + _player.Navigation.PlanDirectPath(playerStartTransform.origin, playerStartTransform.origin, playerStartTransform.basis.Quat()); + } + public void OnWorldGenerated() { GD.Print("Using new map"); + ImageTexture newWorldTexture = new ImageTexture(); newWorldTexture.CreateFromImage(_tileWorld.Colormap, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat)); - ImageTexture newHeightTexture = new ImageTexture(); - newHeightTexture.CreateFromImage(_tileWorld.Heightmap, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat)); - _worldTextureRect.Texture = newWorldTexture; _tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture); _tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.Colormap.GetSize().x); + ImageTexture newHeightTexture = new ImageTexture(); + newHeightTexture.CreateFromImage(_tileWorld.Heightmap, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat)); _heightTextureRect.Texture = newHeightTexture; _streamContainer.OnWorldGenerated(); // Reset player transform to offset 0,0 and at current height - Transform playerStartTransform = Transform.Identity; - float height = _tileWorld.GetHeightAtOffset(new Vector2(0, 0)); - playerStartTransform.origin.y = height; - _player.Transform = playerStartTransform; + ResetGameState(); } } \ No newline at end of file diff --git a/scenes/TileWorld.cs b/scenes/TileWorld.cs index 5ef453a..7a1a6d9 100644 --- a/scenes/TileWorld.cs +++ b/scenes/TileWorld.cs @@ -9,12 +9,21 @@ using Vector3 = Godot.Vector3; public class TileWorld : Spatial { + private enum GenerationState + { + Heightmap, + Color, + Done + } + + private GenerationState CurrentGenerationState = GenerationState.Heightmap; + // signals [Signal] delegate void WorldGenerated(); // public members - public float Size = 5; + public float Size = 100; public float HeightScale = 10.0f; public Image Heightmap; public Image Colormap; @@ -23,39 +32,42 @@ public class TileWorld : Spatial // private members private HexGrid _hexGrid; private Random _tileTypeRandom; - private Viewport _offscreenViewport; - private TextureRect _offscreenTextureRect; + private Viewport _worldOffscreenViewport; + private TextureRect _worldOffscreenTextureRect; + private Viewport _heightmapOffscreenViewport; + private TextureRect _heightmapOffscreenTextureRect; + // Called when the node enters the scene tree for the first time. public override void _Ready() { _hexGrid = new HexGrid(); _tileTypeRandom = new Random(); - - _offscreenViewport = (Viewport)GetNode("OffscreenViewport"); - Debug.Assert(_offscreenViewport != null); - _offscreenViewport.Size = new Vector2(Size, Size); - _offscreenTextureRect = (TextureRect)GetNode("OffscreenViewport/TextureRect"); - Debug.Assert(_offscreenTextureRect != null); - _offscreenTextureRect.SetSize(new Vector2(Size, Size)); - //VisualServer.Singleton.Connect("frame_post_draw", this, nameof(GenerateNoiseColorMap)); + _worldOffscreenViewport = (Viewport)GetNode("WorldOffscreenViewport"); + Debug.Assert(_worldOffscreenViewport != null); + _worldOffscreenViewport.Size = new Vector2(Size, Size); + _worldOffscreenTextureRect = (TextureRect)GetNode("WorldOffscreenViewport/TextureRect"); + Debug.Assert(_worldOffscreenTextureRect != null); + _worldOffscreenTextureRect.SetSize(new Vector2(Size, Size)); + + _heightmapOffscreenViewport = (Viewport)GetNode("HeightmapOffscreenViewport"); + Debug.Assert(_heightmapOffscreenViewport != null); + _heightmapOffscreenViewport.Size = new Vector2(Size, Size); + _heightmapOffscreenTextureRect = (TextureRect)GetNode("HeightmapOffscreenViewport/TextureRect"); + Debug.Assert(_heightmapOffscreenTextureRect != null); + _heightmapOffscreenTextureRect.SetSize(new Vector2(Size, Size)); + + Generate(); } public void Generate() { - //GenerateSimpleMap(); - //GenerateNoiseMap(); - - - GenerateNoiseColorMap(); + GenerateNoiseMap(); //GenerateDebugMap(); - - EmitSignal("WorldGenerated"); } - private void GenerateDebugMap() { Colormap = new Image(); @@ -63,7 +75,7 @@ public class TileWorld : Spatial Heightmap = new Image(); Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf); - + Heightmap.Lock(); Colormap.Lock(); foreach (int coord_x in Enumerable.Range(0, (int)Size)) @@ -78,16 +90,17 @@ public class TileWorld : Spatial { coord_to_height = 1; } + SetHeightAtOffset(new Vector2(coord_x, coord_y), coord_to_height); } } - + Colormap.Unlock(); - + ImageTexture imageTexture = new ImageTexture(); imageTexture.CreateFromImage(Heightmap); imageTexture.Flags = 0; - _offscreenTextureRect.Texture = imageTexture; + _worldOffscreenTextureRect.Texture = imageTexture; Colormap.CopyFrom(imageTexture.GetData()); } @@ -97,40 +110,21 @@ public class TileWorld : Spatial Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf); Heightmap.Lock(); - foreach (int coord_x in Enumerable.Range(-(int) Size / 2, (int)Size)) + foreach (int coord_x in Enumerable.Range(-(int)Size / 2, (int)Size)) { - foreach (int coord_y in Enumerable.Range(-(int) Size / 2, (int)Size)) + foreach (int coord_y in Enumerable.Range(-(int)Size / 2, (int)Size)) { SetHeightAtOffset(new Vector2(coord_x, coord_y), 5f); } } } - + private void GenerateNoiseMap() { Heightmap = new Image(); - Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf); - - NoiseTexture noiseTexture = new NoiseTexture(); - OpenSimplexNoise noiseGenerator = new OpenSimplexNoise(); + Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rgba8); - noiseGenerator.Seed = Seed; - noiseGenerator.Octaves = 4; - noiseGenerator.Period = 20; - noiseGenerator.Persistence = 0.1f; - noiseGenerator.Lacunarity = 2; - - Heightmap.CopyFrom(noiseGenerator.GetImage((int)Size, (int)Size, null)); - } - - - private void GenerateNoiseColorMap() - { - Colormap = new Image(); - Colormap.Create((int)Size, (int)Size, false, Image.Format.Rgba8); - - NoiseTexture noiseTexture = new NoiseTexture(); OpenSimplexNoise noiseGenerator = new OpenSimplexNoise(); noiseGenerator.Seed = Seed; @@ -139,30 +133,55 @@ public class TileWorld : Spatial noiseGenerator.Persistence = 0.2f; noiseGenerator.Lacunarity = 4; - ImageTexture imageTexture = new ImageTexture(); - Heightmap = noiseGenerator.GetSeamlessImage((int)Size); - imageTexture.CreateFromImage(Heightmap); - imageTexture.Flags = 0; - _offscreenTextureRect.Texture = imageTexture; - Colormap.CopyFrom(_offscreenViewport.GetTexture().GetData()); - Heightmap.Lock(); + ImageTexture heightmapTexture = new ImageTexture(); + // heightmapTexture.CreateFromImage(noiseGenerator.GetImage((int)Size, (int)Size)); + heightmapTexture.CreateFromImage(noiseGenerator.GetSeamlessImage((int) Size)); + heightmapTexture.Flags = 0; + _heightmapOffscreenTextureRect.Texture = heightmapTexture; + Heightmap.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData()); + + CurrentGenerationState = GenerationState.Heightmap; } + public override void _Process(float delta) + { + if (CurrentGenerationState == GenerationState.Heightmap) + { + CurrentGenerationState = GenerationState.Color; + ImageTexture imageTexture = new ImageTexture(); + imageTexture.CreateFromImage(Heightmap); + imageTexture.Flags = 0; + _worldOffscreenTextureRect.Texture = imageTexture; + } + else if (CurrentGenerationState == GenerationState.Color) + { + Colormap = new Image(); + Colormap.Create((int)Size, (int)Size, false, Image.Format.Rgba8); + + Colormap.CopyFrom(_worldOffscreenViewport.GetTexture().GetData()); + Heightmap.Lock(); + + CurrentGenerationState = GenerationState.Done; + + EmitSignal("WorldGenerated"); + } + } + public void ApplyHeightmap(Image heightmap) { - foreach (int coord_x in Enumerable.Range(-(int) Size / 2, (int)Size)) + foreach (int coord_x in Enumerable.Range(-(int)Size / 2, (int)Size)) { - foreach (int coord_y in Enumerable.Range(-(int) Size / 2, (int)Size)) + foreach (int coord_y in Enumerable.Range(-(int)Size / 2, (int)Size)) { Vector2 textureCoord = OffsetToTextureCoord(new Vector2(coord_x, coord_y)); - float height = heightmap.GetPixel((int) textureCoord.x, (int) textureCoord.y).r; + float height = heightmap.GetPixel((int)textureCoord.x, (int)textureCoord.y).r; SetHeightAtOffset(new Vector2(coord_x, coord_y), height); } } } - + public bool IsOffsetCoordValid(Vector2 offsetCoord) { return ((int)Math.Clamp(offsetCoord.x, -Size / 2, Size / 2 - 1) == (int)offsetCoord.x @@ -200,14 +219,19 @@ public class TileWorld : Spatial public void SetHeightAtOffset(Vector2 offsetCoord, float height) { Vector2 textureCoord = OffsetToTextureCoord(offsetCoord); - - Heightmap.SetPixel((int) textureCoord.x, (int) textureCoord.y, new Color(height, 0f, 0f)); + + Heightmap.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f)); } public float GetHeightAtOffset(Vector2 offsetCoord) { - Vector2 textureCoord = OffsetToTextureCoord(offsetCoord); + if (CurrentGenerationState != GenerationState.Done) + { + return 0f; + } + Vector2 textureCoord = OffsetToTextureCoord(offsetCoord); + return Heightmap.GetPixel((int)textureCoord.x, (int)(textureCoord.y)).r * HeightScale; } diff --git a/scenes/TileWorld.tscn b/scenes/TileWorld.tscn index 6b3d354..78ce70b 100644 --- a/scenes/TileWorld.tscn +++ b/scenes/TileWorld.tscn @@ -1,8 +1,9 @@ -[gd_scene load_steps=4 format=2] +[gd_scene load_steps=5 format=2] [ext_resource path="res://scenes/TileWorld.cs" type="Script" id=1] [ext_resource path="res://icon.png" type="Texture" id=2] [ext_resource path="res://materials/IslandColorRampShader.tres" type="Material" id=3] +[ext_resource path="res://materials/IslandHeightmapFalloffShader.tres" type="Material" id=4] [node name="TileWorld" type="Spatial"] script = ExtResource( 1 ) @@ -12,7 +13,7 @@ transform = Transform( 0.328059, -0.878387, 0.347583, 0, 0.367946, 0.929847, -0. shadow_enabled = true directional_shadow_mode = 0 -[node name="OffscreenViewport" type="Viewport" parent="."] +[node name="WorldOffscreenViewport" type="Viewport" parent="."] size = Vector2( 100, 100 ) own_world = true handle_input_locally = false @@ -22,8 +23,24 @@ usage = 0 render_target_v_flip = true render_target_update_mode = 3 -[node name="TextureRect" type="TextureRect" parent="OffscreenViewport"] +[node name="TextureRect" type="TextureRect" parent="WorldOffscreenViewport"] material = ExtResource( 3 ) texture = ExtResource( 2 ) -[node name="Camera2D" type="Camera2D" parent="OffscreenViewport"] +[node name="Camera2D" type="Camera2D" parent="WorldOffscreenViewport"] + +[node name="HeightmapOffscreenViewport" type="Viewport" parent="."] +size = Vector2( 100, 100 ) +own_world = true +handle_input_locally = false +hdr = false +disable_3d = true +usage = 0 +render_target_v_flip = true +render_target_update_mode = 3 + +[node name="TextureRect" type="TextureRect" parent="HeightmapOffscreenViewport"] +material = ExtResource( 4 ) +texture = ExtResource( 2 ) + +[node name="Camera2D" type="Camera2D" parent="HeightmapOffscreenViewport"]