regarding the heightmap

blert2112
Member
 
Posts: 244
Joined: Sat Apr 25, 2015 04:05
GitHub: blert2112

regarding the heightmap

by blert2112 » Fri Feb 26, 2016 04:47

Can somebody shed some light on the MapGen object: heightmap?
Consider the following code:
Code: Select all
cid_diamond  = core.get_content_id("default:diamondblock")

core.register_on_generated(function(minp, maxp, seed)

   -- get mapgen objects
   local hm = core.get_mapgen_object("heightmap")
   local vm, emin, emax = core.get_mapgen_object("voxelmanip")
   local vm_area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
   local vm_data = vm:get_data()

   -- get a random position
   local index3d = 0
   do
      local p1 = {
         x = math.random(minp.x,maxp.x),
         y = 0,
         z = math.random(minp.z,maxp.z)
      }

      -- returns the height based on height map
      local chunksize = maxp.x - minp.x + 1
      local index2d = (p1.z - minp.z) * chunksize + (p1.x - minp.x) + 1
   --[[
      local index2d = 0
      for i = minp.x, maxp.x do
         local br = false
         for j = minp.z, maxp.z do
            index2d = index2d + 1
            if (i == p1.x) and (j == p1.z) then
               br = true
               break
            end
         end
         if br == true then break end
      end
   ]]

      p1.y = hm[index2d]
      index3d = vm_area:indexp(p1)

      print(core.pos_to_string(p1))
   end

   vm_data[index3d] = cid_diamond

   vm:set_data(vm_data)
   vm:write_to_map()
end)

No matter if using the mathematical method of finding the index or the (commented) count method, more often than not the position is not on the ground. The mathematical method seems to work better, but still, more often than not if I teleport to the position I am many nodes above or below the ground. There has to be something I am missing or something is wrong with my code. Anybody have any ideas?

edit:
Seem to have found a slight error in the math. The line...
Code: Select all
local index2d = (p1.z - minp.z) * chunksize + (p1.x - minp.x) + 1

...should be...
Code: Select all
local index2d = (p1.z - minp.z) * chunksize + (p1.x - minp.x)

..I think. The "+ 1" was adding an extra 80 to the index. It is still not anywhere close to right all the time but it is much closer than before and I think I can force it with a little node checking. Still, it would be nice to have an extra set of eyes on this and tell what is going wrong.
Last edited by blert2112 on Fri Feb 26, 2016 05:32, edited 1 time in total.
 

User avatar
duane
Member
 
Posts: 1597
Joined: Wed Aug 19, 2015 19:11
Location: Oklahoma City
GitHub: duane-r

Re: regarding the heightmap

by duane » Fri Feb 26, 2016 05:30

blert2112 wrote:Can somebody shed some light on the MapGen object: heightmap?
Consider the following code:
Code: Select all
cid_diamond  = core.get_content_id("default:diamondblock")

core.register_on_generated(function(minp, maxp, seed)

   -- get mapgen objects
   local hm = core.get_mapgen_object("heightmap")
   local vm, emin, emax = core.get_mapgen_object("voxelmanip")
   local vm_area = VoxelArea:new({MinEdge = emin, MaxEdge = emax})
   local vm_data = vm:get_data()

   -- get a random position
   local index3d = 0
   do
      local p1 = {
         x = math.random(minp.x,maxp.x),
         y = 0,
         z = math.random(minp.z,maxp.z)
      }

      -- returns the height based on height map
      local chunksize = maxp.x - minp.x + 1
      local index2d = (p1.z - minp.z) * chunksize + (p1.x - minp.x) + 1
   --[[
      local index2d = 0
      for i = minp.x, maxp.x do
         local br = false
         for j = minp.z, maxp.z do
            index2d = index2d + 1
            if (i == p1.x) and (j == p1.z) then
               br = true
               break
            end
         end
         if br == true then break end
      end
   ]]

      p1.y = hm[index2d]
      index3d = vm_area:indexp(p1)

      print(core.pos_to_string(p1))
   end

   vm_data[index3d] = cid_diamond

   vm:set_data(vm_data)
   vm:write_to_map()
end)

No matter if using the mathematical method of finding the index or the (commented) count method, more often than not the position is not on the ground. The mathematical method seems to work better, but still, more often than not if I teleport to the position I am many nodes above or below the ground. There has to be something I am missing or something is wrong with my code. Anybody have any ideas?


If you're using valleys, the reason has to do with this part of the generateTerrain method.

Code: Select all
      // This happens if we're generating a block that doesn't
      // contain the terrain surface, in which case, an
      // approximation should be good enough.
      if (heightmap[index_2d] == -MAX_MAP_GENERATION_LIMIT)
         heightmap[index_2d] = myround(surface_y);


Surface height is determined by a 3D noise (inter-valley fill), which allows overhangs and tunnels to be generated. The way valleys (C and lua) gets the actual ground level is to run through a series of possible altitudes and compare their y value to each noise value at that position. When the numbers compare right, we have the ground level.

This causes problems for heightmap. The estimated terrain level is given by surface_y, but the actual terrain level is usually different. If it's not in the chunk being generated, no actual terrain level is available to generateTerrain. So, we fall back to the method used when the chunk is up in the air or underground -- we store surface_y as an approximation.

Unfortunately, lua code has no way to tell if the number it's getting is a real value or the estimate. I'm very unhappy about that, and I've been trying to think of a better way to go about it. I considered passing -31000 instead, but it's probably more useful to most mods to get something in the neighborhood of ground level than no information at all.

To get the index for heightmap, just loop x inside z and add one to the index each time x counts. (I hope you didn't copy your loops from valleys_c. It was wrong until very recently.) That gives you the correct entry from heightmap, which may still be wrong.

Code: Select all
   for z = minp.z, maxp.z do
      for x = minp.x, maxp.x do
         index_2d = index_2d + 1


Edit: I removed some comments that weren't very helpful.
Believe in people and you don't need to believe anything else.
 

blert2112
Member
 
Posts: 244
Joined: Sat Apr 25, 2015 04:05
GitHub: blert2112

Re: regarding the heightmap

by blert2112 » Fri Feb 26, 2016 05:47

I see. That would explain why v7 is more consistent with the heightmap, but still not anywhere close to 100%. Looping was way off for me, though I am looping z inside of x and then adding. Don't see why it should matter but I will swap them and see what happens.
After I removed the "+ 1" from the math in my above code it works almost reliably in v7 and does a fair job in valleys so I should be able to avoid looping altogether. I will test both and see which is faster and more reliable.

edit:
Heh, I guess it does matter. Looping z inside x gave me bad results, x inside z works comparably to the mathematical formula. Guess that fixed my problem. Thanks for your help. Now on to speed testing to see which method to use and then work on node checking.
 

User avatar
duane
Member
 
Posts: 1597
Joined: Wed Aug 19, 2015 19:11
Location: Oklahoma City
GitHub: duane-r

Re: regarding the heightmap

by duane » Fri Feb 26, 2016 13:10

It finally occurred to me that all I have to do to avoid most of the heightmap issues is give an approximation that's always outside of the chunk when the actual terrain must be outside (rather than using surface_y when it's obviously wrong). If the heightmap value is outside of the chunk you're working with, you're less likely to need the exact number. It's not perfect, but it doesn't require enough extra cpu time to matter.

Edit: Of course you'll still have issues with caves and dungeons, since they're generated after the heightmap.
Believe in people and you don't need to believe anything else.
 


Return to Modding Discussion



Who is online

Users browsing this forum: No registered users and 3 guests