Heightmap texture saving issue

Heightmap texture saving issue

Discuss Lua based Spring scripts (LuaUI widgets, mission scripts, gaia scripts, mod-rules scripts, scripted keybindings, etc...)

Moderators: Moderators, Moderators

Post Reply
gajop
Moderator
Posts: 3026
Joined: 05 Aug 2009, 20:42

Heightmap texture saving issue

Post by gajop »

My heightmap texture saving code is as follows:

Code: Select all

        local heightmapTexture = "heightmap.png"
        local texInfo = gl.TextureInfo("$heightmap")
        local heightmapTexture = gl.CreateTexture(texInfo.xsize, texInfo.ysize, {
            border = false,
            min_filter = GL.LINEAR,
            mag_filter = GL.LINEAR,
            wrap_s = GL.CLAMP_TO_EDGE,
            wrap_t = GL.CLAMP_TO_EDGE,
            fbo = true,
        })

        gl.Texture("$heightmap")
        gl.RenderToTexture(heightmapTexture,
        function()
            gl.TexRect(-1,-1, 1, 1)
        end)
        gl.Texture(false)

        gl.RenderToTexture(heightmapTexture, gl.SaveImage, 0, 0, texInfo.xsize, texInfo.ysize, heightmapPath)
        gl.DeleteTexture(heightmapTexture)
It doesn't produce the correct heightmap. It's often black and white (with no greyscale), and obvious features aren't included (like not having any mountains sometimes).
I can post concrete examples when I get home, but the issue might be clear from the code.
PS: I can save the diffuse or minimap just fine. (grass is borked, but also a different issue).
0 x

Kloot
Spring Developer
Posts: 1865
Joined: 08 Oct 2006, 16:58

Re: Heightmap texture saving issue

Post by Kloot »

$heightmap is an fp32 luminance texture, not RGB.
0 x

User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Heightmap texture saving issue

Post by jK »

https://github.com/spring/spring/commit ... df0999ca55

+

dev_saveheightmap.lua:

Code: Select all

function widget:GetInfo()
   return {
      name      = "HeightMap To BMP32",
      desc      = "Saves current heightmap to heightmap.bmp",
      author    = "jK",
      version   = "0",
      date      = "2015",
      license   = "GPLv2",
      layer     = 1,
      enabled   = false,
   }
end

--// note: DevIL does not support 32bit PNGs!
local heightmapPath = "heightmap.bmp"
local GL_LUMINANCE32F_ARB = 0x8818

function widget:DrawGenesis()
	local texInfo = gl.TextureInfo("$heightmap")
	local heightmapTexture = gl.CreateTexture(texInfo.xsize, texInfo.ysize, {
		format = GL_LUMINANCE32F_ARB,
		border = false,
		min_filter = GL.NEAREST,
		mag_filter = GL.NEAREST,
		wrap_s = GL.CLAMP_TO_EDGE,
		wrap_t = GL.CLAMP_TO_EDGE
	})

	local fbo = gl.CreateFBO{color0 = heightmapTexture}

	local saved = false
	if gl.IsValidFBO(fbo) then
		gl.ActiveFBO(fbo, function()
			gl.Texture("$heightmap")
			gl.TexRect(-1, -1, 1, 1)
			gl.Texture(false)
			saved = gl.SaveImage(0, 0, texInfo.xsize, texInfo.ysize, heightmapPath, {float = true})
		end)
	end

	if saved then
		Spring.Log(widget:GetInfo().name, "info",  ("Saved HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	else
		Spring.Log(widget:GetInfo().name, "error", ("Couldn't save HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	end

	gl.DeleteFBO(fbo)
	gl.DeleteTexture(heightmapTexture)
	widgetHandler:RemoveWidget()
end
Edit: after checking the resulted file with gimp, I hardly think it is really a 32bit bmp. Tried also .exr & .hdr, at least the return something (in contrast to .png), but I don't got a tool to open them to see if they are 32bit.
0 x

gajop
Moderator
Posts: 3026
Joined: 05 Aug 2009, 20:42

Re: Heightmap texture saving issue

Post by gajop »

Kloot wrote:$heightmap is an fp32 luminance texture, not RGB.
Oh. Well if I can export it in something meaningful I can probably use imagemagick to convert it to the desired format.
jK wrote:https://github.com/spring/spring/commit ... df0999ca55

+

dev_saveheightmap.lua:

Code: Select all

function widget:GetInfo()
   return {
      name      = "HeightMap To BMP32",
      desc      = "Saves current heightmap to heightmap.bmp",
      author    = "jK",
      version   = "0",
      date      = "2015",
      license   = "GPLv2",
      layer     = 1,
      enabled   = false,
   }
end

--// note: DevIL does not support 32bit PNGs!
local heightmapPath = "heightmap.bmp"
local GL_LUMINANCE32F_ARB = 0x8818

function widget:DrawGenesis()
	local texInfo = gl.TextureInfo("$heightmap")
	local heightmapTexture = gl.CreateTexture(texInfo.xsize, texInfo.ysize, {
		format = GL_LUMINANCE32F_ARB,
		border = false,
		min_filter = GL.NEAREST,
		mag_filter = GL.NEAREST,
		wrap_s = GL.CLAMP_TO_EDGE,
		wrap_t = GL.CLAMP_TO_EDGE
	})

	local fbo = gl.CreateFBO{color0 = heightmapTexture}

	local saved = false
	if gl.IsValidFBO(fbo) then
		gl.ActiveFBO(fbo, function()
			gl.Texture("$heightmap")
			gl.TexRect(-1, -1, 1, 1)
			gl.Texture(false)
			saved = gl.SaveImage(0, 0, texInfo.xsize, texInfo.ysize, heightmapPath, {float = true})
		end)
	end

	if saved then
		Spring.Log(widget:GetInfo().name, "info",  ("Saved HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	else
		Spring.Log(widget:GetInfo().name, "error", ("Couldn't save HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	end

	gl.DeleteFBO(fbo)
	gl.DeleteTexture(heightmapTexture)
	widgetHandler:RemoveWidget()
end
Edit: after checking the resulted file with gimp, I hardly think it is really a 32bit bmp. Tried also .exr & .hdr, at least the return something (in contrast to .png), but I don't got a tool to open them to see if they are 32bit.
My old code gives me this:
[f=0000510] Saving the heightmap to projects/brownwood-test/heightmap.png...
*** Error in `./spring': malloc(): memory corruption: 0x0000000019ab62d0 ***

Using the original code with {float=true} has the same effect.

I suspect this might be an issue: https://github.com/spring/spring/commit ... b7fa28L388 (there's no 4* multiplication, but not really sure)

Using your code doesn't crash things, but the result is something odd. It's definitely wrong, since I can see UI elements in the heightmap image that were probably incorrectly exported due to some memory allocation issue. (Added image below, you can see folders/labels in it).
Image
0 x

User avatar
enetheru
Posts: 627
Joined: 11 Jun 2010, 07:32

Re: Heightmap texture saving issue

Post by enetheru »

jK wrote:Edit: after checking the resulted file with gimp, I hardly think it is really a 32bit bmp. Tried also .exr & .hdr, at least the return something (in contrast to .png), but I don't got a tool to open them to see if they are 32bit.
https://launchpad.net/~otto-kesselgulas ... /gimp-edge
gimp-edge is the bleeding edge repo that supports high bit depth images

https://sites.google.com/site/openimageio/home
I use OpenImageIO and tools to test image formats/convert etc

i cant stand imagemagick
0 x

User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Heightmap texture saving issue

Post by jK »

@gajop seems some gl states differ in your enviroment, appended a version that explicit sets some states:

Code: Select all

function widget:GetInfo()
   return {
      name      = "HeightMap To BMP32",
      desc      = "Saves current heightmap to heightmap.bmp",
      author    = "jK",
      version   = "1",
      date      = "2015",
      license   = "GPLv2",
      layer     = 1,
      enabled   = false,
   }
end

--// note: DevIL does not support 32bit PNGs!
local heightmapPath = "heightmap.bmp"
local GL_LUMINANCE32F_ARB = 0x8818

function widget:DrawGenesis()
	local texInfo = gl.TextureInfo("$heightmap")
	local heightmapTexture = gl.CreateTexture(texInfo.xsize, texInfo.ysize, {
		format = GL_LUMINANCE32F_ARB,
		border = false,
		min_filter = GL.NEAREST,
		mag_filter = GL.NEAREST,
		wrap_s = GL.CLAMP_TO_EDGE,
		wrap_t = GL.CLAMP_TO_EDGE
	})

	local fbo = gl.CreateFBO{color0 = heightmapTexture}

	local saved = false
	if gl.IsValidFBO(fbo) then
		gl.ActiveFBO(fbo, function()
			gl.DepthTest(false)
			gl.Blending(false)
			gl.Texture("$heightmap")
			gl.TexRect(-1, -1, 1, 1)
			gl.Texture(false)
			saved = gl.SaveImage(0, 0, texInfo.xsize, texInfo.ysize, heightmapPath, {float = true})
		end)
	end

	if saved then
		Spring.Log(widget:GetInfo().name, "info",  ("Saved HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	else
		Spring.Log(widget:GetInfo().name, "error", ("Couldn't save HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	end

	gl.DeleteFBO(fbo)
	gl.DeleteTexture(heightmapTexture)
	widgetHandler:RemoveWidget()
end
0 x

gajop
Moderator
Posts: 3026
Joined: 05 Aug 2009, 20:42

Re: Heightmap texture saving issue

Post by gajop »

A slightly different approach (sorta seems to work for me).
The idea is to use shaders to rescale the heightmap into a (0,1) range

Code: Select all

            local heightmapScaleShader = [[
                uniform sampler2D heightmapTex;
                uniform float maxPos, maxNeg;
                void main() {
                    gl_FragColor = texture2D(heightmapTex, gl_TexCoord[0].st);
                    gl_FragColor.rgb = (gl_FragColor.rgb - maxNeg) / (maxPos - maxNeg);
                }
            ]]

            local shader = gl.CreateShader({ fragment = heightmapScaleShader, uniformInt = {heightmapTexID = 0 }})
            local errors = gl.GetShaderLog(shader)
            if errors ~= "" then
                Spring.Echo(errors)
            end
            local heightmapTexID = gl.GetUniformLocation(shader, "heightmapTex")
            local maxPosID       = gl.GetUniformLocation(shader, "maxPos")
            local maxNegID       = gl.GetUniformLocation(shader, "maxNeg")

        -- heightmap
        local heightmapPath = self.path .. "/heightmap.png"

        Spring.Echo("Saving the heightmap to " .. heightmapPath .. "...")

        if VFS.FileExists(heightmapPath, VFS.RAW) then
            Spring.Echo("removing the existing heightmap")
            os.remove(heightmapPath)
        end

        local texInfo = gl.TextureInfo("$heightmap")
        local heightmapTexture = gl.CreateTexture(texInfo.xsize, texInfo.ysize, {
            border = false,
            min_filter = GL.NEAREST,
            mag_filter = GL.NEAREST,
            wrap_s = GL.CLAMP_TO_EDGE,
            wrap_t = GL.CLAMP_TO_EDGE,
            fbo = true,
        })

        -- not used, seem incorrect
        local minHeight, maxHeight = Spring.GetGroundExtremes()
        Spring.Echo(maxHeight, minHeight)

        local maxH, minH = -math.huge, math.huge
        for x = 0, Game.mapSizeX, Game.squareSize do
            for z = 0, Game.mapSizeZ, Game.squareSize do
                local groundHeight = Spring.GetGroundHeight(x, z)
                if groundHeight > maxH then
                    maxH = groundHeight
                end
                if groundHeight < minH then
                    minH = groundHeight
                end
            end
        end
        Spring.Echo(minH, maxH)

        gl.UseShader(shader)
        gl.Uniform(maxPosID, maxH)
        gl.Uniform(maxNegID, minH)
        gl.Texture(0, "$heightmap")
        gl.RenderToTexture(heightmapTexture,
        function()
            gl.TexRect(-1,-1, 1, 1)
        end)
        gl.Texture(0, false)
        gl.UseShader(0)

        gl.RenderToTexture(heightmapTexture, gl.SaveImage, 0, 0, texInfo.xsize, texInfo.ysize, heightmapPath)
        gl.DeleteTexture(heightmapTexture)
Resulting heightmap attached (looks correctish)
heightmap.png
(100.38 KiB) Not downloaded yet
0 x

User avatar
jK
Spring Developer
Posts: 2299
Joined: 28 Jun 2007, 07:30

Re: Heightmap texture saving issue

Post by jK »

<_< >_>
Found a way to make DevIL build a 16bit grayscale PNG

commit: https://github.com/spring/spring/commit ... c39788b71b

updated widget:

Code: Select all

function widget:GetInfo()
   return {
      name      = "HeightMap To PNG16",
      desc      = "Saves current heightmap to heightmap.png",
      author    = "jK",
      version   = "2",
      date      = "2015",
      license   = "GPLv2",
      layer     = 1,
      enabled   = false,
   }
end

local heightmapPath = "heightmap.png"
local GL_LUMINANCE32F_ARB = 0x8818

function widget:DrawGenesis()
	local texInfo = gl.TextureInfo("$heightmap")
	local heightmapTexture = gl.CreateTexture(texInfo.xsize, texInfo.ysize, {
		format = GL_LUMINANCE32F_ARB,
		border = false,
		min_filter = GL.NEAREST,
		mag_filter = GL.NEAREST,
		wrap_s = GL.CLAMP_TO_EDGE,
		wrap_t = GL.CLAMP_TO_EDGE
	})

	local fbo = gl.CreateFBO{color0 = heightmapTexture}

	local heightmapScaleShader = [[
		uniform sampler2D heightmapTex;
		uniform float groundMin, groundMax;
		void main() {
			gl_FragColor = texture2D(heightmapTex, gl_TexCoord[0].st);
			gl_FragColor.rgb = (gl_FragColor.rgb - groundMin) / (groundMax - groundMin);
		}
	]]

	local gmin, gmax = Spring.GetGroundExtremes()
	local shader = gl.CreateShader{
		fragment = heightmapScaleShader,
		uniformInt = { heightmapTex = 0 },
		uniformFloat = { groundMin = gmin, groundMax = gmax }
	}

	local saved = false
	if gl.IsValidFBO(fbo) and (gl.GetShaderLog(shader) == "") then
		gl.ActiveShader(shader, gl.ActiveFBO, fbo, function()
			gl.DepthTest(false)
			gl.Blending(false)
			gl.Texture("$heightmap")
			gl.TexRect(-1, -1, 1, 1)
			gl.Texture(false)
			saved = gl.SaveImage(0, 0, texInfo.xsize, texInfo.ysize, heightmapPath, {grayscale16bit = true})
		end)
	end

	if saved then
		Spring.Log(widget:GetInfo().name, "notice",  ("Saved HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	else
		Spring.Log(widget:GetInfo().name, "error",   ("Couldn't save HeightMap to \"%s\" (%ix%i)"):format(heightmapPath, texInfo.xsize, texInfo.ysize))
	end

	gl.DeleteFBO(fbo)
	gl.DeleteTexture(heightmapTexture)
	widgetHandler:RemoveWidget()
end
edit: example
Image
heightmap.png
(862.9 KiB) Not downloaded yet
0 x

gajop
Moderator
Posts: 3026
Joined: 05 Aug 2009, 20:42

Re: Heightmap texture saving issue

Post by gajop »

Yey, thanks!
Although I'm using slightly different code, I can confirm I'm getting 16bit greyscale pngs with {grayscale16bit = true} .
0 x

User avatar
Silentwings
Moderator
Posts: 3618
Joined: 25 Oct 2008, 00:23

Re: Heightmap texture saving issue

Post by Silentwings »

Nice work.
0 x

Post Reply

Return to “Lua Scripts”