L
Lab88

  • Oct 29, 2023
  • Joined Aug 21, 2023
  • 1 best answer
  • Lab88 For the light added via the script (the right one) to be influenced by the player's lights like the left one is as seen in the video.

    Currently the left one - which was a part of the scene initially - gets obscured by the player's "darkness" light (which casts no shadow) and can get revealed by the player's "line of sight" light (which casts shadows and gets obscured by the walls)
    And the right light (added via a script) - ignores all of the player's lights.

    The objective is being able to add PointLight2D nodes via gdscript to any scene and have them be affected by the other lights in the scene (like the player ones).

    I cannot currently continue on with my Godot projects until either this bug is fixed or a workaround is found.

    • I checked Godot 4's options to see what modes it uses.
      When using VRAM Compressed, there's three formats available on desktop targets: DXT1, DXT5 and BPTC.
      If the texture has no transparency, Godot picks DXT1. If it has transparency, DXT5 is picked. If you enable High Quality, Godot uses BPTC for transparency and no transparency.

      DXT1 has the best compression (8:1). It's what I described above. It uses 16bit colour instead of 32bit. (DXT1 does have transparency support, but in exchange for a pure transparent colour you lose one of the interpolated colours. Godot doesn't support DXT1 transparency)
      DXT5 has ok compression (4:1), they take twice the vram of DXT1. The colour part is the same as DXT1, but they add better alpha support (8 possible alpha values in each 4x4 block of the texture).
      BPTC is one I'm not familiar with. It's similar to DXT5, but each block can pick from 7 different modes to try to get the best quality. It also has a floating point version.

      Mobile targets have different modes, but they are similar in concept to the above.

    • Standard texture compression on the GPU works by giving you only 4 colours for each 4x4 block of the texture. These are two explicit colours and two colours interpolated at 33% and 66% between the first two colours.
      It can definitely look bad when zoomed in and if there's too many different colours near each other (but has performance benefits and uses 1/4 to 1/8 (depending on mode) of the ram).

    • I'm making this high-level guide to help save other newbies some headache for procedurally generating maps with huge amounts of tiny tiles (1,000,000+).

      Essentially I am working on a 2D dungeon platformer with procedurally generated, high-fidelity dungeon rooms. There are plenty of great tutorials for this already so I will save my breath on this. And while TileMaps work great, huge performance issues arise while generating maps with huge amounts of tiles - the initial generation step takes forever but also low-FPS occurs when playing the map. So you might be wondering, why not just load/unload the TileMap in chunks as you go? The issue with this approach is that I'm using tiny tiles (4x4 px) in large amounts to give the map a high-fidelity look; and even in relatively small chunks, I was still having performance problems.

      My solution: use a combination of TileMap + MultiMesh Instances.
      The thought process is that most tile objects do not need to have individual collision/navigation layers, so we can greatly reduce the amount of GPU draw() calls by having these display tiles share resources and be rendered as a single-object. MultiMeshes allow us to render large amounts of meshes (individual tiles in this case) very efficiently.

      So, in implementation, I still use TileMaps for the floor tiles with collision layers, but use tile-specific MultiMeshes for everything else. My code looks like this:

      Init the MultiMesh-tile map:

      @onready var multimesh_tiles = {
      	$WaterMultiMesh: [],
      	$GrassMultiMesh: [],
      	$JungleMultiMesh: [],
      }

      Where I translate noise to tiles:

      #Other Biomes
      else:
              #plains
      	if moist < 0.9 and temp < 0.6:
      		~~set_cell_tile(pos, random_tile(biome_data["plains"]))~~
      		self.multimesh_tiles[$GrassMultiMesh].append(pos)
      	#jungle
      	elif moist >= 0.4 and temp > 0.6:
      		~~set_cell_tile(pos, random_tile(biome_data["jungle"]))~~
      		self.multimesh_tiles[$JungleMultiMesh].append(pos)

      Where I set the transforms of each individual MultiMesh instance:

      func set_multimesh_instance_transforms():
             for mm in self.multimesh_tiles:
      		mm.multimesh.instance_count = len(self.multimesh_tiles[mm])
      		for i in mm.multimesh.instance_count:
      			mm.multimesh.set_instance_transform_2d(
      				i, Transform2D(0.0, map_to_local(self.multimesh_tiles[mm][i]))
      			)

      https://docs.godotengine.org/en/stable/tutorials/performance/using_multimesh.html#multimesh-example
      https://docs.godotengine.org/en/stable/classes/class_multimesh.html#class-multimesh-method-set-instance-transform-2d