Any GameObject takes a DrawCall (SOLVED)

Hey there.

Anyone an idea why any GameObject, spawned by factory, takes a drawcall?

What component does the gameobject contain? Is there any other reason why batching breaks, such as use of shader constants with different values?

Also, see this “Draw calls and Defold” post for a good writeup on draw calls and batching, maybe it can give you a hint on what is happening for you. Batching should not break unless the render state needs to be updated.

Hey andreas.

Already know this article. But cant find it actually…

GameObject:

Factories in main.collection:
FR - factories

The simple line to spawn via factory:

factory.create("main:/gamecontrol" .. factories[randomfactory], vmath.vector3(x , y , 0.2), nil, {fac = hash(factories[randomfactory])})

Hmm, what is the script doing? Is it tinting the sprite? How many draw calls do you get when you spawn one instance of the game object and then another? What’s the z-value of the sprite and the label? Are all of the game objects on the same z-value (0.2 if judging by the code)?

No there is no tinting anywhere. Simple spawning.
/EDIT: STOP: lol Sure… in the item (correctly food.script ) each food will tinted more green as more as it becomes rotten :roll_eyes:
I guess this will break the batch. Does the alpha-value also break the batch? Is there a better way to tint/colorize a sprite?
If I use ONE tint-color for ALL items, will that call just ONE draw (meaning. having tons of different tint-values needs tons of drawcalls?)

    if self.clock - self.Timer > 1 then
      --decrease rottentimer
      self.rottenTime = self.rottenTime -1
      -- debug output
      if GLOBAL.debugMode then
        label.set_text("#label", math.floor(self.rottenTime))
      end

      --food rotten?
      if self.rottenTime > 0 then

        self.tint = self.tint - self.rottenSubtract
        sprite.set_constant("#sprite", "tint", vmath.vector4(self.tint, 1, 1, 1))

        if self.rottenTime <= 0 then
          print("FOOD rotten: " .. foods[self.fac]["foodname"] .. " rotten: " .. self.rottenTime .. " tint=" .. self.tint)
          msg.post("main:/gui#gui", "gameinfo", {text = foods[self.fac]["foodname"] .. " is rotten! :("})
          label.set_text("#label", "rotten")
          --GLOBAL.gamestats.points = GLOBAL.gamestats.points - foods[self.fac]["kcal"]/100
          GLOBAL.gamestats.foodrotten = GLOBAL.gamestats.foodrotten +1
        end
      end
      self.Timer = os.clock()
    end
  end

I have to use the Z Value to show the “items” in front of the tilemap.

If I collect an item the DrawCalls decrease by 1 each item.

Every item is stored in a table also to clear up after game ends.

Thats the spawning-script:


    -- get tilemap values
    local lx, ly, lw, lh = tilemap.get_bounds("main:/map#tilemap")
    local tilesize = 32

    print("Levelsize: ", lw, lh)

    -- set max items to spawn
    math.randomseed(os.time() - os.clock() * 1000)
    GLOBAL.gamestats.maxItems = math.random(lw/2, lh/2)

    print("maxitems: ", GLOBAL.gamestats.maxItems)

    --spawn food
    for i=1, GLOBAL.gamestats.maxItems do

      local randomfactory = math.random(1, #factories)
      local spawn = false
      local tile, tile2

      while spawn == false do
        local x = math.random(lx, lx + lw - 1)
        local y = math.random(ly, ly + lh - 1)

        -- check for walls and floors
        tile = tilemap.get_tile("main:/map#tilemap", "layer1", x, y)
        if tile < 10 and tile > 0 then
          spawn = true
        else
          spawn = false
        end

        -- check for decoration-layer
        if spawn == true then
          tile2 = tilemap.get_tile("main:/map#tilemap", "layer2", x, y)
          if tile2 > 0 then spawn = false end
        end
      end

      x = (x -1) * tilesize
      y = (y -1) * tilesize
      factory.create("main:/gamecontrol" .. factories[randomfactory], vmath.vector3(x , y , 0.2), nil, {fac = hash(factories[randomfactory])})
        --print("Spawning " .. factories[randomfactory] .. " at " .. x .. "x" .. y .. "(" .. x/tilesize .. "x" .. y/tilesize ..")" .. " layer1=" .. tile .. " layer2=" .. tile2 )
    end

Yes, this should be the case. But remember also that z-order is important. But as long as all the tinted sprites have the same z-value or are within a range of z-values where nothing else exists the engine will batch them into a single draw call.

1 Like

Ok. thanks.

About the Z-order. If the GO created in the editor have a Z-value and the script (using factory) is spawning, does the Z-values are cumulative? GO Z=0.2 + factory Z=0.2 = engine Z=0.4?

hey @britzl.

Can you explain me why tilemaps takes so much drawcalls?
It seems like if you have a bigger tilemap it needs couple of drawcalls. The bigger the tilemap is, the more drawcalls it needs. At my main-project (Abandoned Force) the map is 100x100 and takes (dont know exactly value now) a couple of drawcalls.
Same at this project (FoodRescue).

Now I am on a random-map using another tilemap als template. This takes 40 drawcalls o.O

Info:

If I tint every GameObject the SAME color just takes 1 drawcall!

In the past I’ve “tinted” each GameObject with a different value (timer-value). This took ONE drawcall for EACH color.

No, the position that you set in your call to factory.create() is the position it will get.

Good question. I don’t know. @sven, @Mathias_Westerdahl?

Yes, this is the expected behaviour. The batch will break if the tint differs between two consecutive sprites.

1 Like

Could it be you were tinting GUI nodes before? Their tint is handled differently, so the GUI would result in just one draw call.

As @britzl said, it is as expected that tinting sprites can/will break batches.

Sorry no idea, it really should result in one draw call as far as I understand. Would probably need a simple repro case to investigate. :confused:

Tint is done by setting the uniform “tint” that is sent to the shader. A change in a uniform value will break the batch.

If you have a limited set of rotten states (like 16 shades of green) a more efficient way may be to create pre-tinted sprites.

2 Likes

(SOLVED, working)

off topic:

Can one of you give me a quick hint for disabling the collider?
this didnt work (script attached to GO):

msg.post("#collisionobject", "disable")

Sending “disable” and “enable” should definitely work. Check that your collision object is really named “collisionobject”.

1 Like

…back to the TILEMAP issue.

Here are some screens:

with ONE tilemap:

drawcalls:
tilemap - 1 tilemap DC

Added 2 more tilemaps:

drawcalls:
tilemap - 3 tilemaps DCs

How many layers into tilemap and what is Z of each layer?
Do you have other objects between this Z?
Can you try to create new collection only with tilemap, what is the result?

1 Like

I have the same issue. but in my case i have 300x1000 map and i have +340 draw calls.

I have equal problems in another project.

Seems like increasing the tilemap-size increases drawcalls.