Discord
Login
Community
DARK THEME

Why is my code so inefficient?

Trying to simulate terrain generation on a 3D scale but it's just such a frame hog, its also really jittery?

I don't really understand why and I've searched everywhere and I just can't seem to grasp why.

chunk = class
  constructor = function(offsetx, offsetz)
    this.chunkId = 1
    this.ox = offsetx
    this.oz = offsetz
    this.data = []        // storage (3d blocsks)
    this.visibleBlocks = [] // flat list of visible blocks for fast draw
    this.loaded = false
  end
  
  isSolid = function(xi, yi, zi)
    if xi < 1 or yi < 1 or zi < 1 then return false end
    if xi > this.data.length then return false end
    if not this.data[xi] or not this.data[xi][yi] or not this.data[xi][yi][zi] then
      return false
    end
    return true
  end
  
  initialize = function()
    //generate all blocks
    for z = -chunk_size/2 to chunk_size/2
      for x = -chunk_size/2 to chunk_size/2
        local height = min_height + noise.noise2D(x / scale, z / scale) * amplitude
        
        for y = min_height to height
          local xi = x + chunk_size/2 + 1
          local yi = y + 1
          local zi = z + chunk_size/2 + 1
          
          if not this.data[xi] then this.data[xi] = [] end
          if not this.data[xi][yi] then this.data[xi][yi] = [] end
          
          local block = object
            block_type = ""
            position = object
              x = x
              y = y
              z = z
            end
          end
          
          this.data[xi][yi][zi] = block
        end
      end
    end
    
    // mark visble blocks and store in flat list
    for xi = 1 to this.data.length
      if this.data[xi] then
        for yi = 1 to this.data[xi].length
          if this.data[xi][yi] then
            for zi = 1 to this.data[xi][yi].length
              local block = this.data[xi][yi][zi]
              if block then
                if not this.isSolid(xi+1, yi, zi) or
                   not this.isSolid(xi-1, yi, zi) or
                   not this.isSolid(xi, yi+1, zi) or
                   not this.isSolid(xi, yi-1, zi) or
                   not this.isSolid(xi, yi, zi+1) or
                   not this.isSolid(xi, yi, zi-1) then
                  block.draw = true
                  this.visibleBlocks.push(block) // store to access ind raw loop
                end
              end
            end
          end
        end
      end
    end
    
    this.loaded = true
  end
  
  update = function()
    // pass
  end
  
  draw = function()
    if this.loaded then
      // only loop/draw visible blocks
      for block in this.visibleBlocks
        cube(block.position.x, block.position.y, block.position.z)
      end
    end
  end
end

I'm like 90% sure its the for loop in the draw function

  draw = function()
    if this.loaded then
      // only loop/draw visible blocks
      for block in this.visibleBlocks
        cube(block.position.x, block.position.y, block.position.z)
      end
    end
  end

But why does this cause so much lag/fps drops? I've tried reducing it by loading everything in the initialize function THEN drawing it into the draw function and only drawing the surface layer of blocks but that does pretty much nothing.

I'm honestly stumped.

I can only guess how you draw it - but I suspect that you draw every cube with all of it's sides. This can become a massive frame hog, especially when you don't even see those sides.

Lets say the following example:

You have two cubes that are perfectly sitting next to each other, two sides intersecting each other. Looking at the two cubes from an isometric angle, you see three sides of one cube, and another two of the neighboring one. You only see five sides, aka 10 triangles. Most engines only render that much. You can configure unity for example to explicitly still do it, but it stops there. This is called Culling.

In your case however:

You end up drawing all 12 sides, regardless if you can see them or not. Even those that intersect, you end up drawing twice. Once from Cube A, and again from Cube B.

To solve this:

During init, or upon a change in the cubes - where you only change the neighboring cubes due to speed - check all cubes, and where it neighbors, set a flag to not render that side. I can't help you with that unfortunately. Best I can suggest is use the information to write something. You don't neccessarily have to ignore rendering the sides you cannot see, start with just sides that neighbor on other cubes.

The problem is likely what @confusedcatgirl said, which you can solve by implementing face culling. Although you've already implemented ignoring blocks that are completely surrounded by other solid blocks, you're still drawing faces that aren't visible. For example, for a flat plane, face culling would have 6x less faces drawn, and on a plane with a slope of 1 on one axis, it would have 3x less.

Post a reply

Progress

Status

Preview
Cancel
Post
Validate your e-mail address to participate in the community