Wednesday 13 October 2010

Tech feature: Sunlight with Shadows

Now I am pretty much done with the first major feature for HPl3, the engine that will power our upcoming (and so far super secret) game. This feature is global sunlight along with shadows, a feature not implemented previously. And since it is now implemented you can bet it will an important feature for the secret game ;)

First up was making the Ambient light nicer. Below is screenshot of how it looks in HPL2:

This is just a uniform color blend that has been added and does not look very. It is quite hard to see any details when there is a uniform texture such as in the screenshot above. To get nice ambient lighting what you need to do is to somehow simulate global illumination. Light does not just hit an object and then stop, but bounces around and scatters color from nearby on each other. There is a lot of research into this and most of it require one to pre-calculate the result in one way or another.

I settled with something really simple called hemispherical lighting, which basically mean to have separate up and down (sky and ground) colors and then blend them depending on the normal of the surface. My first idea was to use cubemaps to do something similar, but since the cubemap needs to be very blurred, using hemispherical lighting gave pretty much the same result and is a lot faster. Here is the result:
Now it is a lot easier to see details and looks a lot better.

Next up was the direct lighting from the sun and this was quite simple. I could just add some tweak to the existing shaders and make it work. Basically sunlight is just like normal light but without any position or attenuation. This means every pixel is lit from the same direction and strength is independent of distance to the source (as it does not have a position).

Here is how the scene looks when we add that too:

Much nicer, even though the texture is a bit boring. Note that there now is specular because of the direct light from the sun.

Finally, lets move on to the shadows! The engine already feature the basic shadow rendering though a technique called shadow maps. What is the big problem now is to make it look good over long distances. Since shadow mapping works by rendering from the light's point of view, doing shadows from an omnipresent light source gets a bit complicated. The simple solution is to use a really large shadow map, but then you would get very bad resolution near the camera.

What you do instead is to use the fact that objects take up smaller space of the screen the farther away they are. So the idea is to use the shadow map in such a way that you give more room for pixel nearby and less to those far away. This is something that has been researched quite a bit and there are various techniques to achieve this. One solution is to warp the projection when rendering to the shadow map. This comes with a lot of issues though and is very rarely used in games.

Instead most games use a technique called Cascaded Shadow Maps or Parallel Split Shadow Maps. The way this works is that the view frustum (a geometrical shape encompassing all the camera sees) is split into several parts and a shadow map is given to each split. This means that the first split, which is right in front of the camera, gets a much larger shadow-per-pixel ratio than the last split, which is much larger, but further away (and hence has small on-screen pixels).

The algorithm itself is pretty easy, especially since there is quite a few papers on it. The big problem is that you can get some flickering results because the shadow map can change a lot. There are published techniques that solve this fairly easy though. Most of my time was instead spent on making it work with the rest of the engine. This is something that might not be that known to non-programmers, but most of the work is often not in the algorithm itself but fitting it into the engine design. I think I spend a 3-4 days on getting it inside the engine, before I had everything set up as it should. The actually algorithm took 2 days or so.

Here is how it looks:
Note how shadows are detailed up front, yet they are cast all the way into the distance.

Here is how the shadow maps look (I combine all into a single one):
Probably want to enlarge this by clicking!

These are the four shadow maps that all render shadows for different slices of the frustum. The white stuff is the objects, the red lines outlines the frustum slice and the sphere is part of an anti-flicker algorithm (that determines size of shadow maps).

Now lets add this to the image I started with:
And lets add some nicer texture while at it:
There! Sunlight with shadows is in!

My next job will be to update the very core of the renderer with something called a Light Pre-Pass Renderer. More on that in a later post!


35 comments:

  1. This looks very nice :O
    I wish I knew how to do this kind of stuff! Is it openGL you're using?

    ReplyDelete
  2. Thanks for this post!
    Additional information is always good.:)

    ReplyDelete
  3. Yes. OpenGL is used right now.

    ReplyDelete
  4. This article of course makes me very curious about your next secret game. I'm still enjoying Amnesia a lot, so it's hard to imagine how you will implement bright (?) outdoor areas, although there were some in Penumbra. :) Looks nice!

    ReplyDelete
  5. Looks very nice!

    ReplyDelete
  6. Cool!

    Have you seen this by any chance? http://the-witness.net/news/?p=113 -- It's a walkthrough on how the team making The Witness is trying to get more out of their shadow maps. Very detailed and very handy. :)

    ReplyDelete
  7. Hi there! Good post again! Also, Congrats for Amnesia! I really enjoy playing it! So many intense moment inside this game! :) So I wish you good luck for your next game. I just hope it is still some kind of survival horror!

    Concerning environment lighting, did you have a look at spherical harmonics? Using this method, you would be able to encode much more complex environments lights with few coefficients. I have my source code online at http://sebastien.hillaire.free.fr/demos/sh/sh.htm and some more examples here http://sebh-blog.blogspot.com/2010/04/spherical-harmonics-lighting.html . This way, you would be able to encode a single global environment or different lighting condition at different places and still use a directional light for the sun. But I don't know if this would fit your engine...

    ReplyDelete
  8. Martijn: Yup read it! Nice stuff!

    sebh: I have check SH a bit, but not that much. The thing is that you need to place probes on the map and that requires some kind of pre-processing, something we try to avoid.

    Your stuff looks very nice though and I have not ruled it out yet. I think KillZone 2 does it the way you do with interpolating between several probes for an object.

    ReplyDelete
  9. I agree with you concerning the probes and preprocessing. However, you could still use SH to encode the environmental cubemap and then use the SH product to light up the world instead of the two color trick (which works great also!). I am currently using this SH method and the result is very nice. It only requires to preprocess the cubemap and it is so fast when done on the GPU that I currently do it when loading the map.

    Good luck with your light-pre pass update! :)

    ReplyDelete
  10. I would like to see more posts like this - for the sake of us who are interested on the technical side of things.

    My advice is not to seek to achieve physical accuracy, but to do what [i]looks[/i] good, and is preferably computationally cheap. Be creative.

    Will the Light Pre-Pass Renderer include occlusion mapping? Is it possible to efficiently implement this dynamically, for animated entities?

    ReplyDelete
  11. sebh:
    I might try a global SH, but it might be a bit expensive since I have to do it per-pixel. Should be easy enough to test. And pre-computing from a single cube-map should not be a problem.

    "Will the Light Pre-Pass Renderer include occlusion mapping?"
    The engine already have SSAO and this is what will be used later on too. I will go over it though and make sure the high rez mode runs faster and gives a bit better result. Will need to check when we get the game's super secret environments up and running.

    ReplyDelete
  12. Oh, in case you are curious, here is the hemispherical ambient with SSAO:
    http://frictionalgames.com/forum/attachment.php?aid=731

    ReplyDelete
  13. Nice (I just registered so I could see it :)). BTW, I the hemispherical ambient was the right choice because you can get some really nice-looking results with little expense. I've been experimenting with something similar myself using DirectX pixel shaders.
    Can you freely modify the way the two colors are blended - linear interpolation is not the best way IMO. If you take a sphere - the upper half should mostly be affected by the color of the sky, the *narrow* (like 10%-15% of the diameter) middle (equatorial) ring should be the transitional, and the surface below it should be affected mostly or only by the reflected ground color. The objects close to the ground - meaning pretty much anything that's not airborne, receive little reflected light at the base - in case of the sphere, at the very bottom the ambient color should fade to black as the normal vector approaches the vertical (but this affects only the *very bottom* part of the sphere).
    If you have the means, try it - it looks great. Test it also on the torus and the standard teapot models.

    One more question: code-wise, was the game designed with these additional features in mind? If not, then adding features will only get harder and harder, until you hit a point where a major refactoring will be needed. What I'm saying is, it's better to analyze this and where required refactor/redesign sooner, than later.

    ReplyDelete
  14. I can't wait to pee myself.


    Outside!

    Just kidding. For all I know you're making a spinoff of Mirror's Edge or something.

    ReplyDelete
  15. It is not totally linear since a dot is used. See here: http://www.yaldex.com/open-gl/ch12lev1sec1.html

    The engine where not really design for sun shadows, but I have tried to make it as expendable as possible (the entire renderer is a actually just a module, so it is easy to switch renderers). But aware that for other features, especially if I focus on multithreading, I might have to do serious changes.

    ReplyDelete
  16. The final image looks a little false - as if the ground is lit more than the objects, and the leftmost object's shadows look wrong?

    ReplyDelete
  17. @Anonymous[14 October 2010 09:51]:
    That's because the objects use a darker texture. In the actual game it can be tweaked to look as best as possible.

    ReplyDelete
  18. Shadows suffer from some bias problems. Stuff that can be fixed by tweaking some variables. And as a the poster above me say, the textures are quite dark for the machine.

    Guess I have to do some more tweaking for next screens :)

    ReplyDelete
  19. Yes. The two final images (IMO) use display the exact same illumination - the same lighting model, if you will - the only difference is that in the upper one the same texture is used for everything, and in the other one the objects use a different, darker texture, thus appearing less lit. To someone not familiar with how light works this might seem strange when shown like this - out of context, however this is how light behaves in the real world! Darker objects reflect less light.

    I find it useless to ask what someone who hasn't been involved with some kind of CGI, thinks about this kind of stuff, unless it's a final image/render, because a meaningful answer requires some insight.
    That's too bad, though, because it means that CGI artists/programmers are more or less on their own :)

    ReplyDelete
  20. Oh, by the way, you said:
    "the entire renderer is a actually just a module".

    Why "just" - a dll is absolutely the right way to go.
    But I was not (well, not entirely) referring to the module-level, but I was thinking more on the class and api design and the interaction between the objects.

    Projects can greatly benefit when future changes are considered during the design phase, because (ideally) the software ends up being constructed in such a way that the addition of features is made as painless as possible.

    Are you (your coding team) familiar with Go4 Design Patterns?
    I was rather surprised when I realized that there are many developers who consider them to be something abstract and theoretical, but in fact they address very practical design problems, and are very powerful and flexible.
    Some people come up with something similar after accumulating the experience with dealing with such problems themselves - in fact, Patterns are the result of industry experience and best practices.
    Have you used some of them in the engine?
    If, not I think investing time to understand the concepts behind them is well worth the wile, and your projects will crucially benefit from this knowledge.

    ReplyDelete
  21. Hey Thomas, have a look at this:
    http://developer.download.nvidia.com/presentations/2010/futuregameon/LouisBavoil_ModernRealTimeRenderingTechniques.pdf

    Maybe you could find some ideas here on how to make hpl3 look amazing

    ReplyDelete
  22. Thanks for the link, not seen it and it was a good overview of a few tech bits. I think I have detailed papers on all of them, but always good to have a simple overview.

    ReplyDelete
  23. Really looking forward to your next game :) I bought both Amnesia and Penumbra Overture although Penumbra Overture has a lot of graphical glitches and a pause problem but it could be the edition I have. I wish I knew how to do these things might look up open gl

    ReplyDelete
  24. great stuff Thomas really great stuff im excited for you guys i've always wanted to be a game devoloper wish i could work for you guys lol be cool to work with my favorite dev team.

    ReplyDelete
  25. besides graphics maybe a physics engine update? I mean newton is ok and everything but since you guys have money now, you could look into havok or apex which has fully destructible environments, cloth and fluid simulations.

    Umbra occlusion booster instead of the CHC you have? Or maybe your version is better who knows.

    The animations and AI could be greatly improved as well. I really wanted that corpse in the morgue in Amnesia to slowly stand up from the table and turn its head towards the player.

    What would be really unique but is probably way too hard to do is ability to burn things. Like a candle would burn a piece of cloth.

    http://software.intel.com/en-us/articles/an-overview-of-procedural-fire/

    Just an idea :)

    ReplyDelete
  26. @Frictional:

    You could update the Frictional Games site: Amnesia is still listed in the "In Development" submenu...

    ReplyDelete
  27. contd.
    And in the game description, it even says:

    "Amnesia: The Dark Descent - Not much is known about this upcoming but exciting game from Frictional Games. [...]"

    You probably haven't changed that since it was called "Unknown".

    BTW, I solved the first (easier) puzzle on the old Unknown site - the spiders-related quote from Penumbra. What was the solution for the second part? Whit all the numbers?
    (And what was the text box for?)

    ReplyDelete
  28. There is a LONG thread on the forum somewhere with discussions and some people eventually finding the solution.

    ReplyDelete
  29. Found it, OMG, I you got so many of us frustrated, LOL!!!

    =======================================================
    Quote (Thomas, page 13 (symbolical...), post 128):
    -------------------------------------------------------
    "I am awfully sorry, but there have been an error in the puzzle and it has now been fixed.

    The line
    8, 6, 9, 6, 11, 8, 13,
    has been expanded to:
    8, 6, 9, 6, 11, 8, 13, 10, 15, 8, 11, 4, 9,

    Website has been updated..."
    =======================================================
    Link:
    http://www.frictionalgames.com/forum/thread-2375-post-24572.html#pid24572

    ReplyDelete
  30. But what was the solution? The puzzle is gone now, and the people PM each other so others could give it a try, so there's no answer anywhere on that thread.

    ReplyDelete
  31. Congratulations as always, Thomas. Posts like these are my favourite ones. : )

    ReplyDelete
  32. This might interest you thomas:

    http://themadoverdose.blogspot.com/2010/10/top-10-budget-games-to-play-for.html

    Amensia is on their Top 10 List of games for halloween. :)

    ReplyDelete
  33. Sunlight and grass (as seen in YouTube video) ! Maybe I will love the next Frictional game even move than I loved Amnesia :)

    ReplyDelete
  34. This is really impressive, man! I've played all three Penumbra games and Amnesia, so witnessing the new "super secret" game being developed is a pretty neat thing! Another thing I'm excited about is the fact that you're working with outside environments and terrain, meaning you're upcoming editors for the game (if released without charge I hope) will incorporate this new tech and more. I loved the HPL2 editors for Amnesia, but I felt so limited knowing I was within the bounds of having to base my story off an indoor environment and atmosphere. I remember some guy made their own story based in an outdoor environment but to be honest it wasn't pretty :P. Anyways, good luck to you and the rest of Frictional Games with this project and hopefully any future projects to follow!

    ReplyDelete
  35. This is really impressive, man! I've played all three Penumbra games and Amnesia, so witnessing the new "super secret" game being developed is a pretty neat thing! Another thing I'm excited about is the fact that you're working with outside environments and terrain, meaning you're upcoming editors for the game (if released without charge I hope) will incorporate this new tech and more. I loved the HPL2 editors for Amnesia, but I felt so limited knowing I was within the bounds of having to base my story off an indoor environment and atmosphere. I remember some guy made their own story based in an outdoor environment but to be honest it wasn't pretty :P. Anyways, good luck to you and the rest of Frictional Games with this project and hopefully any future projects to follow!

    ReplyDelete

Note: only a member of this blog may post a comment.