Tile by tile lighting how would i do this

What opiop65 said. And please, use that wonderful thing called Pastebin :point:

You can change the color of the spritebatch before rendering a texture, it will “tint” it. Are you rendering a transparent texture over your tiles right now? That’s a waste of resources, just use the tinting functions of the spritebatch.

Ninja’d by opiop, but yeah just use a plain white pixel as a texture, tint and set size + transparency at each call to spritebatch.

If it’s his own thread specifically for this issue, I think longer code snippets are fine. Besides, none of these are even over 100 lines.

Well, it’s kinda annoying having to continuously scroll up-and-down between writing a reply and trying to orient in the code, but that’s just my opinion >.>

As the others have said, use a 1x1 white texture. You can create it at the beginning using Pixmap or load it from a file. I highly prefer using the white texture rather than ShapeRenderer because I can draw it in between batches rather than stopping the SpriteBatch and starting the ShapeRenderer batch.

Also, if you like to peek in my source code for my lighting engine, you can do so here.

However I use recursion to create a diamond shape rather than a circular shape.

I don’t know if i should start replying on this thread based on my own needs, but i am curious as to how you would use predefined colors. I need to blend with a full RGB range so that the transitions are smooth, but what you mentioned seems to use less resources. maybe message me, or say a bit more on this thread if you feel it could benefit everyone.

If you haven’t profiled and seen that these color objects are causing a performance problem, then trying to avoid creating them would be a waste of time.
Besides, holding a cache of potentially thousands/millions of color objects (if you really need full RGB range) would most likely be a much larger strain on ‘resources’ then just creating them on the fly.

Thank you for everyone’s help
I am trying to figure out what is the best way of doing this as mine isn’t as perfect as I like it

CODE


			for (int x = startX; x < toX; x++) {
				for (int y = startY; y < toY; y++) {
					if (x < 0 || x > TileRenderer.map.getWidth() - 1 || y < 0 || y > TileRenderer.map.getHeight() - 1)
						continue;
					Color tileColor = sunlight;
					
					float min = Float.MAX_VALUE;

					for(int i = 0;i < lights.size;i++){

							MasterTile tile = lights.get(i);
							if (tile == null)
								continue;


							float distance = Vector2.dst(tile.getX()/MasterTile.TILE_WIDTH,tile.getY()/MasterTile.TILE_HEIGHT, x, y);
							distance = (float) (Math.floor(distance));
							if(distance < min){
							min = distance;
							}else{
								continue;
							}
							if (distance > 3) {
								distance -= 3.1f;

							}else if (distance > 2) {
								distance -= 2.3f;

							}else if (distance > 1) {
								distance -= 1.5f;

							} else {
								distance -= 0.8f;
							}
							
							if(distance < 0){
								distance = 0;
							}

							tileColor = Utils.mixColours(tileColor, Color.WHITE, distance);
							tileColor = Utils.mixColours(tileColor, sunlight, sunlight.a);


						}
				

Your lighting code is weird, if I may say, with some number of strange constants. Usually, whenever I see lighting code that has more than two constants in it, or those two constants are not 0.0f and 1.0f, I suspect a mistake in the code/design.
For a given point/tile you compute the shortest distance to any of the existing light sources and that will currently determine the tile’s irradiance.
This is wrong for the reason that in real life each light source “adds”/contributes light to a given area/tile.
With your current code, even if you had five lights and a tile directly adjacent to all of the five lights, that tile would only receive one light source’s worth of light, so to say.
In other words: With your current code, more light sources would not make a tile brighter. This is physically illogical.
Usually, you would need to compute each light’s contribution to a given tile/point separately (and not just the minimum of the distances over all lights), and then sum those contributions together.
This will then result in that marked spot being brighter.

The distance is the distance from the light to the current tile
How would I fix my problem then? not completely sure… ::slight_smile:
the reason why i am doing this

							if (distance > 4)
								continue;
							if (distance > 3) {
								distance -= 3.1f;

							} else if (distance > 2) {
								distance -= 2.3f;

							} else if (distance > 1) {
								distance -= 1.5f;

							} else {
								distance -= 0.8f;
							}

is because the alpha for the light is between 1 and 0

How about just a linear interpolation?


double maxDistance = 4.0;

...

alpha =  Math.max(0, 1 - distance / maxDistance)

https://www.desmos.com/calculator/2okgm0p5gl

EDIT: you can also try messing around with the curvature for various fall-off types: https://www.desmos.com/calculator/jfi7kcyu9j

Wow that is a better way… how does it work???

Also I am still having the same problem as before where if i have a torch about 3 tile away from another torch one of those tiles will be completely dark doesnt look nice

Just in case it is hard to visualize

You aren’t summing the lights together.

Lights pseudocode in pretty much any framework:


for each tile visible {
     tileBrightness = ambient; // ambient = 0 if you want total darkness outside of lights
    
    for each light visible {
        lightValueAtDistance = /* interpolation from before */
        tileBrightness += lightValueAtDistance;
    }
    
    // probably clamp tileBrightness here
    
    drawTile(tile, tileBrightness);
}

EDIT: example, here’s a system of two lights, at positions p1 and p2: https://www.desmos.com/calculator/ua4b5gab8f

Well

Code

// Lights
			spriteBatch.begin();
			{

				for (int x = startX; x < toX; x++) {
					for (int y = startY; y < toY; y++) {
						if (x < 0 || x > TileRenderer.map.getWidth() - 1 || y < 0 || y > TileRenderer.map.getHeight() - 1)
							continue;

						float tileBrightness = sunlight.a;

						for (int i = 0; i < lights.size; i++) {

							MasterTile tile = lights.get(i);
							if (tile == null)
								continue;
							float distance = Vector2.dst(tile.getX()/MasterTile.TILE_WIDTH,tile.getY()/MasterTile.TILE_HEIGHT, x, y);
							tileBrightness += Math.max(0, distance / MAX_DISTANCE);

						}
						Color tileColor = Color.WHITE;
						tileColor.a = tileBrightness;

						spriteBatch.setColor(tileColor);
						spriteBatch.draw(pixelTexture, x * MasterTile.TILE_WIDTH, y * MasterTile.TILE_HEIGHT, MasterTile.TILE_WIDTH, MasterTile.TILE_HEIGHT);
						spriteBatch.setColor(Color.WHITE);

					}
				}
			}

			spriteBatch.end();
-tileBrightness += Math.max(0, distance / MAX_DISTANCE);
+tileBrightness += Math.max(0, 1 - distance / MAX_DISTANCE);

You want an negative slope, brightness is inversely proportional to distance.

You also aren’t clamping tileBrightness prior to assigning it to tileColor.a, although SpriteBatch might do it anyway, I don’t remember.

What do you mean by “clamping tileBrightness”?
and it kinda works but the light is going outside in so it is dark in the middle and light going outwards?

Clamp in this context: to limit to a range

tileColor.a = Math.min(1, tileBrightness); // don't exceed 1.0

The inside-out lighting is because of the missing ’1 - …’ in 1 - distance / MAX_DISTANCE

Try taking it out of the graphs I linked and see what happens.

Well i changed it on the graph website and it is giving a positive number but when attempting it in the code it doesn’t work

				for (int x = startX; x < toX; x++) {
					for (int y = startY; y < toY; y++) {
						if (x < 0 || x > TileRenderer.map.getWidth() - 1 || y < 0 || y > TileRenderer.map.getHeight() - 1)
							continue;

						float tileBrightness = sunlight.a;

						for (int i = 0; i < lights.size; i++) {

							MasterTile tile = lights.get(i);
							if (tile == null)
								continue;
							float distance = Vector2.dst(tile.getX() / MasterTile.TILE_WIDTH, tile.getY() / MasterTile.TILE_HEIGHT, x, y);
							tileBrightness += Math.max(0, distance / MAX_DISTANCE);

						}
						tileBrightness = Math.min(1, tileBrightness);
						
						Color tileColor = Color.WHITE;
		                tileColor = Utils.mixColours(tileColor, sunlight, sunlight.a);
		                tileColor = Utils.mixColours(tileColor, Color.WHITE, tileBrightness);

						spriteBatch.setColor(tileColor);
						spriteBatch.draw(pixelTexture, x * MasterTile.TILE_WIDTH, y * MasterTile.TILE_HEIGHT, MasterTile.TILE_WIDTH, MasterTile.TILE_HEIGHT);
						spriteBatch.setColor(Color.WHITE);

I’ll point it out very explicitly this time:

for (int x = startX; x < toX; x++) {
               for (int y = startY; y < toY; y++) {
                  if (x < 0 || x > TileRenderer.map.getWidth() - 1 || y < 0 || y > TileRenderer.map.getHeight() - 1)
                     continue;

                  float tileBrightness = sunlight.a;

                  for (int i = 0; i < lights.size; i++) {

                     MasterTile tile = lights.get(i);
                     if (tile == null)
                        continue;
                     float distance = Vector2.dst(tile.getX() / MasterTile.TILE_WIDTH, tile.getY() / MasterTile.TILE_HEIGHT, x, y);
-                     tileBrightness += Math.max(0, distance / MAX_DISTANCE);
+                     tileBrightness += Math.max(0, 1 - distance / MAX_DISTANCE); // you really do need that 1 -

                  }
                  tileBrightness = Math.min(1, tileBrightness);
                  
                  Color tileColor = Color.WHITE;
                      tileColor = Utils.mixColours(tileColor, sunlight, sunlight.a);
                      tileColor = Utils.mixColours(tileColor, Color.WHITE, tileBrightness);

                  spriteBatch.setColor(tileColor);
                  spriteBatch.draw(pixelTexture, x * MasterTile.TILE_WIDTH, y * MasterTile.TILE_HEIGHT, MasterTile.TILE_WIDTH, MasterTile.TILE_HEIGHT);
                  spriteBatch.setColor(Color.WHITE);