LDraw.org Discussion Forums

Full Version: Heightmap to brick converter?
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Does anyone know of any heightmap to LDraw brick converters? I know MLCad can create fractal terrain, but I could have sworn someone had written a converter at some point. Thanks.
Thanks! But, there seems to be a limit on the "max size" a model can be. Not sure how to get around that.
(2015-08-14, 10:28)Michael Horvath Wrote: [ -> ]Does anyone know of any heightmap to LDraw brick converters? I know MLCad can create fractal terrain, but I could have sworn someone had written a converter at some point. Thanks.

Hello,

An old post, new reply.
I am currently looking for the same.

Digging LDraw history (http://www.ldraw.org/community/history/), I found Jacob Sparre Anderson made a Fractal Landscape Editor way back in 1997.
I even found some code on Github referencing to it: https://github.com/sparre/LEGO-tools

I wrote a basic Excel sheet that can generate a `landscape` on a 16x16 baseplate using 1x1 plates and bricks with a maximum height of one brick.
So that is either 1 plate, 2 plates or 1 brick.

Not nearly what I am looking for or what Michael meant.

Does anyone have an idea or tool that can do this?
Could MLCad's code be used?
I am no programmer, but it seems the basics have been made, but unfortunately never worked out further.

Another idea would be using a mosaic generator of which there are quite a few of that can make LDraw files.
But then you have no height, but somehow the color could determine this.
Just some thoughts...
(2015-08-15, 5:21)Michael Horvath Wrote: [ -> ]Thanks! But, there seems to be a limit on the "max size" a model can be. Not sure how to get around that.
What area (in studs/baseplates) are you talking about? 

Do you want to import a greyscale image that represents a height map?
(2018-06-18, 13:40)Gerald Lasser Wrote: [ -> ]
(2015-08-15, 5:21)Michael Horvath Wrote: [ -> ]Thanks! But, there seems to be a limit on the "max size" a model can be. Not sure how to get around that.
What area (in studs/baseplates) are you talking about? 

Do you want to import a greyscale image that represents a height map?

My project is based on x and z coordinates of dots in a grid that have a certain height.
The source would be an excel file.
What I am looking for is a way to translate that, using 1x1 plates and bricks laying out a mosaic like "terrain".

What I can make now is this:
A dot at point x,z at height 1 translates to a 1x1 plate
A dot at height 2  translates to two stacked 1x1 plates
A dot at height 3 translates to a 1x1 brick


The next step I want to make is to be able to calculate the stack at any height.
So a dot at height 4 is a brick and one plate stacked
A dot at height 5 is a brick and two plates stacked
Height 6 is 2 bricks
Height 7 is 2 bricks and one plate
And so forth.

No idea so far how to do that.
Any thoughts. Undecided Huh
(2018-06-18, 20:14)Jaco van der Molen Wrote: [ -> ]No idea so far how to do that.
Any thoughts. Undecided Huh

If you can somehow generate a lua variable definition with excel.

Then you can do the actual generating of the model in LDCad using a macro. All you would need is the x/z values in an array.

For an 3x3 grid you would need something like this:

Code:
local depthMap={ {0, 1, 2}, {4, 5, 6}, {7, 8, 9} }

You use that in a macro run event like so:

Code:
function renDepthGen()

 local sf=ldc.subfile()
 if not sf:isLinked() then
   ldc.dialog.runMessage('No active session')
   return
 end
 
 local sel=ldc.selection()
 sel:remove()

 local depthMap={
   {0, 1, 2},
   {4, 5, 6},
   {7, 8, 9}
 }
 
 local h=genTools.tableArrayCount(depthMap)
 local w=genTools.tableArrayCount(depthMap[1])
 
 for x=1,w do
   for z=1,h do
     local v=depthMap[z][x]
     
     local v1=v // 3
     local v2=v % 3
   
     local xx=(x-1)*20
     local zz=(z-1)*20
     local yy=0
     
     for b=1,v1  do
       yy=yy-24
       sel:add(sf:addNewRef('3005.dat', 4, ldc.matrix(xx, yy, zz)))      
     end
     
     for p=1,v2 do
       yy=yy-8
       sel:add(sf:addNewRef('3024.dat', 4, ldc.matrix(xx, yy, zz)))
     end
     
   end
 end
end

Which would give you:
[attachment=3196]
(2018-06-18, 20:56)NRoland Melkert Wrote: [ -> ]
(2018-06-18, 20:14)Jaco van der Molen Wrote: [ -> ]No idea so far how to do that.
Any thoughts. Undecided Huh

If you can somehow generate a lua variable definition with excel.

Then you can do the actual generating of the model in LDCad using a macro. All you would need is the x/z values in an array.

For an 3x3 grid you would need something like this:

Code:
local depthMap={ {0, 1, 2}, {4, 5, 6}, {7, 8, 9} }

You use that in a macro run event like so:

Code:
function renDepthGen()

 local sf=ldc.subfile()
 if not sf:isLinked() then
   ldc.dialog.runMessage('No active session')
   return
 end
 
 local sel=ldc.selection()
 sel:remove()

 local depthMap={
   {0, 1, 2},
   {4, 5, 6},
   {7, 8, 9}
 }
 
 local h=genTools.tableArrayCount(depthMap)
 local w=genTools.tableArrayCount(depthMap[1])
 
 for x=1,w do
   for z=1,h do
     local v=depthMap[z][x]
     
     local v1=v // 3
     local v2=v % 3
   
     local xx=(x-1)*20
     local zz=(z-1)*20
     local yy=0
     
     for b=1,v1  do
       yy=yy-24
       sel:add(sf:addNewRef('3005.dat', 4, ldc.matrix(xx, yy, zz)))      
     end
     
     for p=1,v2 do
       yy=yy-8
       sel:add(sf:addNewRef('3024.dat', 4, ldc.matrix(xx, yy, zz)))
     end
     
   end
 end
end

Which would give you:

Ah! Ok, I see. That is exactly what I meant!
My excel source can make the depth map, I understand how it works.
For a 16 by 16 baseplate you have 16 arrays with each 16 values.
Now if you can incorporate the color of the column too, I am there.
(2018-06-18, 21:10)Jaco van der Molen Wrote: [ -> ]Ah! Ok, I see. That is exactly what I meant!
My excel source can make the depth map, I understand how it works.
For a 16 by 16 baseplate you have 16 arrays with each 16 values.
Now if you can incorporate the color of the column too, I am there.
You could choose between green and blue (instead of the constant red) depending on the height of 'yy' to mimic above/below sea level. Or do you want the whole column to vary in color depending on an excel variable?

edit, like so:

replcace the '4' in the addNewRef lines with
Code:
genTools.IF(yy<seaLevel, 2, 1)

and add e.g.
Code:
local seaLevel=-24
above the main w/h loop.

ps: as you'll probably notice soon the script needs
Code:
local genTools=require('genTools')
at the top of the .lua file.
OK, got it to work smoothly. Very powerful.
Now for the color.

Got it.


I added (example)
 
Code:
local colorMap={
  { 1,  2,  3,  4 },
  { 5,  6,  7,  8 },
  { 9, 10, 11, 12 }
 }

and

Code:
local c=colorMap[z][x]

(right after local v=depthMap[z][x]

changed the hard coded color in this line to variable c:


Code:
sel:add(sf:addNewRef('3005.dat', c, ldc.matrix(xx, yy, zz)))     



I tried to implement it, but no succes.
Would that work?
With many thanks to Roland, here is an example of a complete script to generate a kind of landscape with a "height map" from Excel.
Excel source and LDraw file attached.

Result:
[attachment=3198]

Script saved as generate.lua and put in folder C:\Users\[user]\AppData\Roaming\LDCad 1.6b\scripts\default\global



Code:
local genTools=require('genTools')

function heightGen()

 local sf=ldc.subfile()
 if not sf:isLinked() then
   ldc.dialog.runMessage('No active session')
   return
 end
 
 local sel=ldc.selection()
 sel:remove()

 local depthMap={
{1,1,2,2,3,2,2,1,1},
  {1,1,2,3,3,3,2,1,1},
  {2,2,3,4,4,4,3,2,2},
  {2,3,4,4,5,4,4,3,2},
  {3,3,4,5,6,5,4,3,3},
  {2,3,4,4,5,4,4,3,2},
  {2,2,3,4,4,4,3,2,2},
  {1,1,2,3,3,3,2,1,1},
  {1,1,2,2,3,2,2,1,1}
 }

 local colorMap={
{1,1,2,2,3,2,2,1,1},
  {1,1,2,3,3,3,2,1,1},
  {2,2,3,4,4,4,3,2,2},
  {2,3,4,4,5,4,4,3,2},
  {3,3,4,5,6,5,4,3,3},
  {2,3,4,4,5,4,4,3,2},
  {2,2,3,4,4,4,3,2,2},
  {1,1,2,3,3,3,2,1,1},
  {1,1,2,2,3,2,2,1,1}
 }

 local h=genTools.tableArrayCount(depthMap)
 local w=genTools.tableArrayCount(depthMap[1])

 for x=1,w do
   for z=1,h do
     local v=depthMap[z][x]
     local c=colorMap[z][x]

     local v1=v // 3
     local v2=v % 3
   
     local xx=(x-1)*20
     local zz=(z-1)*20
     local yy=0
     
     for b=1,v1  do
       yy=yy-24
       sel:add(sf:addNewRef('3005.dat', c, ldc.matrix(xx, yy, zz)))      
     end
     
     for p=1,v2 do
       yy=yy-8
       sel:add(sf:addNewRef('3024.dat', c, ldc.matrix(xx, yy, zz)))
     end
     
   end
 end
end

function register()

  local macro=ldc.macro('Gen Heightmap')
  macro:setHint('Generate terrain from heightmap')
  macro:setEvent('run', 'heightGen')

end

register()
(2018-06-19, 13:28)Jaco van der Molen Wrote: [ -> ]With many thanks to Roland, here is an example of a complete script to generate a kind of landscape with a "height map" from Excel.
Excel source and LDraw file attached.

Fun Smile

I was playing around with actual landscape generating last night using a "Diamond square algorithm" lua module I found somewhere.
Unfortunately it was too slow (due to the hard coded max script run time) to generate any real sized ones.
(2018-06-19, 18:19)Roland Melkert Wrote: [ -> ]
(2018-06-19, 13:28)Jaco van der Molen Wrote: [ -> ]With many thanks to Roland, here is an example of a complete script to generate a kind of landscape with a "height map" from Excel.
Excel source and LDraw file attached.

Fun Smile

I was playing around with actual landscape generating last night using a "Diamond square algorithm" lua module I found somewhere.
Unfortunately it was too slow (due to the hard coded max script run time) to generate any real sized ones.

Oh, I see. Very interesting. I know the Diamond square algorithm is used in games for example to create terrain.
I found a post on Stackoverflow how to make a Diamond square algorithm output to excel, but it doesn't work properly.
If we could somehow get a Diamond square algorithm to work in excel and it outputs numbers in cells, we could use your script.
Or better still straight in LDCad.

I have a few thoughts on this and what it should be able to do, but alas I am not a programmer so no idea how to make it.

My idea is as follows:
  • Modify the script to use only 1x1 plates
  • Be able to set user prefs like set up dimensions in baseplate format 16x16, 32x32 or 48x48
  • Set up colors corresponding to plate height for terrain
    Ie. very global 0 = blue water, 1 = tan sand, 2 = bright green gras, 3 = green trees, 4 = DBG hill, 5 = LBG mountain, 6 = whith snow top
Then
  • Using the Diamond square algorithm create output in Excel or straight in LDCad (?) to fill the height array
  • Generate the LDraw model
That would be awesome.
(2018-06-20, 10:22)Jaco van der Molen Wrote: [ -> ]Oh, I see. Very interesting. I know the Diamond square algorithm is used in games for example to create terrain.
I found a post on Stackoverflow how to make a Diamond square algorithm output to excel, but it doesn't work properly.
If we could somehow get a Diamond square algorithm to work in excel and it outputs numbers in cells, we could use your script.
Or better still straight in LDCad.

I have a few thoughts on this and what it should be able to do, but alas I am not a programmer so no idea how to make it.

My idea is as follows:
  • Modify the script to use only 1x1 plates
  • Be able to set user prefs like set up dimensions in baseplate format 16x16, 32x32 or 48x48
  • Set up colors corresponding to plate height for terrain
    Ie. very global 0 = blue water, 1 = tan sand, 2 = bright green gras, 3 = green trees, 4 = DBG hill, 5 = LBG mountain, 6 = whith snow top
Then
  • Using the Diamond square algorithm create output in Excel or straight in LDCad (?) to fill the height array
  • Generate the LDraw model
That would be awesome.

Should all be possible directly in LDCad, but with 1.6 the main problem is the 'slowness' of the addNewRef function as it takes ~1ms and currently the maximum runtime of a script is limited to 2000ms. I will remove that limitation in 1.6c though (if ever released, so 2.0 otherwise).
(2018-06-20, 17:18)Roland Melkert Wrote: [ -> ]Should all be possible directly in LDCad, but with 1.6 the main problem is the 'slowness' of the addNewRef function as it takes ~1ms and currently the maximum runtime of a script is limited to 2000ms. I will remove that limitation in 1.6c though (if ever released, so 2.0 otherwise).

OK, so that means the current limit is about 2000 bricks or a bit less?
(2018-06-21, 5:50)Jaco van der Molen Wrote: [ -> ]
(2018-06-20, 17:18)Roland Melkert Wrote: [ -> ]Should all be possible directly in LDCad, but with 1.6 the main problem is the 'slowness' of the addNewRef function as it takes ~1ms and currently the maximum runtime of a script is limited to 2000ms. I will remove that limitation in 1.6c though (if ever released, so 2.0 otherwise).

OK, so that means the current limit is about 2000 bricks or a bit less?

It depends on multiple things, but the bottle neck is clearly the addNewRef.

I compiled a version without the max execution time, and played around with diamond square.

[attachment=3203]

This consists of 36000 bricks and, the script took about 35 seconds.


2.0's scripting environment will be much more suited for these kinds of things as the one in 1.6 is mostly optimized for animations.
(2018-06-21, 22:17)Roland Melkert Wrote: [ -> ]
(2018-06-21, 5:50)Jaco van der Molen Wrote: [ -> ]OK, so that means the current limit is about 2000 bricks or a bit less?

It depends on multiple things, but the bottle neck is clearly the addNewRef.

I compiled a version without the max execution time, and played around with diamond square.



This consists of 36000 bricks and, the script took about 35 seconds.


2.0's scripting environment will be much more suited for these kinds of things as the one in 1.6 is mostly optimized for animations.

Oh wow! That looks stunning already.

I think we can conclude that Michael Horvath's original question is answered:
"Does anyone know of any heightmap to LDraw brick converters?"

The answer is yes, though in development :-)

Do you mind sharing this script? Can I run some tests too on smaller scale?
(2018-06-22, 7:14)Jaco van der Molen Wrote: [ -> ]Do you mind sharing this script? Can I run some tests too on smaller scale?

Attached zip contains two .lua files, put landscape.lua in the global folder and heightmap.lua in the modules folder of %appdata%/LDCad/scripts/default

Also change the
maxExecTime
value to 2000 in main.cfg for the maximum time allowed in 1.6b (instead of the default 250ms)

Using a freshly started new file might be slightly faster as deleted type 1 lines are still kept in memory and thus processed during addNewRef stuff.

On my system it runs at max 64x64 (most of the time) within the 2s limit. It's an older system though, so you might go higher if you have a more recent one.

Look for hMap.create to change the dimensions, (should be powers of 2).
(2018-06-22, 17:39)Roland Melkert Wrote: [ -> ]
(2018-06-22, 7:14)Jaco van der Molen Wrote: [ -> ]Do you mind sharing this script? Can I run some tests too on smaller scale?

Attached zip contains two .lua files, put landscape.lua in the global folder and heightmap.lua in the modules folder of %appdata%/LDCad/scripts/default

Also change the
maxExecTime
value to 2000 in main.cfg for the maximum time allowed in 1.6b (instead of the default 250ms)

Using a freshly started new file might be slightly faster as deleted type 1 lines are still kept in memory and thus processed during addNewRef stuff.

On my system it runs at max 64x64 (most of the time) within the 2s limit. It's an older system though, so you might go higher if you have a more recent one.

Look for hMap.create to change the dimensions, (should be powers of 2).

I get this error:

[string "landscape.lua"]:11: module 'heightmap' not found:
    no field package.preload['heightmap']
    no file 'C:\Users\mj\AppData\Roaming\LDCad 1.6b\scripts\default\global\heightmap.lua'
    no file 'C:\Users\mj\AppData\Roaming\LDCad 1.6b\scripts\default\modules\heightmap.lua'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\heightmap.dll'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\..\lib\lua\5.3\heightmap.dll'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\loadall.dll'
    no file '.\heightmap.dll'
Script main run failed.
(2018-06-25, 12:34)Jaco van der Molen Wrote: [ -> ]I get this error:

[string "landscape.lua"]:11: module 'heightmap' not found:
    no field package.preload['heightmap']
    no file 'C:\Users\mj\AppData\Roaming\LDCad 1.6b\scripts\default\global\heightmap.lua'
    no file 'C:\Users\mj\AppData\Roaming\LDCad 1.6b\scripts\default\modules\heightmap.lua'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\heightmap.dll'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\..\lib\lua\5.3\heightmap.dll'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\loadall.dll'
    no file '.\heightmap.dll'
Script main run failed.
Did you put the loose heightmap.lua file in the global folder and not its whole containing folder.
(2018-06-25, 19:57)Roland Melkert Wrote: [ -> ]
(2018-06-25, 12:34)Jaco van der Molen Wrote: [ -> ]I get this error:

[string "landscape.lua"]:11: module 'heightmap' not found:
    no field package.preload['heightmap']
    no file 'C:\Users\mj\AppData\Roaming\LDCad 1.6b\scripts\default\global\heightmap.lua'
    no file 'C:\Users\mj\AppData\Roaming\LDCad 1.6b\scripts\default\modules\heightmap.lua'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\heightmap.dll'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\..\lib\lua\5.3\heightmap.dll'
    no file 'C:\Program Files (x86)\LDraw\LDCad 1.6b\loadall.dll'
    no file '.\heightmap.dll'
Script main run failed.
Did you put the loose heightmap.lua file in the global folder and not its whole containing folder.

Oops, my mistake. I put the entire folder "heightmap" with heightmap.lua, readme and licence.
It works now, though it still times out on 32x32.
16x16 works fine.

This looks all very promising!

[edit] On another PC 32x32 also works. 48x48 most of the time. 64x64 times out most of the time.
I have also worked with mesh-based terrain where each pixel of the heightfield represents a 640x640 unit area (i.e. a normal baseplate).

Two problems:

1. There are many many steps to get to the final product, using several different software (some I wrote myself).
2. You can't easily edit the mesh inside MLCad, LDCad, etc. Rendering the mesh happens fast if it is a single object. Rendering is very very slow if you load all the triangles as individual sub-parts. If you want to raise or lower a vertex, you have to manually modify every triangle that meets at that vertex.

Here are some instructions:

https://sourceforge.net/p/datsville/wiki...ldMachine/
https://sourceforge.net/p/datsville/wiki...ldsWilbur/

Here are some pictures as well as a download link to the terrain files:

https://forums.ldraw.org/thread-17107.html

This process is not streamlined at all!