Showing posts with label shadows. Show all posts
Showing posts with label shadows. Show all posts

26 October 2009

Behind the veil

I sent out what I thought was an impressive update of the shadow engine to a number of friends. Mostly they just complained about how slow it ran. Sigh. To be fair (which they were), it was horrifically slow at doing anything - I could only run it mostly smoothly on my super radical good speed* computer at home. Testing it on my work Mac made me yearn for more for... well, speed.

As such I sat down and had a look at the code. It was a hacky mess of naughty tricks that confused me as to how I'd even gotten it to work in the first place. If I recall, I sort of threw code at it until something akin to shadows edged onto my screen and I called it a day.

"But that's not good enough!" I cried out. Which caused some people nearby to give me funny looks. This weekend I decided to build the shadow engine properly and I pretty much scrapped a vast majority of the code. It's still not perfect or completely finished (there are a lot of possible effects and optimisations (see previous post) I'd like to add to it). It's also superior to my previous attempt with a nice array of features.

  


How to muck around with light:
The top left button will reset the scene, positioning the lights and objects randomly. You can click and drag the objects around the scene. Dragging them through a light or another object will glitch out the shadows (I haven't done light/object intersection testing or object collision testing). Objects will shadow each other, too.

Clicking on the light buttons labeled "light x" will enable control of that light. With a light selected, hold the spacebar and the light will move towards the mouse. Select the light again to turn off the controls. Change the light colour with the red/green/blue ratio sliders - the objects are white so you can see how the light colours them, lights of different colours will blend together (disco lights!).

Play with the intensity, etc. to see the effect. Glows are affected by the intensity and falloff of the light itself but have a separate radius. A high falloff level will give a hard edge at the radius to the light. You can turn off the light or the glow. Turning off lights will speed up the simulation. If multiple lights cast onto the same object, it'll slow down the sim quite a bit. So it's something I'll be avoiding in the actual game.

When light enters an area, the photons bounce around against objects. Effectively, this causes the objects to "light" each other. This is why, when there is only a single light source, you can still see in the shadowy areas of a room. The light bounces around even into the shadowed area and lights it up a bit as well. The effect is called radiosity. Besides just lighting areas, it also creates a colour-bleed between various objects. If you have a green room, objects within that room will be tinged green due to the light bouncing off the green walls (and the bits of the wall near certain non-white objects will tint towards those colours a little).



I've simulated this above on a washing machine in a room with some slightly weird perspective. In the first image, there is no colour bleed and the shadow is solid black. It doesn't look very natural at all. The second image has some colour bleeding onto the (white) machine and the wall and floor bleed colour onto each other (although it may be hard to see the wall/floor bleeding). This makes the image feel as though it is more inline with reality. Except for the alien geometries.**

Colour-bleed is a pretty complex and intense (to the CPU) thing to do in real time. So I've chucked that concept and instead stuck with a slight lightening of the shadows instead, depending on the intensity of the light around them (and the density of the shadow as larger or less translucent objects have more dense shadows). This is more easily noticed if you only have a single light affecting an object (simply turn off all the other lights) and adjust the lights intensity while taking note of the shadow density. I've also included something called ambient lighting, which makes the shadow layer more or less opaque, simulating a higher or lower level of radiosity in a pretty rudimentary way.
(it's the top slider in the prototype, feel free to drag it around. Things look much better when it's darker, though).

There's lots still to do in the shadow engine but I feel I've done enough to move onto other things for a bit before I get too carried away on just that one feature. Object shadows are currently limited to non-concave objects, but it shouldn't be too bad to adjust that by grouping shadows together. The shadow that an object casts and the object itself are unrelated elements so you can have very complex visuals with fairly simple shadows.

At the moment, I've only allowed it to do big veiling sort of shadows (blocking out light completely behind an object) which is fine for large objects but it would be nice to have smaller objects (like a thin pole, or thrown knife) to only cast a small shadow of themselves nearby without the veiling.


And for extra fun, a sun or global light system would be cool for outdoors. At the moment, shadows expand out from the source light, but a sun system will keep the shadow angles the same for each object.

* line blatantly stolen from the Scryed anime.
** Cthulhu reference again. I should probably stop that.

20 October 2009

Shadowy figures

There are many ways of immersing somebody into the environment of your game. The extra touches of detail that bring a bit more realism (even in cartoony games) like a character shrugging their shoulders while talking instead of just mouthing the words, or the leaves in trees rustling subtly in the wind. Simple textures can be heightened with bump maps (and more fancy effects). Objects can self shadow. Sunlight can temporarily blind the player when moving out of a dark area.

Seeing as I'm trying to make a semi-realistic sort of game, I figured shadows would, you know, be there. Shadows can evoke silent horror by withholding or smudging details. This isn't a horror game, but horror is based on heightening aspects seen in life and sometimes it doesn't even need to heighten life - certain things are pretty terrifying without having multi-limbed giant spiders involved (or even worse, single-limbed, because what freakish creature tore the spider-beasts legs off?). The main character certainly won't be in a happy state in this game. He needs to survive some fairly nasty odds at times. Needing to run away but knowing it could cause a heart attack at just the wrong moment can't be fun (except, hopefully, for the player having to work out the most survivable solution). Shadows can add to this tension. They add dynamic detail to objects and by causing objects to cast shadows said objects are better integrated into the world - not mere floss and background noise, but existent.

So. It was time to make dark what once was light. I needed to know where the hell to start for one thing. It took me a while to work out how to actually make shadows work. Instead of skimming off somebody else's work I figured it shouldn't be too hard to work out how to do myself, plus it would probably be far more fun to do it that way. Turns out it was. It also allowed me to expand upon the original code to make a far more visually appealing and functional shadow system later on. After I had done the initial shadow prototype, I went and actually did some research on the subject. Most articles involved themselves with 3D shadow projection which is quite different to 2D projection (being that it is significantly more complex). But I managed to find a particularly noteworthy article on 2D shadow projection.*

The above was one of the initial drafts at a shadow engine. The first one actually just used a single box which is not all that exciting to play with. The engine is limited in that it can't work with concave shapes (a shape that has part of it "hollowed out"). This is mostly because the calculations become quite a bit more complex, especially when self-shadowing is needed. So I cheated. The left had shape above actually consists of two convex shapes. You may have to click the flash movie to activate it. Twiddle the mouse around to move the light source. You'll note that it glitches out when moving the light into one of the shadow objects (so don't do that) or if you move the light source very close to one of the shadow casters (don't do that either, please).

The early engine is actually a shadow casting system as opposed to a light casting one. The difference is minor and actually took me a bit to properly conceptualise. Basically in the above, the light is not really doing anything. It isn't light the scene, rather the casting objects (casters) are darkening the scene. Light casting starts with a completely dark scene and then casts light (with shadows being an absence of light like in that place wherein you reside: real life). A friend of mine suggested I do the whole light casting thing instead and I went ahead and listened to him. It meant a complete overhaul (more a starting from scratch) of the shadow code and the result was much improved (perhaps also due to the fact that I understood more what I wanted to do with the shadows). I'll discuss and show that demo in a later post.

At some point I thought doing shadows with fuzzy edges (the penumbra part of the light for all you technophiles) would be fun and I had a quick hack of it underway using the glow filter in Flash instead of an actual calculation to speed it up.



Sadly, I think that unless I bake the shadows into the level (pre-calculate the shadows so that they are part of the level and can't change during gameplay) this approach would be too costly in CPU usage. Filter effects in Flash are notoriously slow.


* this way, if you're interested: http://www.gamedev.net/reference/programming/features/2dsoftshadow/. The article references OpenGL but many of the concepts can be carried through on other systems.