Couple months ago I decided to master shadow techniques for mobile environment, I didn't know at the time would take that much effort. After some serious reading and googling I noticed that there are nothing on interwebs how to do it at least at mobile but that didn't discouraged me.
Shadow mapping seems to be only viable technique for general case.(don't forget that Blinn shadows can do miracles in some special cases). But normal shadow mapping algorithm need really big textures to get enough precision to look good and only give hard edges. But even normal shadow mapping is bit pain for gles2.0 because depth texture is not part of standard but an extension which penetration is not that good.
Also there are no floating points textures. This problem is easily solve by packing depth value which is float to int bits by hand and outputting values to color texture. This is needed to do reversed when reading shadow values. So we got hard and ugly shadows. Pic is brightened to show the artifacts more clearly. Shadow map resolution is 1024x1024 and look horrible.
Because I already use full color texture just for depth. VSM start look a really good option. If just packing depth to red and green channels and depth squared to blue and alpha channels the data amount statys a same but there is many advantages. This shadow map texture can be blurred with efficient Gaussian blur, hardware bilinear or anisotropic filtering can be used. Even mipmap chain can be created. Biggest con is that shadows can bleed light a bit in some cases but even that can be overcomed. For mobile standard version of VSM is not suitable becouse of branching but that can be fixed with ternary operation.
512x512 shadow map texture with VSM, filtered with 9x9 kernel Gaussian blur and hardware trilinear filtering. Notice how VSM fix shadow acne and yagged edges without really big shadow map.
This run around 30fps on my device with sports with adreno205 GPU.
For vsm 256x256 is usually good enough.
Full source of VMS shader with one spotlight here
Shadowmap generation shader can be found here
Kalle Hämäläinen Portfolio
This blog is for my projects that I am proud of. Not all of these are finished but every single one has taught me something. Projects are in chronological order starting from early 2011. From older projects I don't have that much media or memories left. Just let say that there is lot of projects before that point but nothing that fancy to show.
torstai 5. huhtikuuta 2012
torstai 29. maaliskuuta 2012
Gaussian blur for gles2.0
For box2dlights I needed soft shadows and initial guess was blur is the key. Problem was that Gaussian blur can be really heavy especially on mobile devices where GPU memory bandwith can be really low.
I tried many different tricks but it was just too slow. Thankfully I didn't sleep at signal processing lectures and I didn't wasted my time any of those brute force implemenations but instead used separated exis kernel from start. But for getting enough blur I needed at least 9x9 kernel which mean 18 samples and that was still too many. Then I found this efficient-gaussian-blur-with-linear-sampling and method was almoust fast enough but on some devices it just hit against brick wall(namely powerVR gpu's)
Then I realized that I need to calculate texture coordinates on vertex shader and pass those at varyings to prevent "dependant" texture reads on this problematic gpu's.
Full source of shader is here http://pastebin.com/QSbR5Z8T
Using it is really easy just pass fbo sizes as uniform and which pass is nex as another uniform. shader.setUniformf("dir", 1f, 0f); correspond a horizontal pass. This way you can use one shader for both pass and any fbo size without touching there shader code.
Gaussian blur is one basic post proces effect that is used everywhere I have used this shader with good results for basic blurring, bloom, SSAO, VSM, 2d water rendering.. etc. So it's really important have quality and performant shader for this.
I tried many different tricks but it was just too slow. Thankfully I didn't sleep at signal processing lectures and I didn't wasted my time any of those brute force implemenations but instead used separated exis kernel from start. But for getting enough blur I needed at least 9x9 kernel which mean 18 samples and that was still too many. Then I found this efficient-gaussian-blur-with-linear-sampling and method was almoust fast enough but on some devices it just hit against brick wall(namely powerVR gpu's)
Then I realized that I need to calculate texture coordinates on vertex shader and pass those at varyings to prevent "dependant" texture reads on this problematic gpu's.
Full source of shader is here http://pastebin.com/QSbR5Z8T
Using it is really easy just pass fbo sizes as uniform and which pass is nex as another uniform. shader.setUniformf("dir", 1f, 0f); correspond a horizontal pass. This way you can use one shader for both pass and any fbo size without touching there shader code.
Gaussian blur is one basic post proces effect that is used everywhere I have used this shader with good results for basic blurring, bloom, SSAO, VSM, 2d water rendering.. etc. So it's really important have quality and performant shader for this.
tiistai 27. maaliskuuta 2012
Box2dLights
Some how light and light behavior is always fascinated me. Long time ago I noticed that I can do some 2d lights with textures and blendfuncs. Basic model was something like this.
Render scene.
Clear alpha channel.
Render lights to alpha channel with glBlendFunc(GL_SRC_ALPHA, GL_ONE)
Render fullscreen quad with glBlendFunc(GL_ONE, GL_DST_ALPHA)
This give lights and shadows that blend together nicely. But this way you can't get dynamic shadows.
When I coded Boxtrix I did get idea that was too crazy to work. Everyone said that it's not gonna work but I still wanted to test it. Plan was to simulate lights rays using box2d raycasting. After couple hours first prototype was working and looked really ugly but tech seemed to work great.
After Boxtrix was finished I noticed that raycasting lights have really great api and usage is simple. User can add just lights and then one line of code to render lights. That was amazing allready but there was tons of features at wishlist. Softshadows, gles2.0 support, way to query if something is in shadows/lights, lights filters etc. Biggest problem was that usually you don't have alpha channel at render target when you are coding against android. Luckily gl es2.0 solved almoust every problem.
Rendering pipeline goes in box2dLights with gl es 2.0 pretty much like this.
Render scene.
Construct light volumes using crazy amount of raycasts.
Render light volumes to small fbo.
Blur fbo. Using really fast two pass shader that use separate convolution and hardware bilinear filtering tricks. 10samples for 9x9 kernel.
Render lightmap over scene using custom shader that render shadows and lights in one pass.
Box2dLights is complex and powerfull beast but using it is still really simple. Least half dozed published games is using it and more to come. It's opensource and license is compatible with LibGDX license so it can be used for commercial projects. http://code.google.com/p/box2dlights/
Performance is better than any full gpu solution that I have tested and most of mobile games is fragment shader limited anyway so it's good to use CPU to share some heavy lifting. More info at google code page.
Render scene.
Clear alpha channel.
Render lights to alpha channel with glBlendFunc(GL_SRC_ALPHA, GL_ONE)
Render fullscreen quad with glBlendFunc(GL_ONE, GL_DST_ALPHA)
This give lights and shadows that blend together nicely. But this way you can't get dynamic shadows.
When I coded Boxtrix I did get idea that was too crazy to work. Everyone said that it's not gonna work but I still wanted to test it. Plan was to simulate lights rays using box2d raycasting. After couple hours first prototype was working and looked really ugly but tech seemed to work great.
After Boxtrix was finished I noticed that raycasting lights have really great api and usage is simple. User can add just lights and then one line of code to render lights. That was amazing allready but there was tons of features at wishlist. Softshadows, gles2.0 support, way to query if something is in shadows/lights, lights filters etc. Biggest problem was that usually you don't have alpha channel at render target when you are coding against android. Luckily gl es2.0 solved almoust every problem.
Rendering pipeline goes in box2dLights with gl es 2.0 pretty much like this.
Render scene.
Construct light volumes using crazy amount of raycasts.
Render light volumes to small fbo.
Blur fbo. Using really fast two pass shader that use separate convolution and hardware bilinear filtering tricks. 10samples for 9x9 kernel.
Render lightmap over scene using custom shader that render shadows and lights in one pass.
Box2dLights is complex and powerfull beast but using it is still really simple. Least half dozed published games is using it and more to come. It's opensource and license is compatible with LibGDX license so it can be used for commercial projects. http://code.google.com/p/box2dlights/
Performance is better than any full gpu solution that I have tested and most of mobile games is fragment shader limited anyway so it's good to use CPU to share some heavy lifting. More info at google code page.
torstai 16. helmikuuta 2012
Lonely miner.
Lonely miner was made for Ludum dare #22. It's game dev competition where there are strict time limit and no prizes. Competition is very popular and usually entries are really good quality if you take account the 48hour timer limit and that every content has to be done withing timeframe and by coder himself.
It was my first Ludum dare and I was planned to use that competition as motivator to do fluid simulator. I didn't worry about theme or gameplay that much.
Gameplay is pretty basic: You controll the protagonist and your mission is dig deeper and watch out the nuclear waste. Gameplay contain just moving, jumping and bombs. Main selling point here is technical aspects. Game contain fluid simulator, dynamic lights and shadows, destructable ground, physics particles and so on. Game is basically just a neat tech demo. I even made controls for Android but I didn't have time to optimize the code for mobile devices and its get too slow when screen is full of fluid.
Ludum dare is so much fun that I can warmly recommend it to everybody.
Game can be tested here: http://www.ludumdare.com/compo/ludum-dare-22/?action=preview&uid=8170
tiistai 14. helmikuuta 2012
Boxtrix.
This was my first finished Android game. I invented original idea for Kinect but the idea needed too accurate hand tracking so that idea was deserted. I code original prototype with Slick2d in couple hours and it was totally playable and fun even back then. Project name was Kinectris. prototype applet
After couple months after that University was starting from summer break and I signed up for Game programming course. I decided to work solo and do android game. I wanted to learn all about Android and finally give Kinectris another chance. Name evolved to Boxtris and later I renamed it Boxtrix becouse there was iOS game that have same name and similar gameplay(physic puzzle).
Gameplay is classic Tetris but with new twist. All blocks are physic object that player can rotate and move freely. Suddendly simple game is complex and hard even with really slow pace of falling blocks.
Multitouch support and intuitive controlls help with this but game is totally playble even with mouse.
Coding this game was bit tedious becouse prototype was ready so fast but for polished game I used over 300hours. Prize for my hard work was excellent grade for the course(5/5) and over ten thousand downloads
Download game here: https://market.android.com/details?id=boxtrix.android
Or play it as applet: http://www.students.tut.fi/~hamala26/boxtris-applet/
Unnamed tower def game.
We started this game with three man team and my title was game desinger. We started game with slick2d but after some point we decided that we need more performance and switched to LibGDX. Team leader was Gudradain from Canada and third member was Ra4king from USA. We did have lot of fun and we writed the game code base at least five times from the scratch. After somepoint our roles did get mixed and I was graphical programmer and I also did lot of gameplay elements. Gameplay was constantly changing that caused lot of rewriting. This was mostly educational project but damn we learned a lot. With this project I finally started to grasp OpenGL and team working. Sadly we didn't have graphical designer or artist so game look a bit crappy.
We even ported game to Android but we didn't know anything about Android back then so we was just learning and testing the platfrom. Performance with all those enemies with individual pathfinding was bit lacking but not that much. Game run about 20-40fps on my Huawei depending how many enemies there is on screen. Game supported thousands of enemies same time so I was happy with that.
We tried some nice features like individual pathfinding, spell casting and four enemy base at once. Every enemy camp have one of four basic element. Fire, water, earth and air. Each element have weak and strong points and elements can be mixed. Idea was cool but we did't nail it well enough.
You can test game prototype there: http://www.students.tut.fi/~hamala26/def-applet/
ShapeTronic!
I made this game for Slick2d game competition 2011 and it won second place.
Gameplay is unique breakout variant in surrelistic atmosphere. I really like the audiovisual outcome. Gameplay is polished but bit short.
Game use Slick2d, lwjgl, phys2d and great piano masterpiece from William Cushman's.
Test game at: http://gamejolt.com/online/games/arcade/shapetronic/5419/
ps. You need to allow game to use native resources becouse of openGL wrapper.
Tilaa:
Blogitekstit (Atom)