Page 1 of 1
Heightmap texture saving issue
Posted: 14 Apr 2015, 12:08
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).
Re: Heightmap texture saving issue
Posted: 14 Apr 2015, 19:44
by Kloot
$heightmap is an fp32 luminance texture, not RGB.
Re: Heightmap texture saving issue
Posted: 14 Apr 2015, 22:36
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.
Re: Heightmap texture saving issue
Posted: 15 Apr 2015, 03:20
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).

Re: Heightmap texture saving issue
Posted: 15 Apr 2015, 03:48
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
Re: Heightmap texture saving issue
Posted: 15 Apr 2015, 17:13
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
Re: Heightmap texture saving issue
Posted: 15 Apr 2015, 17:58
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)
Re: Heightmap texture saving issue
Posted: 15 Apr 2015, 22:04
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
Re: Heightmap texture saving issue
Posted: 16 Apr 2015, 07:30
by gajop
Yey, thanks!
Although I'm using slightly different code, I can confirm I'm getting 16bit greyscale pngs with {grayscale16bit = true} .
Re: Heightmap texture saving issue
Posted: 16 Apr 2015, 08:33
by Silentwings
Nice work.