3D Fake 3D light?

Fredrik

Member
So we all know that the 3D light for GM is kinda limited as there's eight hardware lights avable..
Does anyone have some clever ways to easly create some sort of fake 3D light? not for lighting up but rather to add to the ambience.
 
Last edited by a moderator:

kraifpatrik

(edited)
GameMaker Dev.
You don't have to use any fake lights, you can write yourself a shader that would support more lights. Or find one here on the forum/marketplace/old GMC. Or I would know about one way that would allow you to have more than 8 lights while still using the GM's 3D lighting, but that would include drawing the scene multiple times and that would slow down your game.
 

Fredrik

Member
Oh. I've never really gotten into shaders yet, even tho I've been using gm since gm7 and should probably be abit more updated about newer features. Any good suggestions that might be easy to add into the game? I have no experience with shaders at all and don't know how to make one myself.
 
M

MishMash

Guest
So there are multiple things to factor in here:

The 8 hardware lights is just a limitation of old-style directX 8 shaders. Since GM uses DirectX 9 now, we have the freedom to pass in as many lights as we want into shaders. That being said, if we are using forward rendering, this is inefficient as every pixel on screen needs to perform lighting calculations for every light. There are two main ways in which we can optimise lighting:

1) Forward pass lighting: We still pass lights into a shader, but we change which lights are active. This also applies to GM lights. Just because we are limited to 8 lights, this does not mean we can only use 8 lights in our scene, it simply means that we can only use 8 lights SIMULTANEOUSLY when rendering one object. Each time an object is rendered, you can simply place those 8 light points on the nearest 8 lights to that one object. Realistically, you dont even need 8 lights, you only need 3 or 4.

The main downside of forward rendering is that we cannot apply drawing optimisations. If we want to render a whole scene as one model, then yeah, this technique goes out the window. Though it is important to be aware of it.

2) Deferred Rendering: This is the idea that we separate our rendering out into a number of processes. We have to keep a G-buffer, this is a collection of surfaces which contain information about our scene. We will normally use a number of common buffers for light: Diffuse (This is the rendered un-lit scene with textures), Depth (This stores per-pixel information of how far away a given point is from the camera), Normals (This stores per-pixel information about the direction in which the surface of a given pixel is facing.)

We then use a second pass to render lights onto a light buffer. Now we can cheat here, we draw spheres in the areas the light is. This means that lights only do processing for the pixels they affect, and far away/out of sight lights do not have any performance impact on the rendering process (This is not true for forward rendering). The downside is you have to do a little more work to set the system up, though you get other benefits such as the ease of adding in normal mapping or other renering effects.

Deferred rendering can theoretically support 1000s of lights in a scene, and on screen at any one time, the number of lights you can render before you hit a fillrate crash, though on a modern GPU, that'll be in the 100s atleast.

The final step is to merge the light surface with the diffuse.

Now, I understand this is all quite hard to grasp at first, though learning about 3D rendering techniques is a fantastic and fun skill to have. The forward lighting approach is what is built in and being smart about which lights we draw at any given time can be really helpful. Unfortunately, I can't really give you any help in setting up a deferred renderer, as its something that requires your own understanding in order to be able to use well. GM currently has no system/pipeline which abstracts away all the difficulty of it. I was working on one, but stopped to focus on my main project.

I can walk you through the process, though it'll require that you have some knowledge of shaders + surfaces in order to achieve it successfully and to really have control over what you are trying to do.
 
E

elementbound

Guest
Since GM uses DirectX 9 now, we have the freedom to pass in as many lights as we want into shaders
Is this really true though? Afaik we are limited in the number of uniforms we pass into the shader. If anybody happens to have checked it, it would be awesome to have some actual numbers on hand, about how many uniform slots do we have. I know this depends on the shader model used, I just don't know which shader model does GMS use.

There is also forward+ rendering which eliminated the weakness of forward where a single pixel gets shaded, overwritten, gets shaded again, and so on. At first you draw the scene without colors, so all the info is stored in the depth buffer. In the second pass, you draw the scene, shaded. Pixels which wouldn't be visible on screen gets discarded in depth test, so only the visible pixels get shaded.
 
M

MishMash

Guest
Is this really true though? Afaik we are limited in the number of uniforms we pass into the shader. If anybody happens to have checked it, it would be awesome to have some actual numbers on hand, about how many uniform slots do we have. I know this depends on the shader model used, I just don't know which shader model does GMS use.

There is also forward+ rendering which eliminated the weakness of forward where a single pixel gets shaded, overwritten, gets shaded again, and so on. At first you draw the scene without colors, so all the info is stored in the depth buffer. In the second pass, you draw the scene, shaded. Pixels which wouldn't be visible on screen gets discarded in depth test, so only the visible pixels get shaded.
GM uses Direct X 9.0c, so therefore I would assume Shader Model 2.0. I don't know the uniform limit off the top of my head, but I'd say 128 or 256 32-bit floats, which would allow 32/64 lights respectively. Though this is a bad approach to pass in all lights and have a loop which runs like 64 iterations per pixel.
You could use it for efficient per-vertex lighting if you baked in which lights affected which vertices, though at that point, if the lights were static, you may as well just bake it into the scene triangle data, and then use a limited number of dynamic lights.

When I say as many as we want, there is a hard limit, but its defo larger than 8, and is reasonable. Though regular forward rendering is just bad on modern hardware. It was good when the pipelines were stricter and had less features as it squeezed out more performance than you could have achieved with shaders. But as everything is built around the shader model now, old-style forward is bad.

That forward plus looks interesting, the only other time I had heard of it was with BF3 I think. Didn't really know much about it, so had an interesting skim through this: http://www.3dgep.com/forward-plus/
 

Fredrik

Member
I have no idea how to make my own shader like that. I havn't really looked into shaders and have no idea how they work at all. But I'd like to have as many light points around as possible (not being active once outside my render distance ofc).
As for now I use the 8 light points and if two points with the same index is trying to be active at the same time the one closest to you will stay on and the other one off.
 
M

MishMash

Guest
I have no idea how to make my own shader like that. I havn't really looked into shaders and have no idea how they work at all. But I'd like to have as many light points around as possible (not being active once outside my render distance ofc).
As for now I use the 8 light points and if two points with the same index is trying to be active at the same time the one closest to you will stay on and the other one off.
So if you read my post in full, I gave a number of solutions which doesn't require shaders or surfaces, and still uses the built in light system/simple rendering:

- The limit of 8 lights isn't that you can only have 8 lights in your scene, it is that you can only have 8 lights affecting any single rendering instance. This means that you can place infinite obj_lights, then before every object render call:
- find the 4 to 8 nearest or so to that one object you want to render, and enable lights at those positions.

- If you are using a static scene which is rendered in a single draw call, this will not work, however then, you have other options such as going into a program like blender and baking a lightmap for your model (This is essentially a texture where each triangle gets an allocation of the texture sheet, and lighting data/calculation is baked right into the data.)

- The other option I also discussed was vertex light baking, again more complicated, but there is software that can bake light data into the colour of your objects vertices. GM supports coloured vertices as part of its model standard, so there is nothing to stop you using this :)
 

Yal

šŸ§ *penguin noises*
GMC Elder
I'm kinda with MishMash here... even if you don't do fancy light source switching for each object you draw, 8 lights are still plenty if you only render the lightsources that are the closest to the camera. Directional light never really need more than 1 or 2 lights to look good, and from my experiences with level design, you never really need to place tons of point light sources close together (especially if you're going for a horror game - light is best used for emphasis, and making a whole letter bold won't make anyone see the words you think are the most important). One is enough, and if you need to have a big ball of light, you could always have a big, strong point light in the middle and have all other light sources be duds and nobody can tell the difference.
 
Top