Lighting in 2D using DX8
EACamWell...seing as Lucky's forum is having issues...I'll just post here for a while [;)]. I had this same question on lucky's forum...but with little informative now i'll try again considering i've done a bit more... I tried to adapt the "introduction to lighting" tutorial by Jack Hoxley for DX8 (at DirectX4VB obviously) to work with my 2D game. So far I've been able to: Apply the geometry to my vertices using an UNLIT vertex format. Set the ambient light color Add a light (i'm currently only adding a directional light) Enable the light Eenble DX8's lighting engine Set the vertex shader to the unlit vertex format and what do i get???? A BIG BLACK SCREEN!!! I have a few things that aren't using the unlit I set the vertex shader to FVF_UNLIT...draw the tiles which use unlit vertices (and yes...i've supposedly set their normals to the correct thing...0,0,1 as i think it should be for 2D). Then I switch the vertex shader back to FVF_LIT and draw the rest of my stuff which is showing up fine... I have a background surface (not texture) and at one point I could actually see black tiles rotating on that surface. I thought it was because the lights weren't working that the tiles were black. I realized I had forgotten to set the vertex shader to FVF_UNLIT before drawing now i've done that and I don't see ANYTHING. Any help??? Normals are confusing me to death. Does anyone have any sample code i could look at for lighting in 2D (NOT 3D!!!!)? Thanks a bunch.
Eric ColemanThe problem sounds like it a bunch of different things going wrong. You need to start eliminating some possible errors. For example, instead of using 0,0,1 as a normal, try 0,0,-1. There also must be something wrong with how you have the lighting system setup because ambient light should illuminate your scene regardless of any lights that are created. You said you enabled the light, but did you enable lighting in general? Something like .SetRenderState D3DRENDERSTATE_LIGHTING, True. Also, if you draw LIT vertices, you have to disable lighting, .SetRenderState D3DRENDERSTATE_LIGHTING, False.
EACamOk...I have tried using a normal of 0,0,-1, but I guess if nothing is else is working anyway, then I can't say that didn't work. I'm getting that normal from the CreateTriangleNormal function by Jack Hoxley, so I think that it's right. At the moment I'm just setting all the vertices to have the same normal. Ok...i'll try a little more process of elimination. It's funny but my objects using lit vertices were showing up even though I had forgotten to disable lighting...hmmm. I'll look at it all closer. Thanks. P.S. Any sample code?
game_makerHi are you using translated vertex ,,, you may need to manualy translate your vertex by orthogonal projection becouse we don't know for sure what happaning inside DX and yes logis sais it doesn't matter (true ,, but still not 100% sure [:)]) i wrote a tutorial for this for just 2 weeks :
MantasticI'm not too helpful, but have you applied a material to the scene(or whereever they go's been awhile since I've programmed)? I recall that was my black screen problem.
EACamActually, that would have been really helpful if I had forgotten to do it, becuase you're right: it's absolutely necessary from what I hear.
EACamtranslated? I've heard of transformed, but not translated. I'll check out that tutorial... thanks
Eric ColemanWell, what's different between your lighting code and the code from Jack? Did you copy and paste? and do you have Option Explicit at the top of every module, form, and class?
EACamYup...well, seeing as Jack's tutorial is for 3D, there's quite a lot different. I don't have an presentation matrix (or whatever), no Z buffer, etc. The weird thing is, unless i missed something, but it seems that in Jack's tutorial, he disables lighting in the init code. And it still works...i don't know, maybe he turns it on somewhere else, I don't know. Option Explicit? I've never programmed without it! [:)]
EACamHas anyone ever done this before? I've never seen lighting in anyone's 2D VB game.
Originally posted by EACam
Has anyone ever done this before? I've never seen lighting in anyone's 2D VB game.
I believe the Safrosoft boys put lighting into ROX ... you might try to Google up where Dmitri's hanging out these days and drop him a note. (Good luck ... just spent 10 minutes on Google and didn't have much luck [:(] ...) -Bryk
Spodi"Has anyone ever done this before? I've never seen lighting in anyone's 2D VB game." Really? There's plenty out there. That is, unless you mean without using DX8, then theres just a few...
cjb0087you could always use lightmaps, since the only light kinds i think you would be using are point and ambient
EACamwhat's a light map? and how do I use it? You say it's been done Spodi...example?
EACamOh, and it might be useful to tell you that when I enumerate, it seems my Max Active Lights = 0. I know that -1 means unlimited, and > 0 means that's how many. But what about 0? Does that actually mean I can't have ANY active lights? I'm pretty sure it's not an error in my enumeration, becuase on my friend's computer, he gets -1 (unlimited; and his computer is older than mine). I KNOW that i've seen lighting. In all of Jack's tutorials, lighting works fine. In all the games I've played, lighting works fine. My enumeration also says I don't have gamma correction support...though I KNOW i've done it in DD on my comp. I'm clueless.
SpodiWell depends, do you mean verticy-based lighting? There's lots of 2d games that do that, such as ORE and DXRE. If you mean hardware lights (like in the DirectX4VB tutorials), I cant recall any projects off the top of my head, but I believe I've seen it before. As for the Max Active Lights = 0, you sure you enumerated it correctly? Or did you enumerate the correct device?
cjb0087lightmaps: gives a short thing of what they are it basically takes a greyscale representation of the light on a texture and is multiplied over it and als try making you device REF, and see what the enum says then
EACamAhh, with REF, I can unlimited lights. I've even checked the Caps viewer utility that came with the SDK and even it says i have 0 max active lights. (oh, and that gamma thing, it was because I was checking CANCALIBRATEGAMMA instead of FULLSCREENGAMMA)
Eric ColemanSince you're creating a 2D game, it might be easier for you to do lighting manually by using lit vertices.
EACamI was actually highly considering would be tremendously easy, not very slow, and give me far more control. As of now, I'm thinking i should just calculate what tile the light is in, then determine the distance of all the nearby vertices to the light and light them accordingly. Does this sound like a good method? Thanks.
Eric ColemanYou haven't really given many details other than it is 2D. You mention a tile in your most recent post, so I'll just guess that the entire map is a tile map? If that's the case, then the smaller your tiles the better the light system will be. Also, you might consider using 4 triangles per tile instead of the traditional 2. Manual lighting can be really fast depending on how your map is organized. If your map is a 2D array, then I would create a restriction of making lights only effect a certain area. Omnidirectional lights, or spot lights with a short range. Any further suggestions on my part would really be based on speculation on how your tile engine is designed. Perhaps you can give a few more technical speicifications, such as average map size, tile size, number of tiles displayed on the screen, etc. Also, what kind of lights are you trying to create in the game? Omni, spot, directional?
EACammostly spotlights...the game is a scolling tile game, and there could be any where from 20x20 tiles to 100x100 tiles +. all tiles are 32x32 but the sprites can be bigger or smaller. hmmm, 4 triangles? i'm wondering how i would set that up, i'm not to great in the geometry department.
SpodiInstead of: ____ xxx/x xx/xx x/xxx /____ Just do ________ |\xxxxx/x| |xx\xx/xx| |xxx\/xxx| |xx/x\xxx| |x/xxxx\x| |/______\|
VBBRBTW Spodi how's DXRE going?
EACamyeah, I knew that much Spodi...sorry, i wasn't very specific, I was refering to using that for lighting and rotating it. I think I'll just stick with 4 vertices. BTW, What IS DXRE? I downloaded it once, but couldn't figure out what it did. I couldn't do anything except watch identical people walk all over the place. Good graphix tho.
SpodiHeh, DXRE is mainly just an engine. Most people who use it say they really like it, only problem is there is no documentation or anything, I'm too lazy. I've stopped on it since the last release (2 months ago now I believe) since I started on something else. I'll probably get back into it to finish it off finally during summer vacation. I just kinda got discouraged since I cant update my site (FTP dun work and cant get ahold of my host). or But going more then that, sorry EACam, I have no idea. :)
Eric ColemanSpotlights don't look very good on a tiled map. If the light ever gets rotated, then you'll see effects from the Gourard shading. Omni lights work best because their area of effect is always a circle, that makes them easier to manipulate and calculate. Spotlights are generally either ellipses when projected at an angle, and their projected light is generally somewhat constant througout the lit area. If you want to use spotlights, then I would suggest using a lightmap.
EACamdid i say spot? I totally meant point [:)]
SpodiOkay, yeah, it should be possible to do point lights. Though, I've always had a problem with the lighting - it always looks more like a diamond then a triangle. Say you have this for example (each X represents a tile, the O represents the light origin.) XXX XOX XXX Okay, so if the middle tile has full lighting (255 argb) then the point(s) of the other tiles that point at the middle have full lighting and the outside points have, lets say 200, it will look like a diamond more then anything. I mainly ran into this problem when trying to apply Fog to DXRE (4 textures, each 1/4 of the screen, using same method as above, ended up looking like CRAP). Theoretically, this should make a circle, or close, right?
EACamIt should, and i'm almost positive it will. I think your method may be what's causing that. I'm going to do this: Say, again, the light is O. Now say it has a range of 100. Well, considering my tiles are 32x32, it's range will extend to 4 tiles (1/32=3.1, and remember, if it's even 0.0000001 more than a number, it'll be rounded UP to the next one, since the next tile WILL get SOME lighting.) Ok, so in memory it'll look like this: XXXXXXX XXXXXXX XXXXXXX XXXOXXX XXXXXXX XXXXXXX XXXXXXX To ensure ALL lighting is applied, I make sure that the full length is considered in all four cardinal directions (up, down, left, right). Notice the radius is 3, but the diameter is actually 7 (2x3 + 1) because the light takes up one tile, this isn't exactly how it'll look, but text limits what I can draw [:)]. Now, some of tiles in the corners of this box will receive NO lighting, but that's ok. So from here, I simply loop through every vertex of every tile in this box and light it according to its distance from the light using pythagoras' good old theorem. This is the hard part, because "light it according to its distance" is easier said then done. But with a little trial and error, i'll get it looking fine... I hope.
"light it according to its distance" is easier said then done
I think it's not that hard. you just calculate the distance between the center and the desired point, and then make some calculations. Check this out: [url][/url]
Spodi"using pythagoras' good old theorem" Just wondering, how would "A^2 + B^2 = C^2" help? Isn't this to calculate the hypotineus (or slanty-thingy) of a triangle?
VBBRYou can use it to calculate the distance between two points by using the x,y coordinates as two of the sides of the triangle and the "hypotineus" (if it's spelled that way) for the distance.
SpodiOOooooooooooohhhh, okay, that makes sense, thanks. And yeah, I dont think it's "hypotineus", wouldn't trust my spelling. :)
cjb0087but that would require the deadly square root function, because a=sqr(b*b+c*c) (a*a is faster than a^2), if the light is stationary maybe you could calculate the verticies at load time?
Eric ColemanAre there going to be shadows in the game?
EACamShadows? Sure, that would be a cinch...if I make them look kind of cheap. I would simply loop through that box from the inside out and stop when I get to a barrier (that is, stop for that direction only). It would work, kind of...I'll have to develop it tho, so far this is all theoretical. Aw, the square root function isn't THAT slow, is it? For the example I gave a while ago, that would be, hmmm, let's see here...area = 7x7 = 49, so 49 tiles to possibly go through, then 49x4 since there are 4 vertices in each tile...that's 196 Sqr operations for one, kinda small light. Ok, so maybe I should try optimizing it somehow. Perhaps in my level editor I could make certain lights be precalculated. Then for the moving ones (i'll have enough of those), i'll do it during run-time.
cjb0087you could probably check the inline asm thingo at persistant realities, i *think* there is a squareroot function there
EACamI did some testing; lighting in 2D [using my method, anyway] works like a charm, with a little optimization it'll be working like Sampson at the treadmill. And Spodi, I don't get the slightest hint of a triangle. It's PERFECTLY attenuated and circular.
SpodiHmm, well I'll try doing it again. Do you think you can send me what you got though for reference?
SuperCThis might help
EACamSpodi, this example will work ONLY with how it's set up. I've tried changing the range and things get messed up, but the principle is the same...kind of. I basically did this: Range = 200 TileGeom(0).Color = D3DColorRGBA(Range - DistanceBetweenLightAndThisVertex, Range - Distance...., ...., 255) ' Notice, the 255 is the alpha value, so it's opaque. This doesn't work with colored lights or anything. It doesn't have customizable attenuation, but it works. TileGeom(1).Color = ... ...for all four vertices. This is a bad example here, because you have to do something else. You have to have a variable that holds the color because you need to check if it's negative. If it is, just make it 0. Now, my tiles are 32x32. They were all rotating CC in my test app, and everything looked fine. When I increased the range, I got dark splotches in the middle of the light area. When I decreased the light range, the whole thing got dimmer. I'll work on this and pop a post when its fixed up. Note, this is TOTALLY UNOPTIMIZED. I did this calculation to ALL of the tiles on the screen, not just those within range like I should have. This only works with ONE light. So basically, this is a pretty lame example, but it was perfectly circular. Sorry this is so confusing...I'll try to fix it up and post my results. [:)][|)]