Fixed world generation artefacts after changing world size.

WorldChunkRefactoring
Martin Felis 2023-07-28 22:23:41 +02:00
parent 87f7af88f8
commit e759d6d3d5
5 changed files with 157 additions and 90 deletions

View File

@ -313,21 +313,11 @@ public class Game : Spatial
public void OnWorldGenerated() public void OnWorldGenerated()
{ {
GD.Print("Using new map. Size: " + (int)_tileWorld.Colormap.GetSize().x); GD.Print("Using new map. Size: " + (int)_tileWorld.ColormapImage.GetSize().x);
_goldCountLabel.Text = "0"; _goldCountLabel.Text = "0";
ImageTexture newWorldTexture = new ImageTexture(); UpdateWorldTextures();
newWorldTexture.CreateFromImage(_tileWorld.Colormap,
(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(); _streamContainer.OnWorldGenerated();
@ -344,6 +334,23 @@ public class Game : Spatial
} }
} }
private void UpdateWorldTextures()
{
GD.Print("Updating World textures");
ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_worldTextureRect.Texture = newWorldTexture;
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.ColormapImage.GetSize().x);
GD.Print("Texture size: " + (int)_tileWorld.ColormapImage.GetSize().x);
ImageTexture newHeightTexture = new ImageTexture();
newHeightTexture.CreateFromImage(_tileWorld.HeightmapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_heightTextureRect.Texture = newHeightTexture;
}
public void OnGoldCountChanged(int goldCount) public void OnGoldCountChanged(int goldCount)
{ {

View File

@ -42,7 +42,7 @@ transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.1, 0 )
[node name="TileWorld" parent="." instance=ExtResource( 8 )] [node name="TileWorld" parent="." instance=ExtResource( 8 )]
GenerationMapType = 0 GenerationMapType = 0
Size = 96 Size = 64
[node name="GameUI" type="HBoxContainer" parent="."] [node name="GameUI" type="HBoxContainer" parent="."]
anchor_left = 1.0 anchor_left = 1.0
@ -259,21 +259,21 @@ margin_bottom = 84.0
text = "Textures" text = "Textures"
[node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"] [node name="WorldTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
visible = false
margin_top = 88.0 margin_top = 88.0
margin_right = 135.0 margin_right = 100.0
margin_bottom = 188.0 margin_bottom = 188.0
rect_min_size = Vector2( 100, 100 ) rect_min_size = Vector2( 100, 100 )
stretch_mode = 1 expand = true
stretch_mode = 5
flip_v = true flip_v = true
[node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"] [node name="HeightTextureRect" type="TextureRect" parent="Generator Container/WorldGeneratorContainer"]
visible = false margin_top = 192.0
margin_top = 88.0 margin_right = 100.0
margin_right = 135.0 margin_bottom = 292.0
margin_bottom = 188.0
rect_min_size = Vector2( 100, 100 ) rect_min_size = Vector2( 100, 100 )
stretch_mode = 1 expand = true
stretch_mode = 5
flip_v = true flip_v = true
[node name="EditorUI" parent="." instance=ExtResource( 4 )] [node name="EditorUI" parent="." instance=ExtResource( 4 )]

View File

@ -4,7 +4,6 @@ using System.Linq;
using System.Diagnostics; using System.Diagnostics;
using Godot.Collections; using Godot.Collections;
using Namespace; using Namespace;
using Array = Godot.Collections.Array;
using Vector2 = Godot.Vector2; using Vector2 = Godot.Vector2;
using Vector3 = Godot.Vector3; using Vector3 = Godot.Vector3;
@ -19,8 +18,8 @@ public class TileWorld : Spatial
} }
// constants // constants
private static readonly Color RockColor = new Color(0.5f, 0.5f, 0.4f, 1f); private static readonly Color RockColor = new Color(0.5f, 0.5f, 0.4f);
private static readonly Color GrassColor = new Color(0, 0.4f, 0, 1f); private static readonly Color GrassColor = new Color(0, 0.4f, 0);
private GenerationState _currentGenerationState = GenerationState.Heightmap; private GenerationState _currentGenerationState = GenerationState.Heightmap;
@ -39,11 +38,11 @@ public class TileWorld : Spatial
[ExportFlagsEnum(typeof(MapType))] public MapType GenerationMapType = MapType.Debug; [ExportFlagsEnum(typeof(MapType))] public MapType GenerationMapType = MapType.Debug;
[Export] public int Size = 64; [Export] public int Size = 64;
[Export] public bool DebugMap = false; [Export] public bool DebugMap;
public float HeightScale = 2.0f; public float HeightScale = 2.0f;
public Image Heightmap; public Image HeightmapImage;
public Image Colormap; public Image ColormapImage;
public int Seed = 0; public int Seed = 0;
public Spatial Entities; public Spatial Entities;
public HexGrid HexGrid; public HexGrid HexGrid;
@ -55,10 +54,12 @@ public class TileWorld : Spatial
private TextureRect _worldOffscreenTextureRect; private TextureRect _worldOffscreenTextureRect;
private Viewport _heightmapOffscreenViewport; private Viewport _heightmapOffscreenViewport;
private TextureRect _heightmapOffscreenTextureRect; private TextureRect _heightmapOffscreenTextureRect;
private Array<Spatial> _rockAssets = new Array<Spatial>(); private Array<Spatial> _rockAssets = new();
private Array<Spatial> _grassAssets = new Array<Spatial>(); private Array<Spatial> _grassAssets = new();
private Array<Spatial> _treeAssets = new Array<Spatial>(); private Array<Spatial> _treeAssets = new();
private Spatial _environmentNode; private Spatial _environmentNode;
private bool _resizeTriggered;
private int _resizeExtraFrameCount = 0;
// 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()
@ -100,19 +101,53 @@ public class TileWorld : Spatial
_environmentNode = GetNode<Spatial>("Environment"); _environmentNode = GetNode<Spatial>("Environment");
Entities = GetNode<Spatial>("Entities"); Entities = GetNode<Spatial>("Entities");
Generate(Size); ResetWorldImages(Size);
} }
public void ResetWorldImages(int size)
{
GD.Print("Resetting World Images to size " + size);
Vector2 sizeVector = new Vector2(size, size);
ColormapImage = new Image();
ColormapImage.Create(size, size, false, Image.Format.Rgba8);
ColormapImage.FillRect(new Rect2(0, 0, size, size), Colors.Black);
_worldOffscreenTextureRect.SetSize(sizeVector);
_worldOffscreenViewport.Size = sizeVector;
HeightmapImage = new Image();
HeightmapImage.Create(size, size, false, Image.Format.Rf);
HeightmapImage.FillRect(new Rect2(0, 0, size, size), Colors.ForestGreen);
_heightmapOffscreenTextureRect.SetSize(sizeVector);
_heightmapOffscreenViewport.Size = sizeVector;
}
public void PrintTextureSizes()
{
GD.Print("Color Viewport: " + _worldOffscreenViewport.Size);
GD.Print("Color TextureRect: " + _worldOffscreenTextureRect.Texture.GetSize());
GD.Print("Heightmap Viewport: " + _heightmapOffscreenViewport.Size);
GD.Print("Heightmap TextureRect: " + _heightmapOffscreenTextureRect.Texture.GetSize());
}
public void Generate(int size) public void Generate(int size)
{ {
GD.Print("Triggering generation for size: " + size); GD.Print("Triggering generation for size: " + size);
if (Size != size)
{
ResetWorldImages(size);
_resizeTriggered = true;
_resizeExtraFrameCount = 1;
}
Size = size; Size = size;
_worldOffscreenViewport.Size = new Vector2(size, size); _worldOffscreenViewport.Size = new Vector2(size, size);
_heightmapOffscreenViewport.Size = new Vector2(size, size); _heightmapOffscreenViewport.Size = new Vector2(size, size);
_halfSize = Mathf.RoundToInt((float)size) / 2; _halfSize = Mathf.RoundToInt(size) / 2;
HexGrid.SetBounds( HexGrid.SetBounds(
TextureCoordToCell(new Vector2(0, 0)), TextureCoordToCell(new Vector2(0, 0)),
TextureCoordToCell(new Vector2(size, size)) TextureCoordToCell(new Vector2(size, size))
@ -139,29 +174,29 @@ public class TileWorld : Spatial
private void GenerateDebugMap() private void GenerateDebugMap()
{ {
Colormap = new Image(); ColormapImage = new Image();
Colormap.Create(Size, Size, false, Image.Format.Rgba8); ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
Heightmap = new Image(); HeightmapImage = new Image();
Heightmap.Create(Size, Size, false, Image.Format.Rf); HeightmapImage.Create(Size, Size, false, Image.Format.Rf);
Heightmap.Lock(); HeightmapImage.Lock();
Colormap.Lock(); ColormapImage.Lock();
foreach (int coord_x in Enumerable.Range(0, Size)) foreach (int coordX in Enumerable.Range(0, Size))
{ {
foreach (int coord_y in Enumerable.Range(0, Size)) foreach (int coordY in Enumerable.Range(0, Size))
{ {
Colormap.SetPixel(coord_x, coord_y, ColormapImage.SetPixel(coordX, coordY,
new Color((float)Mathf.Min(coord_x, coord_y) / Size, (float)0, 0, 1)); new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
Heightmap.SetPixel(coord_x, coord_y, HeightmapImage.SetPixel(coordX, coordY,
new Color((float)Mathf.Min(coord_x, coord_y) / Size, (float)0, 0, 1)); new Color((float)Mathf.Min(coordX, coordY) / Size, 0, 0));
} }
} }
// Colormap.SetPixel(Size - 1, Size - 1, new Color(1, 1, 1, 1)); // Colormap.SetPixel(Size - 1, Size - 1, new Color(1, 1, 1, 1));
Colormap.Fill(Colors.ForestGreen); ColormapImage.Fill(Colors.ForestGreen);
Colormap.Unlock(); ColormapImage.Unlock();
OnMapGenerationComplete(); OnMapGenerationComplete();
} }
@ -169,26 +204,26 @@ public class TileWorld : Spatial
private void GenerateFlatMap() private void GenerateFlatMap()
{ {
Colormap = new Image(); ColormapImage = new Image();
Colormap.Create(Size, Size, false, Image.Format.Rgba8); ColormapImage.Create(Size, Size, false, Image.Format.Rgba8);
Heightmap = new Image(); HeightmapImage = new Image();
Heightmap.Create(Size, Size, false, Image.Format.Rf); HeightmapImage.Create(Size, Size, false, Image.Format.Rf);
Heightmap.Lock(); HeightmapImage.Lock();
Colormap.Lock(); ColormapImage.Lock();
foreach (int coord_x in Enumerable.Range(0, Size)) foreach (int coordX in Enumerable.Range(0, Size))
{ {
foreach (int coord_y in Enumerable.Range(0, Size)) foreach (int coordY in Enumerable.Range(0, Size))
{ {
Heightmap.SetPixel(coord_x, coord_y, HeightmapImage.SetPixel(coordX, coordY,
new Color(0, 0, 0, 1)); new Color(0, 0, 0));
} }
} }
Colormap.Fill(Colors.ForestGreen); ColormapImage.Fill(Colors.ForestGreen);
Colormap.Unlock(); ColormapImage.Unlock();
OnMapGenerationComplete(); OnMapGenerationComplete();
} }
@ -196,8 +231,8 @@ public class TileWorld : Spatial
private void GenerateNoiseMap() private void GenerateNoiseMap()
{ {
Heightmap = new Image(); HeightmapImage = new Image();
Heightmap.Create(Size, Size, false, Image.Format.Rgba8); HeightmapImage.Create(Size, Size, false, Image.Format.Rgba8);
OpenSimplexNoise noiseGenerator = new OpenSimplexNoise(); OpenSimplexNoise noiseGenerator = new OpenSimplexNoise();
@ -208,10 +243,9 @@ public class TileWorld : Spatial
noiseGenerator.Lacunarity = 4; noiseGenerator.Lacunarity = 4;
ImageTexture heightmapTexture = new ImageTexture(); ImageTexture heightmapTexture = new ImageTexture();
heightmapTexture.CreateFromImage(noiseGenerator.GetSeamlessImage((int)Size)); heightmapTexture.CreateFromImage(noiseGenerator.GetSeamlessImage(Size));
heightmapTexture.Flags = 0; heightmapTexture.Flags = 0;
_heightmapOffscreenTextureRect.Texture = heightmapTexture; _heightmapOffscreenTextureRect.Texture = heightmapTexture;
Heightmap.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
OnHeightMapChanged(); OnHeightMapChanged();
} }
@ -231,6 +265,7 @@ public class TileWorld : Spatial
private void OnHeightMapChanged() private void OnHeightMapChanged()
{ {
GD.Print("Triggering rendering of height map");
_currentGenerationState = GenerationState.Heightmap; _currentGenerationState = GenerationState.Heightmap;
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once; _heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
} }
@ -238,6 +273,11 @@ public class TileWorld : Spatial
private void OnMapGenerationComplete() private void OnMapGenerationComplete()
{ {
_currentGenerationState = GenerationState.Done; _currentGenerationState = GenerationState.Done;
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
_heightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled;
_resizeTriggered = false;
HeightmapImage.Lock();
EmitSignal("WorldGenerated"); EmitSignal("WorldGenerated");
} }
@ -275,12 +315,14 @@ public class TileWorld : Spatial
{ {
Random environmentRandom = new Random(Seed); Random environmentRandom = new Random(Seed);
Colormap.Lock(); ColormapImage.Lock();
HeightmapImage.Lock();
foreach (int textureCoordU in Enumerable.Range(0, Size)) foreach (int textureCoordU in Enumerable.Range(0, Size))
{ {
foreach (int textureCoordV in Enumerable.Range(0, Size)) foreach (int textureCoordV in Enumerable.Range(0, Size))
{ {
Color colorValue = Colormap.GetPixel(textureCoordU, textureCoordV); Color colorValue = ColormapImage.GetPixel(textureCoordU, textureCoordV);
Vector2 textureCoord = new Vector2(textureCoordU, textureCoordV); Vector2 textureCoord = new Vector2(textureCoordU, textureCoordV);
HexCell cell = TextureCoordToCell(textureCoord); HexCell cell = TextureCoordToCell(textureCoord);
Vector2 offsetCoord = cell.OffsetCoords; Vector2 offsetCoord = cell.OffsetCoords;
@ -316,39 +358,53 @@ public class TileWorld : Spatial
} }
} }
Colormap.Unlock(); HeightmapImage.Unlock();
ColormapImage.Unlock();
} }
public override void _Process(float delta) public override void _Process(float delta)
{ {
if (_resizeTriggered && _resizeExtraFrameCount > 0)
{
_resizeExtraFrameCount--;
return;
}
if (_currentGenerationState == GenerationState.Heightmap) if (_currentGenerationState == GenerationState.Heightmap)
{ {
HeightmapImage.CopyFrom(_heightmapOffscreenViewport.GetTexture().GetData());
_currentGenerationState = GenerationState.Color; _currentGenerationState = GenerationState.Color;
ImageTexture imageTexture = new ImageTexture(); ImageTexture imageTexture = new ImageTexture();
imageTexture.CreateFromImage(Heightmap); imageTexture.CreateFromImage(HeightmapImage);
imageTexture.Flags = 0; imageTexture.Flags = 0;
_worldOffscreenTextureRect.Texture = imageTexture; _worldOffscreenTextureRect.Texture = imageTexture;
GD.Print("Triggering rendering of color map");
_worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once; _worldOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once;
_resizeExtraFrameCount = 1;
} }
else if (_currentGenerationState == GenerationState.Color) else if (_currentGenerationState == GenerationState.Color)
{ {
Colormap = new Image(); ColormapImage = new Image();
Colormap.Create(Size, Size, false, Image.Format.Rgb8); ColormapImage.Create(Size, Size, false, Image.Format.Rgb8);
Colormap.CopyFrom(_worldOffscreenViewport.GetTexture().GetData()); ColormapImage.CopyFrom(_worldOffscreenViewport.GetTexture().GetData());
Heightmap.Lock();
_currentGenerationState = GenerationState.Objects; _currentGenerationState = GenerationState.Objects;
PopulateEnvironment(); PopulateEnvironment();
}
else if (_currentGenerationState == GenerationState.Objects)
{
OnMapGenerationComplete(); OnMapGenerationComplete();
} }
} }
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, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.x
&& (int)Math.Clamp(offsetCoord.y, -Size / 2, Size / 2 - 1) == (int)offsetCoord.y); && (int)Math.Clamp(offsetCoord.y, -(float)Size / 2, (float)Size / 2 - 1) == (int)offsetCoord.y);
} }
@ -365,7 +421,6 @@ public class TileWorld : Spatial
public Vector2 OffsetToTextureCoord(Vector2 offsetCoord) public Vector2 OffsetToTextureCoord(Vector2 offsetCoord)
{ {
// Vector2 textureCoord = (offsetCoord - Vector2.One * (Mathf.Floor(Size / 2))) % (Vector2.One * Size);
Vector2 mapSize = Vector2.One * Size; Vector2 mapSize = Vector2.One * Size;
Vector2 textureCoord = (offsetCoord + mapSize / 2).PosMod(mapSize); Vector2 textureCoord = (offsetCoord + mapSize / 2).PosMod(mapSize);
return textureCoord; return textureCoord;
@ -375,7 +430,7 @@ public class TileWorld : Spatial
{ {
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord); Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
Heightmap.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f)); HeightmapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, new Color(height, 0f, 0f));
} }
public float GetHeightAtOffset(Vector2 offsetCoord) public float GetHeightAtOffset(Vector2 offsetCoord)
@ -387,15 +442,12 @@ public class TileWorld : Spatial
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord); Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
float heightmapHeight = Heightmap.GetPixel((int)textureCoord.x, (int)(textureCoord.y)).r; float heightmapHeight = HeightmapImage.GetPixel((int)textureCoord.x, (int)(textureCoord.y)).r;
if (heightmapHeight > 0.5) if (heightmapHeight > 0.5)
{ {
heightmapHeight = 0.6f; heightmapHeight = 0.6f;
} }
// heightmapHeight = Mathf.Floor(heightmapHeight);
// heightmapHeight = heightmapHeight * 10)
// heightmapHeight = Mathf.Clamp(heightmapHeight, -1f, 5);
return heightmapHeight * HeightScale; return heightmapHeight * HeightScale;
} }
@ -405,11 +457,11 @@ public class TileWorld : Spatial
{ {
Vector2 textureCoord = OffsetToTextureCoord(offsetCoord); Vector2 textureCoord = OffsetToTextureCoord(offsetCoord);
Colormap.Lock(); ColormapImage.Lock();
Colormap.SetPixel((int)textureCoord.x, (int)textureCoord.y, color); ColormapImage.SetPixel((int)textureCoord.x, (int)textureCoord.y, color);
Colormap.Unlock(); ColormapImage.Unlock();
EmitSignal("WorldGenerated"); OnMapGenerationComplete();
} }
public Vector2 WorldToOffsetCoords(Vector3 worldCoord) public Vector2 WorldToOffsetCoords(Vector3 worldCoord)

View File

@ -26,7 +26,11 @@ hdr = false
disable_3d = true disable_3d = true
usage = 0 usage = 0
render_target_v_flip = true render_target_v_flip = true
render_target_update_mode = 1 render_target_update_mode = 0
shadow_atlas_quad_0 = 0
shadow_atlas_quad_1 = 0
shadow_atlas_quad_2 = 0
shadow_atlas_quad_3 = 0
[node name="TextureRect" type="TextureRect" parent="WorldOffscreenViewport"] [node name="TextureRect" type="TextureRect" parent="WorldOffscreenViewport"]
material = ExtResource( 3 ) material = ExtResource( 3 )
@ -42,7 +46,11 @@ hdr = false
disable_3d = true disable_3d = true
usage = 0 usage = 0
render_target_v_flip = true render_target_v_flip = true
render_target_update_mode = 1 render_target_update_mode = 0
shadow_atlas_quad_0 = 0
shadow_atlas_quad_1 = 0
shadow_atlas_quad_2 = 0
shadow_atlas_quad_3 = 0
[node name="TextureRect" type="TextureRect" parent="HeightmapOffscreenViewport"] [node name="TextureRect" type="TextureRect" parent="HeightmapOffscreenViewport"]
material = ExtResource( 4 ) material = ExtResource( 4 )

View File

@ -81,10 +81,10 @@ public class NavigationTests : Spatial
_player.Transform = playerTransform; _player.Transform = playerTransform;
ImageTexture newWorldTexture = new ImageTexture(); ImageTexture newWorldTexture = new ImageTexture();
newWorldTexture.CreateFromImage(_tileWorld.Colormap, newWorldTexture.CreateFromImage(_tileWorld.ColormapImage,
(uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat)); (uint)(Texture.FlagsEnum.Mipmaps | Texture.FlagsEnum.Repeat));
_tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture); _tileMaterial.SetShaderParam("MapAlbedoTexture", newWorldTexture);
_tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.Colormap.GetSize().x); _tileMaterial.SetShaderParam("TextureSize", (int)_tileWorld.ColormapImage.GetSize().x);
} }