From 092896aa5223f76f0caa165beac2c2e3a6c8d815 Mon Sep 17 00:00:00 2001 From: Jarrod Doyle Date: Tue, 27 Aug 2024 21:18:31 +0100 Subject: [PATCH] Use Texture2dArray for lightmap texture --- project/code/LGS/Database/Chunks/WorldRep.cs | 74 ++++++++------------ project/code/TMV/Mission.cs | 36 ++++++++-- project/materials/base.tres | 9 ++- 3 files changed, 68 insertions(+), 51 deletions(-) diff --git a/project/code/LGS/Database/Chunks/WorldRep.cs b/project/code/LGS/Database/Chunks/WorldRep.cs index 63967fc..32ec6d2 100644 --- a/project/code/LGS/Database/Chunks/WorldRep.cs +++ b/project/code/LGS/Database/Chunks/WorldRep.cs @@ -149,56 +149,44 @@ public class WorldRep : IChunk } } - public readonly byte[] AsBytesRgba() + public readonly byte[] AsBytesRgba(int layer) { - var length = Width * Height * 4; - var bytes = new byte[length]; - for (var i = 0; i < length; i++) + if (layer >= Layers) { - bytes[i] = 0; + throw new ArgumentOutOfRangeException(nameof(layer)); } - // TODO: might be faster to do these fors in the switch? - for (var z = 0; z < Layers; z++) + var length = Width * Height * 4; + var layerOffset = layer * Bpp * Width * Height; + var bytes = new byte[length]; + for (var y = 0; y < Height; y++) { - for (var y = 0; y < Height; y++) + for (var x = 0; x < Width; x++) { - for (var x = 0; x < Width; x++) + var bIdx = x * 4 + y * 4 * Width; + var pIdx = x * Bpp + y * Bpp * Width + layerOffset; + switch (Bpp) { - var pIdx = 0 + x * Bpp + y * Bpp * Width + z * Bpp * Width * Height; - var r = 0; - var g = 0; - var b = 0; - var a = 0; - switch (Bpp) - { - case 1: - var raw1 = Pixels[pIdx]; - r = raw1; - g = raw1; - b = raw1; - a = 255; - break; - case 2: - var raw2 = Pixels[pIdx] + (Pixels[pIdx + 1] << 8); - r = (int)(255 * (raw2 & 31) / 31.0f); - g = (int)(255 * ((raw2 >> 5) & 31) / 31.0f); - b = (int)(255 * ((raw2 >> 10) & 31) / 31.0f); - a = 255; - break; - case 4: - r = Pixels[pIdx + 2]; - g = Pixels[pIdx + 1]; - b = Pixels[pIdx]; - a = Pixels[pIdx + 3]; - break; - } - - var bIdx = x * 4 + y * 4 * Width; - bytes[bIdx] = (byte)Math.Min(255, bytes[bIdx] + r); - bytes[bIdx + 1] = (byte)Math.Min(255, bytes[bIdx + 1] + g); - bytes[bIdx + 2] = (byte)Math.Min(255, bytes[bIdx + 2] + b); - bytes[bIdx + 3] = (byte)Math.Min(255, bytes[bIdx + 3] + a); + case 1: + var raw1 = Pixels[pIdx]; + bytes[bIdx] = raw1; + bytes[bIdx + 1] = raw1; + bytes[bIdx + 2] = raw1; + bytes[bIdx + 3] = 255; + break; + case 2: + var raw2 = Pixels[pIdx] + (Pixels[pIdx + 1] << 8); + bytes[bIdx] = (byte)(255 * (raw2 & 31) / 31.0f); + bytes[bIdx + 1] = (byte)(255 * ((raw2 >> 5) & 31) / 31.0f); + bytes[bIdx + 2] = (byte)(255 * ((raw2 >> 10) & 31) / 31.0f); + bytes[bIdx + 3] = 255; + break; + case 4: + bytes[bIdx] = Pixels[pIdx + 2]; + bytes[bIdx + 1] = Pixels[pIdx + 1]; + bytes[bIdx + 2] = Pixels[pIdx]; + bytes[bIdx + 3] = Pixels[pIdx + 3]; + break; } } } diff --git a/project/code/TMV/Mission.cs b/project/code/TMV/Mission.cs index 9fa1c3c..fb4b120 100644 --- a/project/code/TMV/Mission.cs +++ b/project/code/TMV/Mission.cs @@ -282,7 +282,11 @@ public partial class Mission : Node3D return new LightmapRectData(cellIdx, polyIdx, textureId, start, end); } - private static Texture BuildLightmapTexture(WorldRep.Cell[] cells, PackingRectangle[] packingRects, Dictionary rectDataMap, Dictionary surfaceDataMap) + private static Texture2DArray BuildLightmapTexture( + WorldRep.Cell[] cells, + PackingRectangle[] packingRects, + Dictionary rectDataMap, + Dictionary surfaceDataMap) { var bounds = Timing.TimeStage("RectPack", () => { @@ -290,7 +294,16 @@ public partial class Mission : Node3D return bounds; }); GD.Print($"Creating lightmap with bounds: ({bounds.Width}, {bounds.Height})"); - var image = Image.CreateEmpty((int)bounds.Width, (int)bounds.Height, false, Image.Format.Rgba8); + + var lightmapFormat = Image.Format.Rgba8; + var lmLayerCount = 33; + var lmImages = new Godot.Collections.Array(); + lmImages.Resize(lmLayerCount); + for (var i = 0; i < lmLayerCount; i++) + { + lmImages[i] = Image.CreateEmpty((int)bounds.Width, (int)bounds.Height, false, lightmapFormat); + } + foreach (var rect in packingRects) { if (!rectDataMap.ContainsKey(rect.Id)) GD.Print("Invalid rectDataMap key"); @@ -298,9 +311,18 @@ public partial class Mission : Node3D if (info.cellIndex >= cells.Length) GD.Print($"CellIndex too big: {info.cellIndex}/{cells.Length}"); if (info.lightmapIndex >= cells[info.cellIndex].Lightmaps.Length) GD.Print($"LightmapIndex too big: {info.lightmapIndex}/{cells[info.cellIndex].Lightmaps.Length}"); + var lightmap = cells[info.cellIndex].Lightmaps[info.lightmapIndex]; - var cellLm = Image.CreateFromData(lightmap.Width, lightmap.Height, false, Image.Format.Rgba8, lightmap.AsBytesRgba()); - image.BlitRect(cellLm, new Rect2I(0, 0, lightmap.Width, lightmap.Height), new Vector2I((int)rect.X, (int)rect.Y)); + var width = lightmap.Width; + var height = lightmap.Height; + var layerCount = lightmap.Layers; + var srcRect = new Rect2I(0, 0, width, height); + var dst = new Vector2I((int)rect.X, (int)rect.Y); + for (var i = 0; i < layerCount; i++) + { + var cellLm = Image.CreateFromData(width, height, false, lightmapFormat, lightmap.AsBytesRgba(i)); + lmImages[i].BlitRect(cellLm, srcRect, dst); + } if (!surfaceDataMap.ContainsKey(info.textureId)) GD.Print("Invalid SurfaceDataMap key"); surfaceDataMap[info.textureId].TransformUv2s(info.uvStart, info.uvEnd, (uv) => @@ -321,7 +343,9 @@ public partial class Mission : Node3D }); } - return ImageTexture.CreateFromImage(image); + var lightmapTexture = new Texture2DArray(); + lightmapTexture.CreateFromImages(lmImages); + return lightmapTexture; } private int CalcBaseUV( @@ -448,7 +472,7 @@ public partial class Mission : Node3D } const string MATERIAL_PATH = "res://project/materials/base.tres"; - private static Material BuildMaterial(Texture albedoTexture, Texture lightmapTexture, bool lmHdr) + private static Material BuildMaterial(Texture2D albedoTexture, Texture2DArray lightmapTexture, bool lmHdr) { var material = ResourceLoader.Load(MATERIAL_PATH).Duplicate() as ShaderMaterial; material.SetShaderParameter("texture_albedo", albedoTexture); diff --git a/project/materials/base.tres b/project/materials/base.tres index ccfb39d..8854037 100644 --- a/project/materials/base.tres +++ b/project/materials/base.tres @@ -4,7 +4,7 @@ code = "shader_type spatial; render_mode blend_mix,depth_draw_opaque,cull_back,unshaded; uniform sampler2D texture_albedo : filter_linear_mipmap_anisotropic,repeat_enable; -uniform sampler2D lightmap_albedo : filter_linear_mipmap_anisotropic,repeat_enable; +uniform sampler2DArray lightmap_albedo : filter_linear_mipmap_anisotropic,repeat_enable; uniform bool lightmap_2x; float srgb_to_linear_e(float input) { @@ -28,7 +28,12 @@ vec3 srgb_to_linear(vec3 input) { void fragment() { vec4 albedo_tex = texture(texture_albedo,UV); - vec4 lightmap_tex = texture(lightmap_albedo,UV2); + vec4 lightmap_tex = vec4(0.0); + for (int i = 0; i < 33; i++) { + lightmap_tex += texture(lightmap_albedo, vec3(UV2, float(i))); + } + lightmap_tex = min(vec4(1.0), lightmap_tex); + if (lightmap_2x) { lightmap_tex *= 2.0f; }