Skip to content

Commit

Permalink
Client: Improve the accuracy of downsampled texture colors
Browse files Browse the repository at this point in the history
It seems that some error correction is applied by the fixed-function pipeline when operating on the downsampled (reduced-color) textures? Merely truncating the colors, as previously done, yields visible artifacts with an accumulating error consistent with the dropped precision (1 per 32 for bpp = 5). The base colors would have to be either uint8 or floats, which carry more information after all. The results are otherwise fairly exact, at least on the few maps I tested. This may also apply to lightmaps? (TBD)
  • Loading branch information
rdw-software committed Mar 18, 2024
1 parent e96fadd commit 0be1251
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 8 deletions.
16 changes: 10 additions & 6 deletions Core/NativeClient/WebGPU/Texture.lua
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ local webgpu = require("wgpu")

local cast = ffi.cast
local new = ffi.new
local math_floor = math.floor
local floor = math.floor

local Texture = {
DEFAULT_TEXTURE_FORMAT = ffi.C.WGPUTextureFormat_RGBA8Unorm,
Expand Down Expand Up @@ -192,7 +192,7 @@ function Texture:GenerateCheckeredGridImage(textureWidthInPixels, textureHeightI
for v = 0, textureHeightInPixels - 1 do
local index = 4 * (v * textureWidthInPixels + u)

local useAlternateColor = math_floor(u / GRID_CELL_SIZE) % 2 == math_floor(v / GRID_CELL_SIZE) % 2
local useAlternateColor = floor(u / GRID_CELL_SIZE) % 2 == floor(v / GRID_CELL_SIZE) % 2
local cellColor = useAlternateColor and firstColor or secondColor

pixels[index + RGBA_OFFSET_RED] = ffi.cast("uint8_t", cellColor.red * 255)
Expand Down Expand Up @@ -234,10 +234,14 @@ function Texture:CreateReducedColorImage(inputImageBytes, width, height, posteri
posterizedBlue = bit.lshift(posterizedBlue, posterizationLevel)
posterizedAlpha = bit.lshift(posterizedAlpha, posterizationLevel)

bufferStartPointer[writableAreaStartIndex + 0] = posterizedRed
bufferStartPointer[writableAreaStartIndex + 1] = posterizedGreen
bufferStartPointer[writableAreaStartIndex + 2] = posterizedBlue
bufferStartPointer[writableAreaStartIndex + 3] = posterizedAlpha
local remainingColorDepthInBitsPerPixel = math.max(1, 8 - posterizationLevel)
local numAvailableColorValues = math.pow(2, remainingColorDepthInBitsPerPixel) -- 256, 128, 64, 32, 16, 8
local errorCorrection = 1 / numAvailableColorValues

bufferStartPointer[writableAreaStartIndex + 0] = posterizedRed + floor(errorCorrection * red)
bufferStartPointer[writableAreaStartIndex + 1] = posterizedGreen + floor(errorCorrection * green)
bufferStartPointer[writableAreaStartIndex + 2] = posterizedBlue + floor(errorCorrection * blue)
bufferStartPointer[writableAreaStartIndex + 3] = posterizedAlpha + floor(errorCorrection * alpha)

numBytesWritten = numBytesWritten + 4
end
Expand Down
12 changes: 10 additions & 2 deletions Tests/NativeClient/WebGPU/Texture.spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,18 @@ describe("Texture", function()
it("should reduce the color depth of the texture image", function()
local testImage = "\255\192\128\000" .. "\007\007\007\007"
local reducedColorImage, width, height = Texture:CreateReducedColorImage(testImage, 2, 1)
local expectedimageBytes = "\248\192\128\000\000\000\000\000"
local expectedImageBytes = buffer.new():put("\255\198\132\000\000\000\000\000")
assertEquals(width, 2)
assertEquals(height, 1)
assertEquals(tostring(reducedColorImage), expectedimageBytes)
assertEquals(reducedColorImage[0], expectedImageBytes[0])
assertEquals(reducedColorImage[1], expectedImageBytes[1])
assertEquals(reducedColorImage[2], expectedImageBytes[2])
assertEquals(reducedColorImage[3], expectedImageBytes[3])
assertEquals(reducedColorImage[4], expectedImageBytes[4])
assertEquals(reducedColorImage[5], expectedImageBytes[5])
assertEquals(reducedColorImage[6], expectedImageBytes[6])
assertEquals(reducedColorImage[7], expectedImageBytes[7])
assertEquals(tostring(reducedColorImage), tostring(expectedImageBytes))
end)
end)
end)

0 comments on commit 0be1251

Please sign in to comment.