Indie game storeFree gamesFun gamesHorror games
Game developmentAssetsComics
SalesBundles
Jobs
Tags
(2 edits)

A priority queue is very costly and not the method I would use personally.  Like I said you can use "depth = something" as long as you have the light engine on a layer lower than the lowest of your instances.  I highly suggest just normalizing the instance depth using room_height.

Lights are all batched and there is no such thing as manually rendering them.  Eclipse uses a deferred renderer so everything is done in as few draw calls as possible. 

You may want to just copy the depth sorting that Eclipse uses, as it passes depth to the shaders for normal and materials maps using the vertex color which gives a range of -16000 to 16000.  That automatically depth sorts things just by a shader while objects remain on the same layer.

Shadow and light depth is normalized from 0 to 1.  This is so that different layer or depth setups will be easy to work.  To match the players depth you can just set the light based on whatever normalized range you use... again room_height is the answer and can easily be translated into the range 0 - 1. 

There are many ways it could be done, but one option would be similar to:

depth = room_height - y;

light/shadow depth =  y / room_height;        // creates a range from 0 to 1

In your case the isometric y value would be used and you may need to account for room_height being a bit bigger in isometric space.

Regardless the light_engine needs to be at a depth or layer lower than everything else.  So, if it is normalized based on 0 - room_height, then the light_engine should be at -1 (or I suppose 0 would work too).

(3 edits)

So I'm now pretty confused. I also have no idea where the depth sorting even is in the Eclipse objects. Nor do I fully understand how to set a light's depth or how I'd incorporate instance depths into it or how to incorporate light depths into my own depth sorter above.  I don't mind using a different method but I don't know how to incorporate light depth (or set light depths) into a depth sorter in general.

I've reverted back to setting the depth for my objects as per your suggestion.

Controller create event (setting layer depths):

layer_depth("Instances", -1);
layer_depth("Light_Layer", 0); // <-- light_engine object placed on this layer
layer_depth("Background", 1);

Player create event:
light = instance_create(x, y, le_light_spot);

Player/Solid Objects step event:
depth = room_height - y; // this works, my player is going under and over other objects properly and vice versa

As well in my Player step event for their light:
light.x = x; light.y = y+1; // so the light always goes over my player
light.depth = y / room_height;

light.light_depth = light.depth;

Expected Results:
If the player goes above the building  (y < building.y), the player should be drawn underneath it. The player's light should be drawn over the player, but underneath the building.
If the player goes below the building (y > building.y) the player should be drawn overtop of it. The player's light should should be drawn over the player as well as the building

Results:
Positives: The lighting system successfully goes over my background and instances layers (I will refer to this as the "darkness")
Negatives: My player's light is always under my player/all other instances but above the background. Setting the Light_Layer depth to -2 puts it over everything. Setting light.depth or light.light_depth doesn't appear to change anything. It doesn't matter where my light's y is set to, it will get drawn over all instances at all times, even if my player goes under (y < building.y) a building.

What am I doing wrong?

(1 edit)

Here is a tutorial I made about normalizing your depth sorting: 

You'll want to also reference the Eclipse User Manual: https://drive.google.com/file/d/1dOVpNrsVvod9C8GMnuO6_hSj5hGVmVM-/view?usp=shari...

You need to use the functions for changing things like depth or updating it which the user guide explains.  For lights and normal objects inherited from __le_game or something you will want to use such functions.

Setting things manually with "instance.depth" will not work.

Also, you mentioned isometric coordinates.  So, you would most likely want to use the isometric y value plus the distance to the bbox bottom from the origin because your bbox_bottom will not be the same in isometric coordinates.  You still would do all your normal logic with collisions and interactions using normal x/y coordinates, but for drawing in an isometric game everything is drawn at a different coordinate along with their depth sorting.

(3 edits)

Another thing that you may need to consider is setting static objects depth in their create event "before" event_inherited.  This is because static objects like shadow casters add their shadow depth when created to a the buffer used for casting shadows.  So, depending on your depth sorting method you would put in the create event:

depth = room_height - bbox_bottom;

event_inherited();  // After setting depth

Then for objects which change depth often you would put in their step event or where ever:

depth = room_height - bbox_bottom;

update_depth();  // Explained in the user manual

Light depth on the other hand is normalized so where the light is updated you would put:

light_id.y = new_y_value;

light_id.set_depth(room_height/new_y_value);

Or use a "with statement" or something to avoid all the extra id lookups, etc.

(2 edits)

I've set the origin of my sprites at the lowest isometric point so I don't have to use bbox_bottom I don't think.


I watched the video, I'm normalizing the depths now (in my player and solid objects):

Function calculate_depth():
depth = room_height - y + 100;

Controller Create Event
layer_depth("Instances", -1);
layer_depth("Light_Layer", 100);
layer_depth("Background", room_height + 100);

Solid Objects Step Event:
calculate_depth();

Player Create Event:
light = instance_create_layer(x, y,"Light_Layer", le_light_spot);


Player Step Event:
calculate_depth();
with(light) {
    x = other.x; y = other.y + 1;

    set_depth(y / room_height);
}

My player and the light objects unfortunately don't have the function "update_depth()"

--
I still don't understand what I'm doing wrong. I'm using set_depth() now but the light is still going under my player and above the background. The light is going under everything except the background.

I haven't touched shadows and nothing is inheriting from a shadow object yet, I'm just trying to get the light to go in the proper depth (same depth as my player but above my player).

Player depth is working fine still. I just don't understand. How do I set the light's depth? What am I doing wrong?

Did you read the manual or watch the videos?  You have to inherit from one of the light engine objects for your things like players, enemies, and other entities.  In most cases __le_game should be inherited from.  Unless of course it is a shadow caster.

(4 edits)

I did but it's a very complicated system honestly at first glance. I'm very sorry I'm trying to understand it. I don't know what objects need to inherit from what to get depth working properly, I understand depth is a recent addition you added?

I now have my player and my building objects inheriting from __le_game. I think things are starting to work a bit better.

I now have two small issues though:

- Light is emitting very strong whiteness against my players and objects that are inheriting from __le_game. I was just hoping it could brighten up the scene the way it would be drawn if there was no darkness. It's lighting up the background layer perfectly fine but the player/solid objects are turning white
--

- The light is not going behind my building now, it's always above it
--

But I'm guessing this is because I need to somehow get the le_light_spot object to inherit from __le_game as well so I can call update_depth? It's already inheriting from _le_light_cull which inherits from __light. So I tried making __light inherit from __le_game but now I get this error:
"
Variable le_light_spot.normal(101661, -2147483648) not set before reading it.

 at gml_Object___le_game_Other_25 (line 3) - draw_sprite_ext(normal_map, image_index, x, y, image_xscale, image_yscale, image_angle, normal, LE_NORMAL_ANGLE);
"

(1 edit)

Lights do not need to have inheritance setup.  I said to setup inheritance for your game objects.  Again, the user manual shows which functions a light has for setting depth.

Your objects are bright because they do not have normal maps and so they use the sprite as a default normal map that is completely flat.  So, they are like a mirror surface.  You can turn up the roughness and turn down the metallic on the object in the variable definitions tab which will help with some of that.  

Another thing is just setting the light different.  A larger radius but with lower intensity or falloff.  

Eclipse is made for PBR lighting which means you will want material and normal maps to go with your sprites.  The PBR packer that comes with it and which also has a video tutorial on it explains how you could make material and normal maps for sprites.  There are many ways to do so, and in most cases you'll want to auto generate one with a good program.

One thing to consider is that this is still a 2D lighting solution (with 3D calculated lights).  So, the isometric buildings might be difficult to get to look right with shadows.

It may seem complicated compared to some assets, but this is the most streamlined and general solution for PBR lighting in GM that there is.  Inheriting from an object for some type of rendering object is usually pretty common, and the user guide plus tutorials do show this.  The example project that comes with Eclipse also could be looked at to get a better understanding of how to set things up.

Thank you for your patience with me. Turning up roughness and down metallic didn't seem to do much unfortunately. I'll try using the PBR packer and see if it changes anything.

Regarding setting the depth, the only one I found in the guide was set_depth(_depth) (0..1) which I am already doing but the light is not going behind my buildings when the y value goes below the building's y value. I am updating the depth of my buildings using update_depth() as well. I couldn't find anywhere in the guide for setting depth other than that function and increment_depth(_increment). The light always appears to be going over everything no matter where its position is.

//Layers depth setup

layer_depth("Instances", -1);
layer_depth("Light_Layer", 100);
layer_depth("Background", room_height + 100);

//Building / Solid Object Step Event
depth = room_height - y + 100;
update_depth();

//Light Step Event
x = mouse_x; y = mouse_y;
d = y / room_height;
set_depth(d);

(+1)

I'm happy to help, so no worries.  Anyone who purchases one of my assets should certainly get all the support I can provide.

Keep things like you have it, but also on your building, put the following in the create:

shadow_depth = y / room_height;

Sorry if this adds more confusion, but there are two places where depth plays a role and it is on purpose to give designers the option of how light and objects/shadows interact separate from the regular old depth sort.  

The rest is just for information purposes:

The normal depth value which you are setting fine and then using update_depth() after is what sorts the normal and material maps during pre-composition.  Then the shadow_depth is where a lights depth is compared to the current pixel's shadow depth.  This value is stored in the material map when drawn to the surface.

Hopefully this can help illustrate things better on how Eclipse renders everything.  Here is a deferred renderer I wrote in WebGL (warning large texture loading): https://badwrongg.github.io/webgl-deferred-pbr/

On the left you can see those four areas that are each part of the G-buffer (graphics buffer).  From top to bottom they are color, normal, material, and position.  In Eclipse everything is just like this, minus the position buffer because we can cheat in 2D with just a matrix during lighting.  So, when you set the shadow_depth its writing to one of those buffers and the light compares its own depth to that.

So, Eclipse is a 3D PBR renderer, but from a 2D orthographic perspective.  The extra parts that seem complicated are there to make it work well with GameMaker's default draw calls.  In other assets for GM that try to do similar things it is actually far more complicated and you have to deal with your own vertex buffers and other things for every draw call.  Once you get the hang of the shadow, light, and depth stuff the rest shouldn't be a big problem.

Lastly, for the texture packer asset you could go and get some normal maps from just any PBR texture and use them for your sprites.  On the tool you set the clip sprite which should be the same as your regular character sprite.  This will clip the normal map to fit exactly to your sprite.  Then in GM on your object just set the normal_map to point to the normal map that matches the current sprite.  What I do is create a struct that just stores all three and adds them by having a standard naming convention.  So, if the base sprite is "spr_player_run" then it simply grabs "spr_player_run_m" for the material and "spr_player_run_n" for the normal automatically.  Cuts down a ton of extra work.