Seeking advice regarding attempts to replicate the behavior of Doom-style """lighting"""

Hello there!

The name’s Dandy, I’m admittedly a bit new to posting on public places like this as somebody who’s mostly been relying on my own knowledge with occasional help from close friends, occasional use of tutorials and often perusing public sources like the forums or online posts to try and seek information. I ended up biting the bullet recently and choosing to create a forum post as admittedly my luck ended up running dry, I’ve been mostly been running into dead ends or into posts like this ( A light that does not emit from a point - #6 by whoozzem and https://www.reddit.com/r/godot/comments/16qmroc/doom_style_lighting_in_godot/) which seem to be an odd mixture of dead ends and explanations that don’t entirely make sense to me: excuse my ramblings, I tend to be a bit talkative! With that being said, I’ve come to here to try and seek some answers in hopes of potentially getting some more information.

Godot Version

I am using Godot 4.6.2.stable.

What am I trying to achieve here?

I threw together a quick in-engine mockup in my Godot project and a quick shoddy picture in Paint to try and explain my plight as clearly as I can. Again, forgive me if I overexplain or if I’m unclear, I’m a bit new to asking public sources for help on matters like this:

To make a long story short: I’ve been working on a project which is heavily inspired by a lot of old first person 3d games, one which I have been extremely dedicated to trying and keep a level of authenticity to. So far, this has gone well: programming the game as a whole has been going quite smoothly, visuals have been mostly no trouble and I’ve not only utilized open source shaders to help sell the look but have even added onto the directional shader I was using, making that into a public resource you can find here! However, I ended up running into a roadblock when trying to account for lighting.

From my experience tinkering myself, Id tech 1 games and a lot of software-rendered 3d games in general at the time were split up into sectors, which also allowed the games to create lighting (.. or an imitation of it). Though this is easy work for a material: just change the color value in the albedo to adjust the lighting of a given split area, this becomes far more tricky when accounting for how sprites should be affected: I am completely unsure as to how I could go about tackling them in a way that would hopefully be optimal and wouldn’t be too taxing on performance.

What have I considered and tried?

My initial hypothesis is that I would have to use Area3Ds and give them their own custom shapes within the areas I would need to change the lighting color for, and then try and detect each and every sprite which enters it. However, the initial way I’ve gone about this implementation made me quickly realize the amount of troubles it’d bring. Unless I were to lock specific sprites to have a specific color, all sprites within an area would have to have some kind of CollisionShape3D to be detected which could get incredibly heavy on performance incredibly fast. Not only that, but the lighting switch could end up being incredibly buggy or inaccurate depending on how I go about it’s implementation, especially between 2 wildly different lit areas. I’ve also considered trying to use shaders to circumvent this issue, though realistically I’m not sure how effective those could even be with my use-case as the only example I can think of which used shaders off the top of my head is Baldi’s Basics: a game which used a vastly different kind of psuedo-lighting technique from what I’m trying to achieve.

What I am seeking

I am simply seeking for some kind of advice as to how I should go about tackling this issue and implementing this kind of system, as it has been an issue I have been stumped on for a while and considering the fact a handful of other posts have asked similar things and have ended up in dead ends, this thread could hopefully serve as useful information for any on-lookers. Though I’m not sure if I will be able to get any answers, I figure it’s worth trying to reach out where-ever I can.

With that being said, if you’re reading this: thank you for taking the time to read my long rambling of a thread and for reading my question! Apologies again if I rambled a bit too much and if I’m unclear. Best wishes to you all and have a wonderful day!

Additional note if it simplifies my particular problem down:

I am NOT seeking to replicate the exact way Doom’s lighting functions, specifically I’m not looking to implement the absurdly small details like light diminishing (if you aren’t aware what that is, I’d recommend reading the section on it in Ryan Thompson’s How Doom Renders Colors article). Though that’d be a neat bonus to figure out, light diminishing is such a small feature that even I think it’s a bit much and I don’t think it’s particularly necessary to find out in order to achieve the early 3D PC game look I’m going for.

I simply want to figure out how to make sure the colors of sprites reflect the specific defined color of whatever area/sector they’re currently in, in order to imitate the “lighting” a lot of early PC games like this use.

Again, apologies for the excessive ramblings! I figured it was just important to clarify that in case.

How is a sector defined in geometric terms?
How many of them can be visible at the same time?

How is a sector defined in geometric terms?

I’m not too great with the exact geometric terms, excuse my lack of expertise there, but I’ll try my best to explain. In something like Doom, sectors just refer to each physical of the map geometry under its line-based map system. I can try and explain the deeper intricacies from my time messing with map editors designed for Doom, but I don’t want to get myself too caught up in that.

Obviously, I’m not working under those exact definitions since this is Godot we’re talking here: in my case, sectors essentially just describe different geometry within the map that have different bits of “lighting”: I suppose in this context it’d specifically refer to the area between that section of map.

Provided above is a picture to help give a little more visual reference! I’d provide three in this one post, but I’ll have to divide it up a bit since I’m a new user to the forums here. Though these two darker-lit sectors are symmetrical and the test map I’ve made is designed in a grid form, I plan to make maps that aren’t using this same shape if that helps provide any extra context.

How many of them can be visible at the same time?

I’m unsure as to if this is referring to the sectors, the map geometry itself or to the sprites: I’m leaning a little more to the first one, but I’ll answer all of the above to the best of my ability just to make sure I don’t lean any gaps out in case I’m mistaken.

Sectors don’t really have a defined amount that can be visible at the same time in the source material I’m taking influence from, though depending on how I handle the visibility of the map geometry in the future (i.e if I end up needing occlusion culling or loading specific parts of a map’s visuals based on the player’s location) that could very well end up changing for my project. Generally speaking though, the amount of sectors visible is essentially just the amount of sectors you can see in your general line of sight.

Sprites also don’t have a set limit that can be visible at once at the moment (and similarly to map geometry, that could very easily Also end up changing.), in the test map at any given angle I tend to see at least 5-10 at a time though it’s quite densely packed with decoration at the moment.

That’s all 3 pictures I tried to provide in my initial reply! If you need any additional context in the form of explanations by word or any pictures for reference, please let me know and I’m more than happy to provide as such. Thank you for the response by the way! ^^

For a generalized solution with arbitrary sector shapes, have a large texture that covers the whole map and draw sector shapes into it in a top view. The color you draw the sector could represent the “illumination”, or you can encode any other information you need into rgba channels. In the fragment shader, sample that texture in world space and alter albedo or irradiance accordingly.

This is honestly an interesting approach to how I could try and handle this kind of system. I’ll go ahead and give it a try, I’ll drop an update here after experimenting a bit. Again, thank you so much for the response and for the advice on how I could go about tackling this: it’s been something I’ve been stumped on for a little while and regardless of I’m able to make it work out or not, that little bit of advice you’ve handed me is greatly appreciated! ^^ Best wishes to you, have a wonderful day!

Update: I did a bit of experimentation + read through a couple times to make sure I understood clearly (admittedly I think I misread it when trying to code it initially) and though I don’t think this particular solution is what I needed, I’ll likely mark it as one anyhow since this solution could be still be useful information to have (especially for any onlookers)!

Based on your wording, I was initially inclined to attempt projecting the texture onto the world: only to realize very quickly that due to my usage of Compatibility that it would not work out for me: not to mention the way certain shaders are handled (namely the sky, which is projected onto a mesh and treated as a wall.) so I pondered for a while and wondered what I may have done wrong:

I realized shortly after re-reading this that the proposed solution was (at least I hope, if I misread again apologies for my foolishness ^^ “) more specifically proposing the idea of trying to project the texture onto each of the sprites, which I gave a try shortly after. Ironically, it looked a bit too clean: ignoring the slight distortion of the UVs, the transition between the darker section and the lighter section was almost too natural for the technical limitations I’m trying to emulate (where sprites would normally snap between brightness, here I could make out the split in which the transition happened.. which is admittedly, not what I’m looking for!), besides that though the shader got quite flimsy quite fast.

For reference for any readers by the way, after retrieving the world coordinates. I converted the lightmap like this:

// Defined alongside other variables
varying vec3 world_position;

// At the end of vertex

world_position = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;

// At the end of fragment

vec4 light = texture(lightmap,world_position.xz);
ALBEDO = tex.rgb * light.rgb;

I may return to this method in the future and try to experiment further to see if I could perhaps get the results I’m looking for with this, but for now I’ll continue experimenting and seeing what other methods may work! Though this may not have been the particular one I needed, I heavily appreciate the help nonetheless and continue to wish you nothing short of the best for helping provide a lead for me! Again, best wishes! ^^

To explain my post that you linked to slightly more, if you look at this shader image:

You see how the Fresnel starts with a solid blue outer line, then blurs to black in the center of the sphere.

If you imagine inverting the above result, this makes it solid blue in the center of the sphere, then it fades to black at the outer edge.

If you then make the inverted fresnel affect both the Albedo and Opacity, you get an orb of colour that goes from a completely solid colour in the center of the sphere and then fades out gently in a gradient to become fully invisible at the edges.

To allow for adjusting the opacity (as obviously we don’t want a solid colour in the center but want it to have some opacity), just add an additional Vec2 value to CLAMP (min/max values) the fresnel effect before returning it as the opacity output.

In this way you can control the effect in-editor (you can also add an additional float value for further control to this clamped output for fine tweaking if required before returning it as the result for the opacity).

Make a material that uses the modified Fresnel shader above, and make sure its’ double sided flag is ticked.

If you then encompass part of a level with a large 3D cube (or any 3D mesh shape required - just remember to make it have no collision so you can walk through it) and apply this material, when standing outside of this cube, everything within it will appear tinted with the colour of the Fresnel.

Because of double sided being used, when standing inside the cube everything will still appear tinted with the colour.

I’m not sure that’s the effect you’re after, but hopefully that clears up any confusion about my post in the other thread you linked to.

Currently posting from my phone since it’s quite late, excuse any spelling errors of mine!

With that being said, I heavily appreciate the clarification you’ve given here! Admittedly, though this isn’t the particular effect I’m looking for, this is an incredibly useful one to keep in mind and I do appreciate the more in depth explanation, honestly seeing the way ya tackled it is incredibly interesting to read on and it does help provide a good lot of insight. Particularly I could imagine that sort of effect being extremely useful for deep, darkened halls and to give objects a bit of an extra glow to them to help those parts stand out. ^^

Whilst I’m here, I will give an update on my own experiments as well: I decided just for the hell of it to try the aforementioned Area3D-based method I mentioned in my image summary: even if I knew I’d probably end up at another dead end, I’m mainly just testing the waters to get an idea of the methods at my disposal. Please excuse my ramblings again, I tend to get a bit carried away!

The Area3D method did provide me with some more pictures I can use as visual reference to show what I’m trying to achieve, though admittedly I found pretty fast that, as I suspected, the area3d method was naturally very messy: namely, the switch into the darkened lighting seemed a bit earlier for characters and some objects would just outright get ignored by the sectors. ^^ “

With that being said, I think it might be a good call for me to try and experiment with normalized’s shader-based method a little more than the initial tests I took. In particular, I reckon I should try tampering with the UVs and see if I have any better luck with changing the albedo fully (unlike what was happening before, where the UVs were off and the lighting didn’t exactly switch as much as I hoped it would. Perhaps that’ll work better if I manage to adjust it or maybe I’ll find another way to achieve the particular look I’m looking for. Something I’ve learned throughout the development of this project is that replicating a lot of the aspects of early cheap 3D PC game visuals are much, much more in depth than the surface level look would imply!

Again, thank you all for your help! If I find any more information of my own that might be of use figuring out this particular case, I’ll stop by with another post! Have a wonderful, wonderful day!

If you want sprites to transition smoothly, don’t sample the texture per fragment. Instead, just use sprite’s position as a sample point, do several samples nearby, average them and use that value for the whole sprite.

If your vertical walls are just planes, you’ll also need to take special care for that - offset the sample along the normal of the currently visible side. That way the distinction within interior and exterior side will be propertly handled.

I’ll try taking this advice into mind and see what results I get out of it: though I wasn’t particularly worried about how to handle the walls as much as how to handle sprites, that tip for the walls in particular is an honestly really clever way to try and calculate what the shadows should look like! Again, thank you very very much for your advice: I’ll be sure to drop an update here after doing some testing with this additional advice in mind! ^^

Mainly only mentioning this here because it’s somewhat related and I reckoned this would be a good call as, admittedly, the project I’ve been using this info for is one I’m a bit secretive on and, at least in my opinion, it always helps to provide a lil’ of what one’s got with stuff like this: I reckoned it’d be a good call on my part to create a very small open source project that includes the map and most of the visual shaders I’ve been using for my personal project. Doom-esque Visuals Pack (Small pack comprised of shaders and some sample textures)

I’ll be continuing to experiment with normalized’s shader-based solution to the sector-based lighting issue I’ve been trying to solve: that’s my number one focus to tackle at the moment, but I reckoned it’s at least worth providing this here since it’s related! ^^