Heightmap and Colormap generation kind of works now.

WorldChunkRefactoring
Martin Felis 2023-05-21 17:24:37 +02:00
parent 55da2346d3
commit 866fd11399
9 changed files with 236 additions and 131 deletions

View File

@ -1,59 +1,6 @@
[gd_resource type="ShaderMaterial" load_steps=2 format=2] [gd_resource type="ShaderMaterial" load_steps=2 format=2]
[sub_resource type="Shader" id=1] [ext_resource path="res://materials/shader/IslandColorRampShader.gdshader" 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);
}
"
[resource] [resource]
shader = SubResource( 1 ) shader = ExtResource( 1 )

View File

@ -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 )

View File

@ -47,7 +47,7 @@ void vertex() {
} }
void fragment() { void fragment() {
ALBEDO = texture(MapAlbedoTexture, map_coord).rgb; ALBEDO = pow(texture(MapAlbedoTexture, map_coord).rgb, vec3(2.4));
} }
void light() { void light() {

View File

@ -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);
}

View File

@ -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);
}

View File

@ -9,17 +9,17 @@
config_version=4 config_version=4
_global_script_classes=[ { _global_script_classes=[ {
"base": "Node", "base": "Reference",
"class": "ClickableComponent", "class": "ClickableComponent",
"language": "GDScript", "language": "GDScript",
"path": "res://components/ClickableComponent.gd" "path": "res://components/ClickableComponent.gd"
}, { }, {
"base": "KinematicBody2D", "base": "Reference",
"class": "CollisionLine", "class": "CollisionLine",
"language": "GDScript", "language": "GDScript",
"path": "res://utils/CollisionLine.gd" "path": "res://utils/CollisionLine.gd"
}, { }, {
"base": "Node", "base": "Reference",
"class": "ColorComponent", "class": "ColorComponent",
"language": "GDScript", "language": "GDScript",
"path": "res://components/ColorComponent.gd" "path": "res://components/ColorComponent.gd"
@ -54,7 +54,7 @@ _global_script_classes=[ {
"language": "GDScript", "language": "GDScript",
"path": "res://utils/SpringDamper.gd" "path": "res://utils/SpringDamper.gd"
}, { }, {
"base": "Sprite", "base": "Reference",
"class": "TintedSpriteComponent", "class": "TintedSpriteComponent",
"language": "GDScript", "language": "GDScript",
"path": "res://components/TintedSpriteComponent.gd" "path": "res://components/TintedSpriteComponent.gd"

View File

@ -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() public void OnWorldGenerated()
{ {
GD.Print("Using new map"); GD.Print("Using new map");
ImageTexture newWorldTexture = new ImageTexture(); ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(_tileWorld.Colormap, (uint) (Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat)); 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; _worldTextureRect.Texture = newWorldTexture;
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture); _tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.Colormap.GetSize().x); _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; _heightTextureRect.Texture = newHeightTexture;
_streamContainer.OnWorldGenerated(); _streamContainer.OnWorldGenerated();
// Reset player transform to offset 0,0 and at current height // Reset player transform to offset 0,0 and at current height
Transform playerStartTransform = Transform.Identity; ResetGameState();
float height = _tileWorld.GetHeightAtOffset(new Vector2(0, 0));
playerStartTransform.origin.y = height;
_player.Transform = playerStartTransform;
} }
} }

View File

@ -9,12 +9,21 @@ using Vector3 = Godot.Vector3;
public class TileWorld : Spatial public class TileWorld : Spatial
{ {
private enum GenerationState
{
Heightmap,
Color,
Done
}
private GenerationState CurrentGenerationState = GenerationState.Heightmap;
// signals // signals
[Signal] [Signal]
delegate void WorldGenerated(); delegate void WorldGenerated();
// public members // public members
public float Size = 5; public float Size = 100;
public float HeightScale = 10.0f; public float HeightScale = 10.0f;
public Image Heightmap; public Image Heightmap;
public Image Colormap; public Image Colormap;
@ -23,39 +32,42 @@ public class TileWorld : Spatial
// private members // private members
private HexGrid _hexGrid; private HexGrid _hexGrid;
private Random _tileTypeRandom; private Random _tileTypeRandom;
private Viewport _offscreenViewport; private Viewport _worldOffscreenViewport;
private TextureRect _offscreenTextureRect; private TextureRect _worldOffscreenTextureRect;
private Viewport _heightmapOffscreenViewport;
private TextureRect _heightmapOffscreenTextureRect;
// Called when the node enters the scene tree for the first time. // Called when the node enters the scene tree for the first time.
public override void _Ready() public override void _Ready()
{ {
_hexGrid = new HexGrid(); _hexGrid = new HexGrid();
_tileTypeRandom = new Random(); _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() public void Generate()
{ {
//GenerateSimpleMap(); GenerateNoiseMap();
//GenerateNoiseMap();
GenerateNoiseColorMap();
//GenerateDebugMap(); //GenerateDebugMap();
EmitSignal("WorldGenerated");
} }
private void GenerateDebugMap() private void GenerateDebugMap()
{ {
Colormap = new Image(); Colormap = new Image();
@ -63,7 +75,7 @@ public class TileWorld : Spatial
Heightmap = new Image(); Heightmap = new Image();
Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf); Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf);
Heightmap.Lock(); Heightmap.Lock();
Colormap.Lock(); Colormap.Lock();
foreach (int coord_x in Enumerable.Range(0, (int)Size)) foreach (int coord_x in Enumerable.Range(0, (int)Size))
@ -78,16 +90,17 @@ public class TileWorld : Spatial
{ {
coord_to_height = 1; coord_to_height = 1;
} }
SetHeightAtOffset(new Vector2(coord_x, coord_y), coord_to_height); SetHeightAtOffset(new Vector2(coord_x, coord_y), coord_to_height);
} }
} }
Colormap.Unlock(); Colormap.Unlock();
ImageTexture imageTexture = new ImageTexture(); ImageTexture imageTexture = new ImageTexture();
imageTexture.CreateFromImage(Heightmap); imageTexture.CreateFromImage(Heightmap);
imageTexture.Flags = 0; imageTexture.Flags = 0;
_offscreenTextureRect.Texture = imageTexture; _worldOffscreenTextureRect.Texture = imageTexture;
Colormap.CopyFrom(imageTexture.GetData()); Colormap.CopyFrom(imageTexture.GetData());
} }
@ -97,40 +110,21 @@ public class TileWorld : Spatial
Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf); Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf);
Heightmap.Lock(); 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); SetHeightAtOffset(new Vector2(coord_x, coord_y), 5f);
} }
} }
} }
private void GenerateNoiseMap() private void GenerateNoiseMap()
{ {
Heightmap = new Image(); Heightmap = new Image();
Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rf); Heightmap.Create((int)Size, (int)Size, false, Image.Format.Rgba8);
NoiseTexture noiseTexture = new NoiseTexture();
OpenSimplexNoise noiseGenerator = new OpenSimplexNoise();
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(); OpenSimplexNoise noiseGenerator = new OpenSimplexNoise();
noiseGenerator.Seed = Seed; noiseGenerator.Seed = Seed;
@ -139,30 +133,55 @@ public class TileWorld : Spatial
noiseGenerator.Persistence = 0.2f; noiseGenerator.Persistence = 0.2f;
noiseGenerator.Lacunarity = 4; noiseGenerator.Lacunarity = 4;
ImageTexture imageTexture = new ImageTexture(); ImageTexture heightmapTexture = new ImageTexture();
Heightmap = noiseGenerator.GetSeamlessImage((int)Size); // heightmapTexture.CreateFromImage(noiseGenerator.GetImage((int)Size, (int)Size));
imageTexture.CreateFromImage(Heightmap); heightmapTexture.CreateFromImage(noiseGenerator.GetSeamlessImage((int) Size));
imageTexture.Flags = 0; heightmapTexture.Flags = 0;
_offscreenTextureRect.Texture = imageTexture; _heightmapOffscreenTextureRect.Texture = heightmapTexture;
Colormap.CopyFrom(_offscreenViewport.GetTexture().GetData()); Heightmap.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
Heightmap.Lock();
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) 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)); 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); SetHeightAtOffset(new Vector2(coord_x, coord_y), height);
} }
} }
} }
public bool IsOffsetCoordValid(Vector2 offsetCoord) public bool IsOffsetCoordValid(Vector2 offsetCoord)
{ {
return ((int)Math.Clamp(offsetCoord.x, -Size / 2, Size / 2 - 1) == (int)offsetCoord.x 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) public void SetHeightAtOffset(Vector2 offsetCoord, float height)
{ {
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord); 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) 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; return Heightmap.GetPixel((int)textureCoord.x, (int)(textureCoord.y)).r * HeightScale;
} }

View File

@ -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://scenes/TileWorld.cs" type="Script" id=1]
[ext_resource path="res://icon.png" type="Texture" id=2] [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/IslandColorRampShader.tres" type="Material" id=3]
[ext_resource path="res://materials/IslandHeightmapFalloffShader.tres" type="Material" id=4]
[node name="TileWorld" type="Spatial"] [node name="TileWorld" type="Spatial"]
script = ExtResource( 1 ) script = ExtResource( 1 )
@ -12,7 +13,7 @@ transform = Transform( 0.328059, -0.878387, 0.347583, 0, 0.367946, 0.929847, -0.
shadow_enabled = true shadow_enabled = true
directional_shadow_mode = 0 directional_shadow_mode = 0
[node name="OffscreenViewport" type="Viewport" parent="."] [node name="WorldOffscreenViewport" type="Viewport" parent="."]
size = Vector2( 100, 100 ) size = Vector2( 100, 100 )
own_world = true own_world = true
handle_input_locally = false handle_input_locally = false
@ -22,8 +23,24 @@ usage = 0
render_target_v_flip = true render_target_v_flip = true
render_target_update_mode = 3 render_target_update_mode = 3
[node name="TextureRect" type="TextureRect" parent="OffscreenViewport"] [node name="TextureRect" type="TextureRect" parent="WorldOffscreenViewport"]
material = ExtResource( 3 ) material = ExtResource( 3 )
texture = ExtResource( 2 ) 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"]