<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-1395042463187467672</id><updated>2011-12-19T18:14:46.085+01:00</updated><category term='reflection'/><category term='refraction'/><category term='Microsoft'/><category term='tools'/><category term='jelly'/><category term='global ilumnation'/><category term='ray tracing'/><category term='ai'/><category term='apple'/><category term='steering behaviors'/><category term='light'/><category term='rendermanager'/><category term='collisions'/><category term='HD'/><category term='robot'/><category term='playstation'/><category term='ambient'/><category term='jellyreef'/><category term='tracing'/><category term='kinect'/><category term='vehicles'/><category term='objective-c'/><category term='tweeter'/><category term='iphone'/><category term='collision detection'/><category term='separating axis'/><category term='HKU'/><category term='render'/><category term='fiat'/><category term='ray'/><category term='occlusion'/><category term='animation'/><category term='gi'/><category term='turbina'/><category term='imac'/><category term='resource'/><category term='maya'/><category term='box boxes'/><category term='.net'/><category term='Surface'/><category term='physics'/><category term='code'/><category term='file'/><category term='reef'/><category term='artificial intelligence'/><category term='last fm last.fm pasta spinach'/><category term='car'/><category term='xml'/><category term='caustics'/><category term='basic'/><category term='java'/><category term='Euler'/><category term='silverlight'/><category term='rockets'/><category term='tutorial'/><category term='engine'/><category term='own'/><category term='xna'/><category term='cube'/><category term='rederjob'/><category term='normal'/><category term='game'/><category term='move'/><category term='C#'/><category term='parallax'/><category term='xcode'/><category term='gdc'/><category term='3D'/><category term='build'/><category term='ipod'/><category term='mac'/><category term='720p'/><category term='Garden'/><category term='modeling'/><category term='dymaics'/><category term='gamescom'/><category term='Dutch'/><title type='text'>Furious Pixels</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-14139426104547342</id><published>2011-10-23T00:11:00.001+02:00</published><updated>2011-10-23T00:11:55.632+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='Euler'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='rendermanager'/><category scheme='http://www.blogger.com/atom/ns#' term='caustics'/><category scheme='http://www.blogger.com/atom/ns#' term='render'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='collision detection'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><category scheme='http://www.blogger.com/atom/ns#' term='collisions'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='parallax'/><category scheme='http://www.blogger.com/atom/ns#' term='rederjob'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Building Your Own Game Engine - Graphics</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;This is the last one in the series of articles that go through the architecture of a small game engine for a small game, &lt;a href="http://www.thejellyreef.com/"&gt;The Jelly Reef&lt;/a&gt;. The very last thing that was implemented into the game was the graphics. The art team in the first weeks  of development was looking for the right look for the game. In mean time the our designer was looking for the right feel, we decided give this top priority and started writing the gameplay code and all the infrastructure. The graphics would wait up until we know what the game will be and look like.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-hAVW90tinvA/TqM9labIMDI/AAAAAAAAA4o/H76nK_boSJY/s1600/SpriteSheet_Cannon.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" id=":current_picnik_image" src="http://2.bp.blogspot.com/-i3tD0nLb0KM/TqM-KgB6woI/AAAAAAAAA40/hoZFKq5YyYE/s1600/16947605614_HQwFC.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;With four talented drawing artist on the team, we knew that the game will be hand painted for the most part and that we will use sprite sheets for all the animations. You would expect this to lead to a 2D rendering system. After all, the math in all previous articles was 2D and Vector2D's were all over place. But at the same time we wanted to have some depth to our top down perspective and considered using parallax effect to achieve that. Using parallax would have some drawbacks and might be difficult to tweak or draw art for. Instead we opted against it, so the rendering system is actually a 3D one. There is a 3D projective camera and 3D triangles are being send to the GPU so the depth is inherent.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The goal was to have a system that can render static images in layers that would make up the level, some animated sprites for the object in the game and lots of bubbles. All this without killing performance, of course. Almost everything is drawn alpha blended, but some things like the GUI overlay and seaweed would require special treatment. Additionally we also wanted to be able to scale and tint all the sprites.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;In the core of our graphics system is the RenderJob which the only thing that our render manager can render. From its fields it's very clear how we implemented the needed functionality.&lt;/div&gt;&lt;pre class="brush: java"&gt;public enum RenderPass { AlphaTested,&lt;br /&gt;                         AlphaBlended,&lt;br /&gt;                         Overlay }&lt;br /&gt;&lt;br /&gt;// All the data need for rendering a object on screen&lt;br /&gt;// A class rather than a struct to enable reference storing&lt;br /&gt;public class RenderJob : IComparable&amp;lt;RenderJob&amp;gt;&lt;br /&gt;{&lt;br /&gt;  // In which pass should the geometry be rendered&lt;br /&gt;  public RenderPass RenderPass;&lt;br /&gt;&lt;br /&gt;  // Used for depth sorting in alpha-blended jobs&lt;br /&gt;  public float Height;&lt;br /&gt;&lt;br /&gt;  // The vertices in world or model coordinates&lt;br /&gt;  public VertexPositionTexture[] Vertices;&lt;br /&gt;&lt;br /&gt;  // Indices of the vertices&lt;br /&gt;  public int[] Indices;&lt;br /&gt;&lt;br /&gt;  // If vertices are in model coordinates a suitable transform&lt;br /&gt;  // matrix should be submited, if vertices are in world&lt;br /&gt;  // coordinates the identity matrix should do fine&lt;br /&gt;  public Matrix WorldMatrix;&lt;br /&gt;&lt;br /&gt;  // A texture to draw this geometry with&lt;br /&gt;  public Texture2D Texture;&lt;br /&gt;&lt;br /&gt;  // Allows the texture to be tinted with a solid color&lt;br /&gt;  public Vector4 Tint;&lt;br /&gt;&lt;br /&gt;  // Allows a render job to disable the caustics&lt;br /&gt;  public bool DisableCaustics;&lt;br /&gt;&lt;br /&gt;  // Create new render job&lt;br /&gt;  public RenderJob()&lt;br /&gt;  {&lt;br /&gt;    Tint = new Vector4(1, 1, 1, 1);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Compares two render jobs&lt;br /&gt;  public int CompareTo(RenderJob other)&lt;br /&gt;  {&lt;br /&gt;     if (Height &amp;gt; other.Height)&lt;br /&gt;       return 1;&lt;br /&gt;     if (Height &amp;lt; other.Height)&lt;br /&gt;       return -1;&lt;br /&gt;     return 0;   // ==&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;The rendering in our game is handled by the rendering manager and all entities that would like to be rendered need to implement the IRenderable inteface.&lt;/div&gt;&lt;pre class="brush: java"&gt;public interface IRenderable&lt;br /&gt;{&lt;br /&gt;  IEnumerable&amp;lt;RenderJob&amp;gt; GetJobs();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;The manager simply goes over all the entities and fills up three lists, one for each render pass. The list with Alpha blended jobs gets sorted by height, from the lowest to the highest. Then the lists are rendered in the order they were declared in the enum aboove.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Each level can have up to five layers and they are rendered as any other alpha blended job. The height, and hence the parallaxing amount, can be set for each layer. The size is automatically determinate to fit the level size with some clearing for the parallaxing. The level layers can be drawn as layers in Photoshop. In the game, their alignment at the the middle of the screen would be the same as while drawing. This means that parallaxing does not interfere with gameplay.The game take place underwater. I really wanted for us to get that feeling early on by adding water caustics and started looking for real-time solutions on the subject. In the end none of the options looked convincing enough and many were too computationally expensive. We quickly opted for a precalculated sequence of images that tile in both, space and time. The image is applied in the shader and the strength of the effect can be tweaked per level. The shader also scales the effect with depth, adding another subtle depth cue.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This wraps up the articles series. I hope people will find them useful. If anyone needs more info, you can drop a comment below the article. &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;A new version of the engine is already in the making. It's based on a somewhat different concept, written in C++ and trying to be as platform independent as possible. &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-14139426104547342?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/14139426104547342/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/10/building-your-own-game-engine-graphics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/14139426104547342'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/14139426104547342'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/10/building-your-own-game-engine-graphics.html' title='Building Your Own Game Engine - Graphics'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-i3tD0nLb0KM/TqM-KgB6woI/AAAAAAAAA40/hoZFKq5YyYE/s72-c/16947605614_HQwFC.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-8792640605489593477</id><published>2011-09-27T17:27:00.002+02:00</published><updated>2011-09-27T17:27:52.354+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Euler'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='collision detection'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='physics'/><category scheme='http://www.blogger.com/atom/ns#' term='separating axis'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><category scheme='http://www.blogger.com/atom/ns#' term='collisions'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='reef'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Building Your Own Game Engine - Collisions</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;This article discusses collision detection and resolution. It directly follows my previous article on &lt;a href="http://draft.blogger.com/blogger.g?blogID=1395042463187467672"&gt;physics&lt;/a&gt;. I have decided for two separate articles so that the text doesn't run longer than your (and mine as well) attention span.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Most physics engines combine collision detection system with the rest of the engine, but many also allow the one to used without the other. In the case of The Jelly Reef, both of the systems are simple and completely separated except for the objects they act upon. Basically, first all the forces are applied and paths integrated. Then using the new positions collisions are found and resolved.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;To do collision detection we first need to have bodies that collide. Early on, we decided that for all objects in the game the collision shape will be approximated with either a disk or a rectangle. Moreover, every objects stores both and the two are always in sync. The disk is also circumcircle of the rectangle at all time. Having a disk around the rectangle allows for early outs when doing collision checking, as disk to disk is a very cheap test to do.&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush: java"&gt;public class BaseGameEntity : ISceneNode&lt;br /&gt;{&lt;br /&gt;  // Some code...&lt;br /&gt;&lt;br /&gt;  [Description("Bounding radius of the entity. Used for collision detection")]&lt;br /&gt;  public float BoundingRadius&lt;br /&gt;  {&lt;br /&gt;    get { return boundingRadius; }&lt;br /&gt;    set&lt;br /&gt;    {&lt;br /&gt;       float s = value / boundingRadius;   // scale&lt;br /&gt;       boundingRadius = value;&lt;br /&gt;       scale *= s;&lt;br /&gt;     }&lt;br /&gt;  }&lt;br /&gt;  protected float boundingRadius;&lt;br /&gt;&lt;br /&gt;  [Description("Half dimensions in a single vector.")]&lt;br /&gt;  public Vector2D Dimensions&lt;br /&gt;  {&lt;br /&gt;      get { return scale; }&lt;br /&gt;      set&lt;br /&gt;      {&lt;br /&gt;          scale = value;&lt;br /&gt;          // Set the bounding radius so that a recatangle with the given&lt;br /&gt;          // dimensions will fit in the disk.&lt;br /&gt;          boundingRadius = (float)Math.Sqrt(value.X * value.X + value.Y * value.Y);&lt;br /&gt;       }&lt;br /&gt;  }&lt;br /&gt;  protected Vector2D scale;   &lt;br /&gt;&lt;br /&gt;  // some more code...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;The game also features some static geometry in the form of walls and these were created from linear segments.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The collision system every frame over the objects and tests for collision among them and collisions against the walls. Each collision is stored in a array of Contact structures. The structure holds all the data that is needed to handle this contact.&lt;/div&gt;&lt;pre class="brush: java"&gt;public struct Contact&lt;br /&gt;{&lt;br /&gt;  // Holds the first bodie in the contact&lt;br /&gt;  public BaseGameEntity FirstBody;&lt;br /&gt;  &lt;br /&gt;  // The second of these can be null, for contacts with the level&lt;br /&gt;  public BaseGameEntity SecondBody;&lt;br /&gt;&lt;br /&gt;  // Holds the direction of the contact in world coordinates.&lt;br /&gt;  public Vector2D ContactNormal;&lt;br /&gt;&lt;br /&gt;  // Holds the depth of penetration at the contact.&lt;br /&gt;  public float Penetration;&lt;br /&gt;&lt;br /&gt;  // A mechanism to detect collisions to raise event but &lt;br /&gt;  // not reslove in the physics engine&lt;br /&gt;  public bool Resolved;        &lt;br /&gt;&lt;br /&gt;  // A hash code uniquely defining the contact of these two entities&lt;br /&gt;  // Makes sure that each pair of entities is checked exactly once&lt;br /&gt;  public override int GetHashCode()&lt;br /&gt;  {&lt;br /&gt;     int hash = firstBody.GetHashCode();&lt;br /&gt;     if (secondBody != null)&lt;br /&gt;        hash ^= secondBody.GetHashCode();&lt;br /&gt;     return hash;&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;For performance reasons we set a predetermined number of contacts that we can have in a single frame, all others will have to wait for the next frame. We also store all the contacts in a preallocated array so that we avoid allocating new objects every frame and strain the garbage collector.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;As I mentioned we have two shapes for collision geometry. With the linear segments for the walls this gives us 3 object types that can collide. Walls will not collide with walls, that leaves us with five combinations of shapes we need to handle. For all cases we use the separating axes theorem.&lt;br /&gt;The theorem states that if the two convex objects are not interpenetrating there is an axis for which the projections of the two object will not overlap. This test is very robust and general, straight forward to implement and easy to debug. It also gives much of the needed information we need for resolution. The contact normal is the axis itself and the interpenetration is the amount of overlap along it.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The problem is of course to find this axis. For polygons such axises run through the vertices or are perpendicular the the line segments. For an intersection test among two rectangles that would yield 16 potential separating axises to be tested. We tackled the problem of optimizing the number of axises for each of the cases separately.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;As a en example I will explain a very straight forward test from the game on the drawing below, an axis aligned rectangle against a linear segment.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-jNa-_fIAblE/Tj1sj_72ZGI/AAAAAAAAA30/U9K0wyx8lu8/s1600/CRW_0721.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-jNa-_fIAblE/Tj1sj_72ZGI/AAAAAAAAA30/U9K0wyx8lu8/s1600/CRW_0721.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;From the drawing we see that one testing axis is aligned with the line segment and the other one is perpendicular to it. The rectangle and its projections are drawn in blue while the line segment and its projections in red. On the drawing we can see that the projection on the axis perpendicular to the line segment there is no overlap, so we have found the separating axis. The drawing also clearly shows that I have a cool whiteboard, but enough of that, lets show the code for this test.&lt;/div&gt;&lt;pre class="brush: java"&gt;public static bool AARectToWall(&lt;br /&gt;   Vector2D centerR, Vector2D halfDimR,&lt;br /&gt;   Vector2D start,       Vector2D end)&lt;br /&gt;{&lt;br /&gt;  // Create first axis &lt;br /&gt;  Vector2D axis1 = (end - start);&lt;br /&gt;  // Normalization gives interpretation to the intervals &lt;br /&gt;  axis1.Normalize();&lt;br /&gt;&lt;br /&gt;  // Project the line segment by projection the end points&lt;br /&gt;  float Sp = axis1.Dot(start);&lt;br /&gt;  float Ep = axis1.Dot(end);&lt;br /&gt;  // Make the interval &lt;br /&gt;  CreateInterval(ref Sp, ref Ep);&lt;br /&gt;&lt;br /&gt;  // Project rectangle - All four vertices&lt;br /&gt;  float rectLeft;&lt;br /&gt;  float rectRight;&lt;br /&gt;  // First  calculate the vertices&lt;br /&gt;  Vector2D A = centerR + halfDimR;&lt;br /&gt;  Vector2D C = centerR - halfDimR;&lt;br /&gt;  Vector2D B = new Vector2D(A.X, C.Y);&lt;br /&gt;  Vector2D D = new Vector2D(C.X, A.Y);&lt;br /&gt;&lt;br /&gt;  float Ap = axis1.Dot(A);      // Project vertex A&lt;br /&gt;  float Bp = axis1.Dot(B);      // Project vertex B&lt;br /&gt;  float Cp = axis1.Dot(C);      // Project vertex C&lt;br /&gt;  float Dp = axis1.Dot(D);      // Project vertex D&lt;br /&gt;&lt;br /&gt;  // Cretate inital interval&lt;br /&gt;  rectLeft = Bp;&lt;br /&gt;  rectRight = Ap;&lt;br /&gt;  CreateInterval(ref rectLeft, ref rectRight);&lt;br /&gt;  // Extend it&lt;br /&gt;  AddInterval(ref rectLeft, ref rectRight, Cp);&lt;br /&gt;  AddInterval(ref rectLeft, ref rectRight, Dp);&lt;br /&gt;&lt;br /&gt;  // If there is no overlap, we have found the separating axis&lt;br /&gt; if (IntervalOverlap(Sp, Ep, rectLeft, rectRight)  &amp;lt;= 0.0f)&lt;br /&gt;    return false;&lt;br /&gt;&lt;br /&gt;  // Second axis, perpendicular to the segment&lt;br /&gt;  Vector2D axis2 = axis1.Perp;&lt;br /&gt;&lt;br /&gt;  // The line segment projects to a single point&lt;br /&gt;  Sp = axis2.Dot(start);&lt;br /&gt;&lt;br /&gt;  // Project the vertices&lt;br /&gt;  Ap = axis2.Dot(A);&lt;br /&gt;  Bp = axis2.Dot(B);&lt;br /&gt;  Cp = axis2.Dot(C);&lt;br /&gt;  Dp = axis2.Dot(D);&lt;br /&gt;&lt;br /&gt;  // Create the rect interval&lt;br /&gt;  rectLeft = Bp;&lt;br /&gt;  rectRight = Ap;&lt;br /&gt;  CreateInterval(ref rectLeft, ref rectRight);&lt;br /&gt;  AddInterval(ref rectLeft, ref rectRight, Cp);&lt;br /&gt;  AddInterval(ref rectLeft, ref rectRight, Dp);&lt;br /&gt;&lt;br /&gt;  // Check if the second axis e separating  &lt;br /&gt;  if (IntervalOverlap(Sp, Sp, rectLeft, rectRight) &amp;lt;= 0.0f)  &lt;br /&gt;    return false;&lt;br /&gt;  else&lt;br /&gt;     return true;   // No axis found, shapes are intersecting&lt;br /&gt;} &lt;/pre&gt;&lt;div style="text-align: justify;"&gt;The next step after detection of collisions is to call all the subscribers for each type of collision. This is where gameplay code might be implemented I it was discussed in detail in the article on gameplay. The event can choose to set the resolved flag to true, so the collision manager will not resolve the collision. This can have many uses. When a jelly hits a rapidly rotating propeller for example, the jelly will not bounce back but rather be removed from the scene and replaced with some gooey jelly pieces.&lt;br /&gt;The last step is to resolve the unresolved contacts. This is done by simply moving them along the contact normal. In the case of a collision with the level geometry, the object is simply moved the full penetration depth. In the case of two objects, both are moved by taking their mass into account. The flowing piece of code, adapted from from &lt;a href="http://www.amazon.com/Physics-Development-Kaufmann-Interactive-Technology/dp/012369471X"&gt;Game Physics Engine Development&lt;/a&gt;, does exactly that.&lt;/div&gt;&lt;pre class="brush: java"&gt;// Some code ...&lt;br /&gt;BaseGameEntity first = contact.FirstBody;&lt;br /&gt;BaseGameEntity second = contact.SecondBody;&lt;br /&gt;                &lt;br /&gt;// The movement of each object is based on inverse mass, so total that&lt;br /&gt;float totalInverseMass = first.InverseMass + second.InverseMass;&lt;br /&gt;                &lt;br /&gt;// If both have infinite mass, skip this contact&lt;br /&gt;if (totalInverseMass &amp;lt;= 0) return;&lt;br /&gt;                &lt;br /&gt;// Calculate amount of penetration resoluion per total inverse mass&lt;br /&gt;Vector2D movePerInverseMass = contact.ContactNormal *&lt;br /&gt;  (-contact.Penetration / totalInverseMass);&lt;br /&gt;                &lt;br /&gt;// Move 'em&lt;br /&gt;first.Position   += movePerInverseMass * first.InverseMass;&lt;br /&gt;second.Position -= movePerInverseMass * second.InverseMass;&lt;br /&gt;// More code...&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Hope this last few articles gave an inside into the bits and pieces of game development that are the not easiest to find information on. The next article is on graphics and will be the last one in the series as well. &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-8792640605489593477?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/8792640605489593477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/09/building-your-own-game-engine.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/8792640605489593477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/8792640605489593477'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/09/building-your-own-game-engine.html' title='Building Your Own Game Engine - Collisions'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-jNa-_fIAblE/Tj1sj_72ZGI/AAAAAAAAA30/U9K0wyx8lu8/s72-c/CRW_0721.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-5480373757106879882</id><published>2011-09-01T16:28:00.001+02:00</published><updated>2011-09-01T16:28:25.416+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Euler'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='collision detection'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='physics'/><category scheme='http://www.blogger.com/atom/ns#' term='separating axis'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><category scheme='http://www.blogger.com/atom/ns#' term='collisions'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='reef'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Building Your Own Game Engine - Physics</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;This is the first one of next two articles that will cover two very close subjects, physics and collision detection. Physics for games for the most part covers moving some bodies in the game world according to the laws of physics. As these bodies occupy some space in the world, we need to detect when collisions among this bodies occur and resolve them. I will assume the reader is familiar with Newton's laws of motion, since you are reading an article about making a game engine and physics in particular.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The Jelly Reef actually uses two somewhat separate physics systems. One used to move objects in the game around and it's completely entangled with the rest of the game. And there is another one, based on particles, used for some specific effects. Our game is not trying to simulate the real word or be realistic, so I decided we take simplistic approach, with plenty of shortcuts. First shortcut was to model the jellies and all other moving objects as point mass and this ignore any actual distribution of mass. Angular movement was not simulated at all, so no torques, no moments of inertia or in fact any physical angular property. This means we treat all objects as particles we can basically reuse the code from the particle. What follows are the properties of the particle class.&lt;/div&gt;&lt;pre class="brush: java"&gt;public class Particle&lt;br /&gt;{&lt;br /&gt;  // The position of the particle in world space&lt;br /&gt;  public Vector2D Position;&lt;br /&gt;&lt;br /&gt;  // Linear velocity of the particle in world space.&lt;br /&gt;  public Vector2D Velocity;&lt;br /&gt;&lt;br /&gt;  // Linear acceleration of the particle&lt;br /&gt;  public Vector2D Accleration;&lt;br /&gt;&lt;br /&gt;  // Damping is required to remove energy added&lt;br /&gt;  // through numerical instability in the integrator.&lt;br /&gt;  // Or to act as drag&lt;br /&gt;  public float Damping;&lt;br /&gt;&lt;br /&gt;  // Holds the inverse of the mass of the particle.&lt;br /&gt;  // It is more useful to have objects with&lt;br /&gt;  // infinite mass (immovable) than zero mass&lt;br /&gt;  // Also one division less&lt;br /&gt;  public float InverseMass;&lt;br /&gt;  //&lt;br /&gt;  public float Mass&lt;br /&gt;  {&lt;br /&gt;    get { return 1.0f / InverseMass; }&lt;br /&gt;    set { InverseMass = 1.0f / value; }&lt;br /&gt;  }&lt;br /&gt;  //&lt;br /&gt;  public bool HasFiniteMass&lt;br /&gt;  {&lt;br /&gt;    get { return InverseMass != 0.0f; }&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // Force accumulator, for dalamber's principle&lt;br /&gt;  public Vector2D ForceAccum;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Next we need to move these objects. Newtons laws are expressed as differential equations so the values are calculated using numerical integration. For this purpose we use Euler integration as it's very easy to implement, but it is not very precise.&lt;/div&gt;&lt;pre class="brush: java"&gt;public void Integrate(float dt)&lt;br /&gt;{&lt;br /&gt;  float duration = dt;&lt;br /&gt;&lt;br /&gt;  // Update linear position&lt;br /&gt;  Position += Velocity * duration;&lt;br /&gt;&lt;br /&gt;  // Work out the acceleration from the force&lt;br /&gt;  Vector2D resultingAcc = Accleration;&lt;br /&gt;  resultingAcc += ForceAccum * InverseMass;&lt;br /&gt;&lt;br /&gt;  // Update linear velocity from the acceleration&lt;br /&gt;  Velocity += resultingAcc * duration;&lt;br /&gt;&lt;br /&gt;  // Add drag&lt;br /&gt;  Velocity *= (float)Math.Pow(Damping, duration);&lt;br /&gt;&lt;br /&gt;  ForceAccum.Clear();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Time is continuous (except maybe in &lt;a href="http://en.wikipedia.org/wiki/Chronon"&gt;quantum mechanics&lt;/a&gt;, which beyond the scope of this article and my brain) and our simulation takes discreet steps into it, so errors get accumulated over time. This imprecision can build up and eventually make the simulation explode and I will return to this later. &lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Although we are not simulating the angular movement, we still need to know the orientation of the objects for both, gameplay and rendering purposes. The solution was to simply align the object to face their direction of movement. However this looks ugly when the direction of movement changes rapidly over few consecutive frames, so the orientation was in fact interpolated from the current one the desired one limiting the change with maximal angular velocity value. This piece of code was not really elegant of flexible and in future I would consider using &lt;a href="http://en.wikipedia.org/wiki/Spinor"&gt;spinors&lt;/a&gt; for this purpose.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;As I mentioned before we also employed a separate particle based physics system. This simple system simulated particles on which some forces can be applied. No contacts or hard constrains were imposed on the particles. The most used part of the system were the spring-damper systems.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-oZ1f0MD35z4/Tl6E0pYd1II/AAAAAAAAA4A/v07c3e2mn7o/s1600/SeaWeedDebug.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="308" src="http://2.bp.blogspot.com/-oZ1f0MD35z4/Tl6E0pYd1II/AAAAAAAAA4A/v07c3e2mn7o/s320/SeaWeedDebug.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;The seaweed was implemented with such a system. Each weed modeled as a two particles connected to each other with such a spring, while simultaneously having one of them being attached to the seabed with another spring. A third spring from the base to the tip tries to keep the form of the weed. On the image to the left we see the three springs in red using the debug drawing.&lt;br /&gt;The water motion also imposed forces on all particles in it. The smooth movement of the camera was also implemented using a spring. &lt;/div&gt;&lt;div style="text-align: justify;"&gt;Particles were used for the bubbles. Obviously the main aim of this dynamic system was to give feedback to the player while he/she plays by controlling the water.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;In an early version of the game the jellies had tentacles, which were modeled with a spring system, exactly like the one on the seaweed. Unlike the seaweed, the jellies move and this adds force to the spring system and tentacles become longer. I tried to remedy this by making the springs stiffer and that is where the Euler integration totally failed. As soon as the spring overextends, a force too large will be applied. In the next iteration the spring will overshoot again and in turn generate and even larger force, until the simulation explodes with the tentacles way outside the screen. This could have been solved by using better integrator like &lt;a href="http://gafferongames.com/game-physics/integration-basics/"&gt;RK4&lt;/a&gt; or Verlet Integration. It turned that the jellies look way better without the tentacles anyhow so I was of the hook. &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-5480373757106879882?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/5480373757106879882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/09/building-your-own-game-engine-physics.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/5480373757106879882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/5480373757106879882'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/09/building-your-own-game-engine-physics.html' title='Building Your Own Game Engine - Physics'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-oZ1f0MD35z4/Tl6E0pYd1II/AAAAAAAAA4A/v07c3e2mn7o/s72-c/SeaWeedDebug.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-2404726813274419016</id><published>2011-08-28T17:22:00.000+02:00</published><updated>2011-08-28T17:22:55.300+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Euler'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='collision detection'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='physics'/><category scheme='http://www.blogger.com/atom/ns#' term='separating axis'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><category scheme='http://www.blogger.com/atom/ns#' term='collisions'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='reef'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><title type='text'>Building Your Own Game Engine - Why Code Physics</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;The next two articles will cover two very close subjects, physics and collision detection. I will do so by going through the relevant pieces of The Jelly Reef's engine. But before I jump into that, I will first put a word or two on why (or why not) to develop your own physics system.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Writing physics for your game is difficult and time consuming task. Collision detection is a subject that alone might consume months of work. There are some superb solutions out there, like &lt;a href="http://www.box2d.org/"&gt;Box2D&lt;/a&gt;, that work right out of the...well box. Free and open source, this engine drives immensely big chunk of the indie hits in the last few years. Angry Birds is not all that different from the samples that come with the engine.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;But sometimes you just need to jump over the hoops yourself, and we did. The decision to code our own physics came was based on few facts we knew at the time:&lt;/div&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;Water, being the main element of gameplay is not part of any existing engine. &lt;/li&gt;&lt;li&gt;A full physics engine would be an overkill for this game and potentially difficult to control and tweak. &lt;/li&gt;&lt;li&gt;The gameplay would be tightly integrated with the physics and the collisions. &lt;/li&gt;&lt;li&gt;Most of the popular and well documented engines are writen in C++ and our game is in C#. &lt;/li&gt;&lt;li&gt;A lot of time still needs to go into integrating the engine into the game.&lt;/li&gt;&lt;li&gt;There is in fact quite a bit of text on how to do things yourself. I recommend &lt;a href="http://www.amazon.com/Physics-Development-Kaufmann-Interactive-Technology/dp/012369471X"&gt;Game Physics Engine Development&lt;/a&gt;, &lt;span id="btAsinTitle"&gt;&lt;a href="http://www.amazon.com/Game-Physics-Second-David-Eberly/dp/0123749034/ref=pd_sim_b_2"&gt;Game Physics&lt;/a&gt; and&lt;/span&gt;&lt;span id="btAsinTitle"&gt; &lt;a href="http://www.amazon.com/Real-Time-Collision-Detection-Interactive-Technology/dp/1558607323/ref=pd_sim_b_1"&gt;Real-Time Collision Detection.&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;I have had some bad experience with closed source engines and the next paragraph goes over it.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;I was working at ZootFly on a vehicle system for quite a bit. The ZEN game engine used in ZootFly employed NVidia Physx, so naturally I built on top of that. I was in awe by how simple it was to get some things running with Physx. In the next few months the more I worked with Physx the more I got to know it, and my respect for its developers grew even further. And then I had to do some stuff that the engine was clearly not made for (obvious when you look at the samples) and suddenly I was in a world of pain. Tweaking parameters didn't get me anywhere fast and as we had binary-only license there was not much else I could do. Eventually the problems were worked around, but the team made a decision to switch to &lt;a href="http://bulletphysics.org/"&gt;Bullet&lt;/a&gt; for their next project. It's open source and Erwin Coumans seems to be doing an awesome job of running it.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;So ultimately it's up to developers the make the decision when they know what they are making. For those that decide to go for coding their own physics and haven't done that before the next two articles should provide some insight.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-2404726813274419016?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/2404726813274419016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/08/building-your-own-game-engine-why-code.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/2404726813274419016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/2404726813274419016'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/08/building-your-own-game-engine-why-code.html' title='Building Your Own Game Engine - Why Code Physics'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-7564331133461739818</id><published>2011-05-05T11:46:00.000+02:00</published><updated>2011-05-05T11:46:27.424+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='reef'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Building Your Own Game Engine - Gameplay</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-pM6bflnHmzA/TcJver0UM3I/AAAAAAAAA2Q/rUEIQ0-vD-g/s1600/JellyConrnerPic.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-pM6bflnHmzA/TcJver0UM3I/AAAAAAAAA2Q/rUEIQ0-vD-g/s1600/JellyConrnerPic.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;This article will focus on gameplay, the part of the code that allows making the game fun. In a smaller game, like ours, the gameplay code can take substantial chunk of the whole code-base. The gameplay in The Jelly Reef was not scripted and completely integrated with the rest of the code; and as such written in C#. The separation between what can be considered engine code and gameplay code was mostly logical but still some physical structure was kept.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;There are generally four places where gameplay code goes in our engine. Of course, our primary gameplay element is the water itself as the player interacts with it. The implementation of the water waited for the concept of the game to be completely defined, so after we know what our game will be about we started building the water dynamics. Our first try was with simulated fluid dynamics, but after playing with few games and simulators that use fluid dynamics we realized that it might not be the best fit for The Jelly Reef. Fluid dynamics are somewhat difficult to program and even more difficult to make them run efficiently on a larger scale. But the real problem was that they were not a good fit for gameplay and can be notoriously time consuming to tweak. My solution was to fake it and I am talking Shanghai Rolex kind of fake. The water in The Jelly Reef is a grid of 2D vectors representing velocities, what we (not physically correctly) called &lt;i&gt;flow field&lt;/i&gt;. The grid is treated as a gray-scale image and every update is filtered using a set of low-pass filters. The resulting image summed with the current image using a tweakable weight factor. The low-pass filtering is done by convolution with a 3 by 3 kernel, which is chosen based on the direction of the water at that cell of the grid. There are 4 kernels in total; horizontal, vertical and two diagonal ones. Basically the value of atan2 is mapped directly into an index in the kernel array. What follows is a piece of code that does exactly that and in some way is the heart of our game.&lt;/div&gt;&lt;pre class="brush: java"&gt;// FlowField.cs&lt;br /&gt;public class FlowField : ISceneNode&lt;br /&gt;{&lt;br /&gt;  #region Weights&lt;br /&gt;&lt;br /&gt;  static float lon = 3;&lt;br /&gt;  static float lat = 0.5f;&lt;br /&gt;&lt;br /&gt;  private static float[,] verticalKernel =&lt;br /&gt;    new float[,]{ {lat, lat, lat},&lt;br /&gt;                  {lon, lon, lon},&lt;br /&gt;                  {lat, lat, lat}};&lt;br /&gt;        &lt;br /&gt;  private static float[,] horizontalKernel =&lt;br /&gt;    new float[,]{ {lat, lon, lat},&lt;br /&gt;                  {lat, lon, lat},&lt;br /&gt;                  {lat, lon, lat}};&lt;br /&gt;&lt;br /&gt;  private static float[,] diagonalKernel0 =&lt;br /&gt;    new float[,]{ {lat, lat, lon},&lt;br /&gt;                  {lat, lon, lat},&lt;br /&gt;                  {lon, lat, lat}};&lt;br /&gt;&lt;br /&gt;  private static float[,] diagonalKernel1 =&lt;br /&gt;    new float[,]{ {lon, lat, lat},&lt;br /&gt;                  {lat, lon, lat},&lt;br /&gt;                  {lat, lat, lon}};&lt;br /&gt;&lt;br /&gt;  private static float[][,] kernels = new float[][,]         &lt;br /&gt;  {&lt;br /&gt;    horizontalKernel,&lt;br /&gt;    diagonalKernel1,&lt;br /&gt;    verticalKernel,&lt;br /&gt;    diagonalKernel0,&lt;br /&gt;    //&lt;br /&gt;    horizontalKernel,&lt;br /&gt;    diagonalKernel1,&lt;br /&gt;    verticalKernel,&lt;br /&gt;    diagonalKernel0&lt;br /&gt;  };&lt;br /&gt;&lt;br /&gt;  #endregion&lt;br /&gt;&lt;br /&gt;  public void Update(float dt)&lt;br /&gt;  {&lt;br /&gt;    // Some update code...&lt;br /&gt;&lt;br /&gt;    // Go through all the cells&lt;br /&gt;    for (int i = iFrom; i &amp;lt; iTo; i++)&lt;br /&gt;    {&lt;br /&gt;      for (int j = jFrom; j &amp;lt; jTo; j++)&lt;br /&gt;      {&lt;br /&gt;        // Get vector angle&lt;br /&gt;        float theta = (float)Math.Atan2(vectorField[i, j].Y, vectorField[i, j].X);&lt;br /&gt;        //&lt;br /&gt;        theta += MathHelper.Pi / 8; // Add half a section&lt;br /&gt;        // get index&lt;br /&gt;        int kindex = (int)Math.Floor(theta * (8.0f / MathHelper.TwoPi));&lt;br /&gt;        kindex %= 8;                // Remove extra sections&lt;br /&gt;        //&lt;br /&gt;        float[,] kernel = kernels[kindex];&lt;br /&gt;&lt;br /&gt;        // Convolve using this kernel!&lt;br /&gt;      }&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;All the kernels are energy-preserving, so a dampening factor is used to stabilize the velocity field. All hand movements add energy to the system so without dampening the simulation would in fact exploded. This system made interacting with the water intuitive while giving us the ability to easily tweak its behavior. The video below shows a visualization of the velocity field, something that we stared a lot when designing the first levels. The video below shows the debug view of the our flow field.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;iframe width="590" height="472" src="http://www.youtube.com/embed/KXi9xdhV9dY?hd=1" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Most of the levels in our game had regions that were not part of the simulated water field, usually rocks and other such big obstacles. The water should not flow through these obstacles so those regions should be excluded from the flow field. For this purpose, when loading the level we employ a flood fill algorithm, that expands until it hits a wall, that marks all the cells that are part of the flow field. By skipping calculations on those cells we also optimized the flow field significantly. The flow field’s value can be read using nearest neighbor or bilinear sampling, depending on the quality and performance needs. Bubbles for example use nearest neighbor as there are many of them and the physical simulation takes care of the trajectory smoothing. For the jellies on the other side we used bilinear sampling as motion quality and responsiveness was paramount.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Next place where gameplay can be added is the update method of the &lt;i&gt;GameWorld&lt;/i&gt; class.  The &lt;i&gt;GameWorld&lt;/i&gt; has been designed to be extended and new functionality can be added by the inheriting class. The update method is the place where game wide game-play code should be, like checking winning and losing conditions or similar stuff. The inherited class would automatically keep all the functionality of the &lt;i&gt;GameWorld&lt;/i&gt; class, like the streaming and real time editing but it needs to do &lt;i&gt;XmlInclude&lt;/i&gt; for all the entity types in the class attributes.Much of the gameplay code is in the &lt;i&gt;Update&lt;/i&gt; method of the different entities and most entities are in fact built for specifically for that purpose. Enemies, propellers and pipes are all examples of such entities. If the entity is dynamic it can inherit the &lt;i&gt;MovingEntity&lt;/i&gt; class and get all the functionality for physically simulated motion.Finally the game implements a mechanism to respond to collision events. The user could subscribe collisions of different pairs of entity types. For example a collision of a jelly with a cannon ball would result in instant death and the event can be used to play a sound, death animation and so on. What follows is are parts of the code doing exactly that.&lt;/div&gt;&lt;pre class="brush: java"&gt;// JellyWorld.cs&lt;br /&gt;&lt;br /&gt;// Include all types that might be used in the game&lt;br /&gt;[XmlInclude(typeof(Jelly))]&lt;br /&gt;// More includes ...&lt;br /&gt;public class JellyWorld : GameWorld&lt;br /&gt;{&lt;br /&gt;   public void SetEvents()&lt;br /&gt;   {&lt;br /&gt;      // Add Jelly vs Propeller&lt;br /&gt;      int hash = EntityTypes.HashCode(EntityType.Jelly, EntityType.Propeller);&lt;br /&gt;      this.collisionManager.SubscribeForCollision(hash, JellyPropellerCollision);&lt;br /&gt;&lt;br /&gt;      // Set more events ...&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void JellyPropellerCollision(ref Contact contact)&lt;br /&gt;   {&lt;br /&gt;      // Play gruesome death, scary sound and remove jelly&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // More JellyWorld code ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;From the two entity types hash is created and is used to index the event method to be called. The hash is calculated by using the first 16 bits to store the first type and the second 16 bits for the second type. As long as there are less than 65536 entity types this works. The method gets a reference of the contact information which can be edited too. The above code for example sets the handled flag to true, so that the contact is ignored by the contact resolver in the physics pipeline. Consequently, physics and collision handling is exactly what the next article will be about. I'll end this post with a montage of our game.&lt;/div&gt;&lt;iframe frameborder="0" height="332" src="http://player.vimeo.com/video/19844734?title=0&amp;amp;byline=0&amp;amp;portrait=0" width="590"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;a href="http://vimeo.com/19844734"&gt;The Jelly Reef&lt;/a&gt; from &lt;a href="http://vimeo.com/adriaandejongh"&gt;Adriaan de Jongh&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-7564331133461739818?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/7564331133461739818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/05/building-your-own-game-engine-gameplay.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7564331133461739818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7564331133461739818'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/05/building-your-own-game-engine-gameplay.html' title='Building Your Own Game Engine - Gameplay'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-pM6bflnHmzA/TcJver0UM3I/AAAAAAAAA2Q/rUEIQ0-vD-g/s72-c/JellyConrnerPic.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-7939404482048448695</id><published>2011-03-02T13:26:00.001+01:00</published><updated>2011-03-02T13:31:15.424+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='reef'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Building Your Own Game Engine - Tools II</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;This is the second article on tools that we developed and used during the making of The Jelly Reef. It covers our profiler, the level editor and few external tools.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Profiler&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh5.googleusercontent.com/-RDvHxCSyuxE/TW1wjmCpfsI/AAAAAAAAA1U/o5pculNzg3w/s1600/ProfilerCapt.PNG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="221" src="https://lh5.googleusercontent.com/-RDvHxCSyuxE/TW1wjmCpfsI/AAAAAAAAA1U/o5pculNzg3w/s320/ProfilerCapt.PNG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Performance is essential for any game and knowing how big of a chunk out of the update time goes to different tasks can be very helpful. For this purpose, we built a profiler early on and always kept a watch over the performance. The profiler has few roles. Firstly, to have a bunch of variables that can be used as counters, like counting the number of collision checks, drawing calls, triangles and such. Secondly, to count framerate. And most importantly, to measure execution time of different sections of the code.The profiler is implemented as a singleton manager, as discussed in the &lt;a href="http://furiouspixels.blogspot.com/2011/02/building-your-own-game-engine-tools-i.html"&gt;previous post&lt;/a&gt;. All the counters are accessible via a public dictionary. The profiler itself only draws the counters as name and value pair. It is up to the user of the counter to take care of the value, like resetting the counter zero or incrementing it.&lt;br /&gt;The game uses a fixed framerate of 60 FPS, but we still use a framerate counter to detect if drop in performance occurs and eliminate the cause.For measuring section execution time we use the &lt;i&gt;Stopwatch&lt;/i&gt;, which is a high-resolution timer. At the beginning of update the stopwatch is reset. At the beginning of the section in the update, like collision detection or water simulation, a the BeginSection method is called with the name if the section. When done, the EndSection method is called with the same name of the section. The profiler simply samples the time of the stopwatch so section can be nested or overlap. The profiler draws a bar from the beginning of the section to the end, using the width of the screen as a reference for the 0.0166 seconds (60-th of a second) available CPU time per update. So if we reach the right side of the screen, we know we need to optimize something, and we might as well start with the longest bar. The difference between the end and the beginning of a section gives its duration and this is shown just below the bars with the same color as the corresponding bar. The profiler is only compiled when the PROFILE symbol is defined, so just like the debug draw it is not part of the final build. Unlike the debug drawing, it is also compiled with the release builds of the game to track their performance as the C# compiler can optimize the release version quite a bit.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Editor&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="https://lh3.googleusercontent.com/--VgEw6bbuT0/TW1xXmbL21I/AAAAAAAAA1Y/6V-t1XmDJpg/s1600/Editor.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="https://lh3.googleusercontent.com/--VgEw6bbuT0/TW1xXmbL21I/AAAAAAAAA1Y/6V-t1XmDJpg/s400/Editor.png" width="213" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;What started as a runtime inspector for the entities in the gameworld, quickly turned into a editor that we used to create the levels. This means that we used an in-game editor to author and edit the levels, rather than a separate tool. In fact at any time you can press E button on the keyboard and bring up the editor. This means very short turnaround times for our designer, as changing a value like mass or a position of a wall has an immediate effect in game. On the other hand, the user needs to remember that the game is running at all times. Physics and collision can easily be broken by large changes while the game is running. That is why the editor got a pause button, but somehow it was almost never clicked. And the programers need to remember that the same code runs during designing and playing. The editor is not included in the release build and the Surface unit doesn’t need a keyboard in user mode, so tampering with the game is not a problem.&lt;br /&gt;The editor is very much based on features available in C# the .NET Framework. The editor is basically a window with a tree control a property grid, both of which a regular windows forms. The tree control is depicting the world hierarchy and allows the user to select one or more entities in the world. For the window to be able to create this hierarchy all the object that we would like to display in the editor must implement the ISceneNode interface.&lt;/div&gt;&lt;pre class="brush: java"&gt;/// &lt;summary&gt;&lt;br /&gt;/// Alows browsing the scene graph in a simple way&lt;br /&gt;/// &lt;/summary&gt;&lt;br /&gt;public interface ISceneNode&lt;br /&gt;{&lt;br /&gt;   IEnumerable&amp;lt;ISceneNode&amp;gt; GetChildNodes();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// GameWorld.cs&lt;br /&gt;public class GameWorld : ISceneNode&lt;br /&gt;{&lt;br /&gt;   // ...&lt;br /&gt;   public virtual IEnumerable&amp;lt;ISceneNode&amp;gt; GetChildNodes()&lt;br /&gt;   {&lt;br /&gt;            foreach (BaseGameEntity o in Entities) { yield return o; }&lt;br /&gt;            //&lt;br /&gt;            foreach (Wall w in Walls) { yield return w; }            &lt;br /&gt;            //&lt;br /&gt;            foreach (ParallaxLayer l in  Layers) { yield return l; }            &lt;br /&gt;#if DEBUG&lt;br /&gt;            yield return DebugDraw.Instance;&lt;br /&gt;#endif&lt;br /&gt;   }&lt;br /&gt;   // ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Using the interface window can build the tree recursively. This is a simple approach also lets a put things in the tree that are not really part of the world, but we would like to be able to tweak them too, like the options for the debug drawing.&lt;br /&gt;The property grid on the other hand required a bit more attention. The property grid in .NET is uses reflection to give the user an interface to tweak any public property of any object, but some care must be taken. Firstly non-primitive types like our vector implementation would need to implement a conversion to a type that can be displayed properly. This actually took few days to get right, so that is doesn’t delete data when some has typed something wrong. Without some kind of description the user interface would be very difficult to use as it might be hard for the designer to know what linear dampening might mean, there might be too many properties that are public and they are not sorted in any way. So the entities have to have attributes attached to all their public properties, as the code below shows.&lt;/div&gt;&lt;pre class="brush: java"&gt;class MovingEntity : BaseGameEntity // Which implements ISceneNode&lt;br /&gt;{&lt;br /&gt;   // ...&lt;br /&gt;&lt;br /&gt;   #if WINDOWS&lt;br /&gt;   [Category("Physical Parameters")]&lt;br /&gt;   [Description("Max turn rate in deg/s")]&lt;br /&gt;   #endif&lt;br /&gt;   [XmlIgnore]&lt;br /&gt;   public float MaxTurnRate&lt;br /&gt;   {&lt;br /&gt;      get { return maxTurnRate; }&lt;br /&gt;      set { maxTurnRate = value; }&lt;br /&gt;   }&lt;br /&gt;   // Field&lt;br /&gt;   protected float maxTurnRate;&lt;br /&gt;&lt;br /&gt;   // ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;As it turns out these attributes, especially the description, also help keep code well documented for programmers too. We always knew if a rotation property is in angles or radians. The component model API is only available on Windows, so some preprocessor guards come in handy if you would like to compile the project for other platforms like Xbox and Windows Phone. Our classes already had the XML attributes, so the code for a single property can be a bit long, but maintenance and ease of implementation made all the scrolling totally worth.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;A very important part of the editor also were the different design modes. With a press of a button on the keyboard the game would switch to wall editing mode or entity manipulation mode. We added those model in a somewhat ad hoc manner and were more or less hacked into the game. Eliminating turnaround&amp;nbsp; time for the designer was a nice plus and it worked great for this game, but this approach doesn't scale well. In retrospective I think I might have been better to build an editor that still uses the engine with all of its classes and functionality but built a separate editor. &lt;/div&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-size: large;"&gt;External Tools&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Aside from the usual content creation applications like Photoshop and After Effect, we used few plugins for Photoshop some other tools. As we learned Photoshop doesn’t work with explicit alpha when saving in the PNG format, so we needed something that can roll back the time to Photoshop 4.0 when it was the last time it did work. Luckily there was a plugin for that. Another plugin, called Solodify, was used to fade the edges in the color channels so that no white pixels appear when alpha testing is used for rendering. The water caustics were precalculated using Caustics Generator, which available for free. I like to work with FX Composer for developing shaders regardless of the fact that is was a bit of overkill for the few shaders we needed. FX Composer is also available as a free download on nVidia’s developer website. As last line of defense when I need to debug my rendering code, I use PIX. This extremely powerful tool comes with the DirectX SDK and can capture every single call to the GPU, including its internal state and even show the intermediate rendering results. &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-7939404482048448695?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/7939404482048448695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/03/building-your-own-game-engine-tools-ii.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7939404482048448695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7939404482048448695'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/03/building-your-own-game-engine-tools-ii.html' title='Building Your Own Game Engine - Tools II'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh5.googleusercontent.com/-RDvHxCSyuxE/TW1wjmCpfsI/AAAAAAAAA1U/o5pculNzg3w/s72-c/ProfilerCapt.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-1081181096099245750</id><published>2011-02-20T13:24:00.002+01:00</published><updated>2011-03-01T23:51:09.302+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='reef'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Building Your Own Game Engine - Tools I</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;This article will focus on the tools that were developed and used during the making of the game. It turn out to be a rather large article so it's split in two posts. Basically a tool is everything that helps get the game done, like a level editor or a profiler. We used some external tool aside from the content creation applications like, Photoshop and After Effects. I will cover those after covering our own tools.&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Managers&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;Before jumping to the different tools, I will first give a short overview of the managers the we used in the engine. There are certain services, routines or data that might be needed at any time in the execution of the game. File reading, resource loading and camera properties are good examples of such services. To make them available at all times we use managers, which are just simple &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;singleton objects&lt;/a&gt;. At first we used static methods to wrap the actual object calls, making the calls a bit shorter, but we later decided for a more simple implementation. What follows is a short piece of the code from the camera class.&lt;/div&gt;&lt;pre class="brush: java"&gt;// Camera.cs&lt;br /&gt;public class Camera : ISceneNode&lt;br /&gt;{&lt;br /&gt;   private static Camera instance;&lt;br /&gt;&lt;br /&gt;   // Gets the instance of the camera; there can be only one.&lt;br /&gt;   public static Camera Instance&lt;br /&gt;   {&lt;br /&gt;      get { return instance; }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public Camera(float camSizeX, float camSizeY, GameWorld world)&lt;br /&gt;   {&lt;br /&gt;      // ctor code ...&lt;br /&gt;   }&lt;br /&gt;   &lt;br /&gt;   public void Initialize()&lt;br /&gt;   {   &lt;br /&gt;      instance = this;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // some camera code...&lt;br /&gt;}&amp;nbsp;&lt;/pre&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;There is only one instance of the singleton object that can be referenced. The parameters in the constructor give the dependencies order among the managers. This strategy was used for many of the tools that will be discussed next.&lt;/div&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;Debug Drawing&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/--X-3Rf1e7xU/TWEJmjSArDI/AAAAAAAAA1Q/2GuSl_HX1G8/s1600/DebugDrawCapt.PNG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="246" src="http://1.bp.blogspot.com/--X-3Rf1e7xU/TWEJmjSArDI/AAAAAAAAA1Q/2GuSl_HX1G8/s320/DebugDrawCapt.PNG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;The very first tool that was implemented was the debug drawing. Textures might go missing, shaders might be buggy, triangles might get clipped, scaled, culled and not render at all. Developing a game in the dark can be extremely frustrating and inefficient, so this is where the debug drawing comes in to let us know exactly what is happening in the game. In a game engine usually drawing should only be done within a draw method and might need to set up many shading and rendering parameters. This is the exact opposite of what we need, so we made a debug draw that allows us to call drawing of colored lines from anywhere in the code. This can help visualize local variables like velocities, grids and such. Here is a short piece of code from the debug drawing manager.&lt;/div&gt;&lt;pre class="brush: java"&gt;// DebugDraw.cs&lt;br /&gt;public class DebugDraw&lt;br /&gt;{          &lt;br /&gt;   protected static DebugDraw instance;&lt;br /&gt;&lt;br /&gt;   // Needs a static instance to be able to answer static calls&lt;br /&gt;   public static DebugDraw Instance&lt;br /&gt;   { get { return instance; } }&lt;br /&gt;&lt;br /&gt;   // lines&lt;br /&gt;   public VertexPositionColor[] lines;&lt;br /&gt;   public int linesCount;&lt;br /&gt;&lt;br /&gt;   public DebugDraw(Game game)&lt;br /&gt;   {&lt;br /&gt;      graphicsDevice = game.GraphicsDevice;&lt;br /&gt;      effect = new BasicEffect(game.GraphicsDevice, null);&lt;br /&gt;      lines = new VertexPositionColor[80000];&lt;br /&gt;      //&lt;br /&gt;      linesCount = 0;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void Initialize()&lt;br /&gt;   {&lt;br /&gt;      // Set static instance to this&lt;br /&gt;      DebugDraw.instance = this;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void DrawLine(Vector3 start, Vector3 end, Color color)&lt;br /&gt;   {&lt;br /&gt;      if (linesCount + 2 &amp;gt; lines.Length)&lt;br /&gt;         return; // Silent error&lt;br /&gt;&lt;br /&gt;      lines[linesCount++] = new VertexPositionColor(start, color);&lt;br /&gt;      lines[linesCount++] = new VertexPositionColor(end, color);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void Update(float dt)&lt;br /&gt;   {               &lt;br /&gt;      // Clear all out&lt;br /&gt;      linesCount = 0;&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void Draw(float dt)&lt;br /&gt;   {&lt;br /&gt;      if (linesCount &amp;gt; 0)&lt;br /&gt;         // call XNA line drawing ...&lt;br /&gt;   }   &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;The approach is very simple; all the vertices are stored in a fixed array and the calls are accumulated into the array. During the render phase, lines are drawn with a single draw call, which is very efficient.&amp;nbsp; Circles and such are simply composed out of multiple line segments. Similarity, methods for drawing points were added too. With this in place we could visualize collision geometry, contact points, forces and similar stuff.&lt;br /&gt;The next posts will discuss the profiler, level editor and some external tools, followed by a post on the water simulation and game play. So if you are curious, you can click the follow button in the top left&amp;nbsp; corner or subscribe to the feed with you favorite reader.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-1081181096099245750?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/1081181096099245750/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/02/building-your-own-game-engine-tools-i.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1081181096099245750'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1081181096099245750'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/02/building-your-own-game-engine-tools-i.html' title='Building Your Own Game Engine - Tools I'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/--X-3Rf1e7xU/TWEJmjSArDI/AAAAAAAAA1Q/2GuSl_HX1G8/s72-c/DebugDrawCapt.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-6391806302963067235</id><published>2011-02-08T13:43:00.003+01:00</published><updated>2011-02-13T14:22:57.016+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='file'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='basic'/><category scheme='http://www.blogger.com/atom/ns#' term='resource'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Building Your Own Game Engine - Basic Mechanisms</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_XNjT4XAs15w/TVFHI5MTRaI/AAAAAAAAA1M/izRF7drhHuc/s1600/2level2a.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://4.bp.blogspot.com/_XNjT4XAs15w/TVFHI5MTRaI/AAAAAAAAA1M/izRF7drhHuc/s400/2level2a.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;There are some game engine mechanisms that are needed in almost any game, and this article will cover exactly that. As I stated in the last article, the work on this common set of features started before we even knew what game we were making. While I have worked on large chunks of a &lt;a href="http://guardiaris.com/si/resitve.shtml"&gt;complex system&lt;/a&gt;, this was my first time as a lead programmer and building an engine from scratch. So I consulted my favourite books, adapted some ideas from there to fit our needs and was ready to start.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;At the very low level we were free from having to develop a memory management system, as we used C# and could let the garbage collection take care of that. Sometimes however the garbage collection can cause hiccups, so special care need to taken. The garbage collection runs fastest when it doesn't run at all, so we had almost no dynamic memory allocation after a level has been loaded. On way we tried to enforce this was to have our low level stuff like math, physics, collisions, render jobs and such as value types. Declaring a structure (struct) instead of a class in C# is not enough, as the garbage collection is a &lt;a href="http://blogs.msdn.com/b/ericlippert/archive/2010/10/11/debunking-another-myth-about-value-types.aspx"&gt;bit more complicated&lt;/a&gt; and sophisticated than that, so we made sure that variables are statically&amp;nbsp; scoped whenever possible. Additionally, we passed by reference all bigger structures to avoid copying memory around.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;XNA is mostly a 3D rendering framework, so The 2D math that is part of the framework was in my opinion not a good match to what we needed for game. So, we implemented a 2D vector and a matrix class, as well as some helper methods for transformations. These can be lifted from any book in the field. Because we didn't do much rigid body physics or angular interpolation, there was no special class for rotations. In future I would prefer to use &lt;a href="http://en.wikipedia.org/wiki/Spinor"&gt;spinors&lt;/a&gt; (2D equivalent of &lt;a href="http://en.wikipedia.org/wiki/Quaternion"&gt;quaternions&lt;/a&gt;) or complex numbers for the purpose.The game structure itself was kept very simple. Everything in the game was derived from &lt;i&gt;GameEntity&lt;/i&gt; and all the entities were kept in the &lt;i&gt;GameWorld&lt;/i&gt;. The game world had no hierarchy, just a list of level of entities. What follows is a piece of code from the &lt;i&gt;GameWorld&lt;/i&gt; class and BaseGameEntity class that I will elaborate on.&lt;/div&gt;&lt;pre class="brush: java"&gt;// Gameworld.cs&lt;br /&gt;public class GameWorld&lt;br /&gt;{&lt;br /&gt;   // some code ...&lt;br /&gt;&lt;br /&gt;   // All the entities in the world&lt;br /&gt;   public List&amp;lt;BaseGameEntity&amp;gt; Entities&lt;br /&gt;   { get; set; }&lt;br /&gt;&lt;br /&gt;   // Adds an entity to the world. This can be anything.&lt;br /&gt;   public void AddEntity(BaseGameEntity entity)&lt;br /&gt;   {&lt;br /&gt;      AddQueue.Add(entity);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // Removes an entity from the world&lt;br /&gt;   public void RemoveEntity(BaseGameEntity entity)&lt;br /&gt;   {&lt;br /&gt;      RemoveQueue.Add(entity);&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   public void Update(float dt)&lt;br /&gt;   {&lt;br /&gt;      // Add entities&lt;br /&gt;      foreach (BaseGameEntity bge in AddQueue)&lt;br /&gt;         Entities.Add(bge);&lt;br /&gt;      AddQueue.Clear();&lt;br /&gt;      &lt;br /&gt;      // Update entities&lt;br /&gt;      foreach (BaseGameEntity bge in Entities)&lt;br /&gt;         if(bge != null)&lt;br /&gt;            bge.Update(dt);&lt;br /&gt;&lt;br /&gt;      // Remove entities&lt;br /&gt;      foreach (BaseGameEntity bge in RemoveQueue)&lt;br /&gt;      {&lt;br /&gt;         // Call cleanup on the entity&lt;br /&gt;            if (bge is IDisposable)&lt;br /&gt;               (bge as IDisposable).Dispose();&lt;br /&gt;            Entities.Remove(bge);&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;   // more code ...&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// BaseGameEntity.cs&lt;br /&gt;[Serializable()]&lt;br /&gt;public class BaseGameEntity&lt;br /&gt;{&lt;br /&gt;   // Refence to the world&lt;br /&gt;   protected GameWorld world;&lt;br /&gt;&lt;br /&gt;   // Unique ID of the enitity.&lt;br /&gt;   [XmlAttribute]&lt;br /&gt;   public int ID&lt;br /&gt;   {&lt;br /&gt;      set {&lt;br /&gt;         this.id = value;&lt;br /&gt;         // Make sure their are unique&lt;br /&gt;         if (id &amp;gt;= nextValidID)&lt;br /&gt;            nextValidID = id + 1;&lt;br /&gt;      }&lt;br /&gt;      get { return id; }&lt;br /&gt;   }&lt;br /&gt;   //each entity has a unique ID&lt;br /&gt;   private int id;&lt;br /&gt;&lt;br /&gt;   // Every entity has a type associated with it (health, troll, ammo etc)&lt;br /&gt;   public EntityType Type&lt;br /&gt;   { get; set; }&lt;br /&gt;   &lt;br /&gt;   // Called when loaded&lt;br /&gt;   public virtual void Initialize(GameWorld gameworld)&lt;br /&gt;   {&lt;br /&gt;      // init code ...&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   // some code ...&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The flat structure and very simple sequential update are not very flexible, an interactive character on a moving platform might be difficult to implement for example, but was sufficient for our needs. Additionally this approach can be memory coherent, which is very good for cache, which is very important performance. The update method of each entity handles everything from physics and game-play to animation. I opted for simple floating point time in seconds as parameter instead of the XNA's &lt;i&gt;GameTime&lt;/i&gt; structure as I it doesn't require every class to calculate time, which can bring inconsistencies, and it allows for easy time manipulation like bullet time or pause. So that there is no inconsistency during the execution of a single world update, entities could only be added and removed at the begging and end of it. Queues of such entities are kept for this reason.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;From the piece of code from the BaseGameEntity class we can see few things.&lt;/div&gt;&lt;ul style="text-align: justify;"&gt;&lt;li&gt;Every entity has a reference to the game world and that is how it communicates with other entities and can be aware of its soundings.&lt;/li&gt;&lt;li&gt;A unique ID is kept to help identify the entities. This ID is persistent and stored in the level.&lt;/li&gt;&lt;li&gt;We have a game entity type for different things in the level, mostly used for game-play and collisions. This is different from the .NET object type, as there can be many different enemies but they are all of the same class. &lt;/li&gt;&lt;li&gt;We are using the .NET framework XML serializing support for writing and reading data, so our executable classes are also our data containers. This can be seen from the many annotations throughout the code.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;This last bullet point was not all that straight forward to implement as it may seem. Firstly, the game scene has a general graph structure, while an XML file has a hierarchical structure and cannot represent the scene properly. Secondly, when reading an object from an XML file, the no arguments constructor is always called. These are remedied by calling an initialization method on all entities after streaming, that has a similar role to a constructor. For cross-reference unique entity IDs are stored in the XML and during the initialization references to the actual objects are obtained by querying the world.&lt;/div&gt;&lt;div style="text-align: justify;"&gt;When a level grows to contain couple of hundred entities, it's obvious that you would like to change properties in bulk, and that is where a settings file comes in. This is just another XML file which can be referenced by an entity. We decided settings to be strongly typed so settings for a jelly are different from settings for a blow fish even if the contents are the same. Settings are implemented as simple classes so they can be inherited when needed. So if a &lt;i&gt;MovingEntity&lt;/i&gt; extends &lt;i&gt;BaseGameEntity&lt;/i&gt;, &lt;i&gt;MovinEntitySettings&lt;/i&gt; can extend &lt;i&gt;BaseGameSettings&lt;/i&gt;, simplifying the maintenance. The settings are applied in the &lt;i&gt;Initialize&lt;/i&gt; method and all entities have a &lt;i&gt;GetSettings&lt;/i&gt; and &lt;i&gt;SaveSettings &lt;/i&gt;methods&lt;i&gt;. &lt;/i&gt;The classes extending the entity class must handle all the details of saving the settings, as it's the only class that knows the type of the settings class. This approach puts a bit of extra work for every type that needs to have settings, but it's flexible and can even allow for structured settings, like a blowfish settings having different sprite settings for all the animations.&lt;br /&gt;These settings files might need to be read frequently during the game, as each created rocket or a bullet might need their settings for example. Reading from disk can do some bad hiccups and there is the added slowdown of parsing the file, allocating memory. For this purpose we cache the settings, which a usually very small data structures and more over, are shared among entities with the same settings. We simply use the file name as a key in a dictionary. The same caching is in fact used for all resources to avoid duplicate data in the game. Our resource manager handles this internally, so it's completely transparent for the rest of the code.&lt;br /&gt;There is always room for improvement, so I'll mention few things. For a future project I might opt for a different streaming solution or make macros that do most of the tedious work for me, but the overall performance and flexibility during the development was quite good. We had a inconsistent way of using the entity types, which lead to some funky bugs. A more structured update method that can handle different priorities and different logical steps might also be beneficial.&lt;br /&gt;The next article will be on tools and the world editor.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-6391806302963067235?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/6391806302963067235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/02/building-your-own-game-engine-basic.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/6391806302963067235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/6391806302963067235'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/02/building-your-own-game-engine-basic.html' title='Building Your Own Game Engine - Basic Mechanisms'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_XNjT4XAs15w/TVFHI5MTRaI/AAAAAAAAA1M/izRF7drhHuc/s72-c/2level2a.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-5095496626921549073</id><published>2011-02-06T13:14:00.001+01:00</published><updated>2011-02-06T13:18:38.564+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='jelly'/><category scheme='http://www.blogger.com/atom/ns#' term='engine'/><category scheme='http://www.blogger.com/atom/ns#' term='own'/><category scheme='http://www.blogger.com/atom/ns#' term='jellyreef'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='reef'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Building Your Own Game Engine - Introduction</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_XNjT4XAs15w/TU6MwyHpKDI/AAAAAAAAA1I/lk95tKpu4AQ/s1600/The+Jelly+Reef-27.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="222" src="http://3.bp.blogspot.com/_XNjT4XAs15w/TU6MwyHpKDI/AAAAAAAAA1I/lk95tKpu4AQ/s320/The+Jelly+Reef-27.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Fast forward from my last post, the game that I was making with students from the Utrecht School of Arts (HKU) for the Dutch Game Garden is done. At least within the project frame that was given by the school. We decided for "The Jelly Reef" as a name and you can read more at &lt;a href="http://www.thejellyreef.com/"&gt;www.thejellyreef.com&lt;/a&gt;.  The game has been showcased on few occasions and has received some very positive reactions. This is the first in a series of six articles on how the game was developed. The articles will cover some details&amp;nbsp; of the game's engine structure and all the technical choices made along the way. The next articles will focus on Basic Structure, Tools, Game Play, Physics and Collision Detection, and Graphics. The articles should be informative to any small team trying to develop a game, as much of the patterns reappear again and again in very different types of games. First, a screen-shot can give you an idea about The Jelly Reef and there is a &lt;a href="http://www.southparkstudios.com/clips/153324/sports-training-montage"&gt;montage&lt;/a&gt; at the end of the article.&lt;/div&gt;&lt;a href="http://2.bp.blogspot.com/_XNjT4XAs15w/TU6KJkZ34fI/AAAAAAAAA1A/qDC_vg7ypTI/s1600/level1a.png" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5570541686099534322" src="http://2.bp.blogspot.com/_XNjT4XAs15w/TU6KJkZ34fI/AAAAAAAAA1A/qDC_vg7ypTI/s320/level1a.png" style="float: left; height: 240px; margin: 0pt 10px 10px 0pt; width: 320px;" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;screen&gt;Before there was any game, there was the team and the clients request, so many of the initial decisions came from there. The team was 9 peoples strong; 3 programmers, 4 artist and 2 designers. Two of the programmers on the project, including myself were part time and the third one had a background in interaction design with little experience in programming. All the artist on the project had background in 2d art. For the vast majority of the project, design was handled by the lead designer, as the other designer was perfecting the art of  slacking. We knew that we were working with the Microsoft Surface, so technical choice number one was the choice of language, C# and was done for us. Because of performance reasons mentioned in the &lt;a href="http://furiouspixels.blogspot.com/2010/11/developing-for-microsoft-surface.html"&gt;previous post&lt;/a&gt;, we decided to go for XNA instead of Silverlight. With the background of our art guys we knew that we would be making a 2d game and the top down perspective of the device reinforced the decision. While we did have the option to use a game engine like Unity, we didn't think that it would be a good fit the projects needs, so we decided to build our own.&lt;br /&gt;For the first three weeks the team was brainstorming on possible concepts. Time is always in short supply so the tech team was eager to start working on something, to avoid sleepless nights at the end of the project. We discarded some of the concepts and merged features from similar concepts. From the handful of distilled concepts, we took a common denominator and started working on that. This is exactly what the next article will discuss.&lt;/screen&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;iframe frameborder="0" height="324" src="http://player.vimeo.com/video/19409187" width="576"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-5095496626921549073?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/5095496626921549073/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2011/02/building-your-own-game-engine.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/5095496626921549073'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/5095496626921549073'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2011/02/building-your-own-game-engine.html' title='Building Your Own Game Engine - Introduction'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XNjT4XAs15w/TU6MwyHpKDI/AAAAAAAAA1I/lk95tKpu4AQ/s72-c/The+Jelly+Reef-27.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-159201016494021170</id><published>2010-11-07T19:06:00.011+01:00</published><updated>2011-02-06T13:16:34.667+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='HKU'/><category scheme='http://www.blogger.com/atom/ns#' term='Dutch'/><category scheme='http://www.blogger.com/atom/ns#' term='Surface'/><category scheme='http://www.blogger.com/atom/ns#' term='Garden'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='Microsoft'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Developing for the Microsoft Surface</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;My plan for the current semester was definitely to the try out some touch devices, which is why I bought an iPod touch. But little did I know that I would be developing for the Microsoft Surface. I am working with the Utrecht School of Arts (HKU) on a project for the Dutch Game Garden, and so far looks quite promising.&lt;br /&gt;The Microsoft Surface has a huge area that can detect and track an almost infinite amount of fingers. Ok, not infinite, but more than it makes sense to have on it at any given time. Because it uses image processing and not touch, it has some more tricks up the sleeve. For example, tags recognition, markings that you can print or stick to any object and track it on the surface. As well as raw image processing if needed. The SDK is .NET based, so you get to access the .NET Framework and you can use both Silverlight and XNA.&lt;br /&gt;On the other, the machine is hugely underpowered and the GPU is especially ridiculous, considering the $12000 or so price tag. Most of the demos and samples had a reaction lag unacceptable for most game scenarios, which did make me a bit worried. On this particular I get to be the engine architect, so I decided to start from zero and build an engine based on XNA. As it turns out, the lag in the samples actually came fro the way Silverlight processes events, so the XNA games runes smoothly on 60 fps. Leveraging on the power of C# (using reflections, serializing and a some generics abuse) in under two month we have developed and a system that has an in-game world editor, flexible gameplay elements, collision detection with a bit of physics and even our own profiler. In the last phase we will of course inevitable see the ugly side of C# when we'll need to optimize the whole thing to keep running on 60 fps.&lt;br /&gt;The device also brought to attention some interesting design challenges, like which point of view to take so that from no angle the game looks upside down. And that thing should be addressed next week, hopefully just in time for me to report on it. In meantime you can check this video of some of the earlier prototypes.&lt;br /&gt;&lt;br /&gt;&lt;object height="312" width="520"&gt;&lt;param name="movie" value="http://www.youtube.com/v/qPVZSDAiiXg?fs=1&amp;amp;hl=en_GB"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;embed src="http://www.youtube.com/v/qPVZSDAiiXg?fs=1&amp;amp;hl=en_GB" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="520" height="312"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-159201016494021170?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/159201016494021170/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/11/developing-for-microsoft-surface.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/159201016494021170'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/159201016494021170'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/11/developing-for-microsoft-surface.html' title='Developing for the Microsoft Surface'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-4737118684836764583</id><published>2010-10-10T22:11:00.006+02:00</published><updated>2010-10-13T22:59:21.883+02:00</updated><title type='text'>GDC Europe Retrospective</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XNjT4XAs15w/TLYdluMYEKI/AAAAAAAAA0Y/6rox-Osf_ZE/s1600/CRW_9548.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 214px; height: 320px;" src="http://3.bp.blogspot.com/_XNjT4XAs15w/TLYdluMYEKI/AAAAAAAAA0Y/6rox-Osf_ZE/s320/CRW_9548.jpg" alt="" id="BLOGGER_PHOTO_ID_5527638126536167586" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;It took me some time to write few words for the GDC Europe and not because there wasn't much said on the conference. On the contrary there was so much material, that I needed some time to digest it and put in into the right perspective.&lt;br /&gt;Me being in general on the technical side, I tried to catch as many of the technical lectures as possible and some were very insightful. I'll pick three of them that stuck to my mind and give a short overview.&lt;br /&gt;Eric Chahi from Ubisoft gave a lecture on High-Performance Simulation, by going through the details of their Project Dust. Now named "From Dust", it is a god game where you have the ability to control a dynamic world shaped by the elements. The game achieves interactive simulation of earth, water and wind in the world, by subdividing it into a grid. Each grid cell is simulated separately, using the neighboring cells as inputs. This idea is often used weather prediction models, but what makes the current implementation is the extreme performance optimization done, so that it can run smoothly on consoles. All the data and code per cell are structured so that they fit in 256KB, so all calculations can be done on a Playstation's SPU's or in the case of the Xbox 360 without a single cache miss.&lt;br /&gt;Michael Drobot from Reality Pump Studios gave a lecture on Advanced Material Rendering, which was mainly a collection of dirty tricks on Deferred Shading. Many of them used the long forgotten technique of dithering. Memorable lecture was also given by Mathew Rubin form Black Rock Studio, the focus of which was the “in studio” pipeline, which allows designers to construct and test their levels in shortest time possible. The topic of most of the lectures was quite narrow, but most importantly it gave a glimpse on how deep are developers prepared to dive to create next generation of games and supply their designers and artists with the best possible tools.&lt;br /&gt;The lectures by Crytek and Autodesk were slightly disappointing in comparison and were used more as a showcase for their products than technology lectures. If I would have been a game producer making a choice which technology to license, the lectures would have been more helpful; but I am not.&lt;br /&gt;The real jewel of the conference however is the mix of disciplines that it includes, so I later shifted my focus towards the fields less known to me, like game design, production and even marketing. The ideas presented were extremely helpful often timeless, as good design doesn’t go bad. Which is more than can be said for rendering techniques. Warren Spector’s keynote on the relation of games to other media has been a guideline for most of my recent game design decisions. The lecture by Louis Castle on how to survive the industry was least to say an inspirational one.&lt;br /&gt;In conclusion, I was a great experience to be part of the game-making world. I would love to be there again, and next year with a project to showcase.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-4737118684836764583?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/4737118684836764583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/10/gdc-europe-retrospective.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/4737118684836764583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/4737118684836764583'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/10/gdc-europe-retrospective.html' title='GDC Europe Retrospective'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XNjT4XAs15w/TLYdluMYEKI/AAAAAAAAA0Y/6rox-Osf_ZE/s72-c/CRW_9548.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-1572377911318321717</id><published>2010-09-20T00:21:00.005+02:00</published><updated>2010-09-20T01:01:53.737+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xcode'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><category scheme='http://www.blogger.com/atom/ns#' term='ipod'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='imac'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Going all Apple</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XNjT4XAs15w/TJaPHd19bKI/AAAAAAAAA0E/fPu2hyYHHus/s1600/IMG_9546.jpg"&gt;&lt;img style="float: right; margin: 0pt 0pt 10px 10px; cursor: pointer; width: 286px; height: 286px;" src="http://3.bp.blogspot.com/_XNjT4XAs15w/TJaPHd19bKI/AAAAAAAAA0E/fPu2hyYHHus/s320/IMG_9546.jpg" alt="" id="BLOGGER_PHOTO_ID_5518755751821929634" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;After quite some years sitting comfortably in the PC camp, last month I decided to go Apple all the way. And by PC user I mean Microsoft Certified Trainer, DirectX and .NET developer and an avid gamer. Now what makes a man turn Mac and fork money for computer that is being sold in the lobby of a fashion store here in Utrecht?&lt;br /&gt;&lt;/div&gt;&lt;ul&gt;&lt;li&gt;It’s the only way to develop for the iPhone/iPod touch.&lt;/li&gt;&lt;li&gt;It’s shinny.&lt;/li&gt;&lt;li&gt;And finally it’s the only way to develop for the iPhone/iPod touch.&lt;/li&gt;&lt;/ul&gt;&lt;div style="text-align: justify;"&gt;Obviously strong reasons…so I bought an iMac and got an iPod touch for (almost) free. After few weeks of using it all I can say is, I love it! Snow Leopard runs extremely smooth and so does Window 7. The bright LED screen blows my 22” Samsung LCD out of the water. It runs whisper quiet even when under heavy load. The sound signal doesn’t have interference noise from the hard drive or any other hardware component, unlike my previous not-so-cheap HP.  The ergonomics are great (except for the silly location for the stereo jack!) and the drivers for my Wacom Ituos4 tablet seem to be more stable, allowing me to use hardware rendering in Photoshop. Time Machine is the best backup solution I have used, easy to set up while still giving you all needed options. Compatibility is no issue as it runs Microsoft Office (in fact did from the 80’s) and easily shares any media with my Xbox 360.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;However few things are less then perfect. Graphics performance is below my expectations. Both Maya and Portal ran slower then under Windows and on top of that Portal shows screen tearing and flickering. Using vertical sync didn’t alleviate the problem either. I am not sure if it is the GPU drivers, the OpenGL implementation or the game itself, but needed my Windows 7 installation anyhow. How else I am going to run Visual Studio, my all time favorite Microsoft product (after the Xbox steering wheel :) )&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-size:85%;"&gt;[Non-geeks can skip this paragraph]&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;And this takes me to developing on the Mac, which why I have it in the first place. Xcode in my opinion is not as slick as Visual Studio. It is not always easy to find the window that you need without using Exposé. Alt-Tab is less then useful as all windows of the same application are bundled together, so after getting to your application you need Cmd + ~ to cycle through the windows. On the other hand the excellent code editor stays out of your way and the simple code completion is better than IntelliSense for C/C++, which is not too hard to beat. The language of choice (or lack of one) for developing applications for the Mac and iOS (iPhone/ iPod/iPad) and hence Xcode, is Objective-C. Objective-C has syntax that can make C++ look elegant and C# a wet dream. The language does have some great features like categories, allowing for extending the functionality of an existing class without creating a new one but the memory model is somewhat scary for game developers. It has all the performance nausea of a garbage collection with none of its benefits.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;Is it all worth to have your game on the small screen and potentially thousands of people enjoying it? Hell yeah! So be on the lookout for some handcrafted pixels hitting the App store.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-1572377911318321717?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/1572377911318321717/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/09/going-all-apple.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1572377911318321717'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1572377911318321717'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/09/going-all-apple.html' title='Going all Apple'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XNjT4XAs15w/TJaPHd19bKI/AAAAAAAAA0E/fPu2hyYHHus/s72-c/IMG_9546.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-7590582477137450578</id><published>2010-08-26T21:51:00.026+02:00</published><updated>2010-08-29T23:05:32.757+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='3D'/><category scheme='http://www.blogger.com/atom/ns#' term='gamescom'/><category scheme='http://www.blogger.com/atom/ns#' term='kinect'/><category scheme='http://www.blogger.com/atom/ns#' term='gdc'/><category scheme='http://www.blogger.com/atom/ns#' term='move'/><category scheme='http://www.blogger.com/atom/ns#' term='playstation'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Gamescom 2010</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XNjT4XAs15w/THetnUxtLTI/AAAAAAAAAxw/cgHsB88sJh4/s1600/_MG_9198.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 266px; height: 400px;" src="http://4.bp.blogspot.com/_XNjT4XAs15w/THetnUxtLTI/AAAAAAAAAxw/cgHsB88sJh4/s400/_MG_9198.jpg" alt="" id="BLOGGER_PHOTO_ID_5510063560214785330" border="0" /&gt;&lt;/a&gt;Thanks to the fine people of &lt;a href="http://www.taskforceinnovatie.nl/"&gt;Task Force Innovatie Utrecht&lt;/a&gt; I got to see this year’s &lt;a href="http://www.gamescom-cologne.com/"&gt;gamescom&lt;/a&gt; and &lt;a href="http://www.gdceurope.com/"&gt;GDC Europe&lt;/a&gt;. And what I got was more information on games than one can handle, so I’ll try to put what stuck to my mind most into few paragraphs, combined with some photos.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;div style="text-align: justify;"&gt;I’ll start with the organization of the gamescom fair, which was excellent. The daily ticket also included a train ticket for the same day, combined with the city’s train system, made getting to the fair a breeze. Quarter of million people flooded the Cologne exhibition center, yet I never felt that it was too crowded. However, I did have to wait in line for quite a bit in front the booths of most games, except the teen rated ones.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;The first thing I noticed; German players seem to be big on the MMO games and games featuring dragons and monsters in general, so naturally plethora of those were being showcased. My personal favorite was Torchlight II. It has the same unique visual style of the first game, while removing many of the annoyances of its predecessor.  Moving on to the next hall...&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XNjT4XAs15w/THet1CfX5qI/AAAAAAAAAx4/S-Zf2TTL_rQ/s1600/_MG_9249.jpg"&gt;&lt;img style="float: right; margin: 0pt 0pt 10px 10px; cursor: pointer; width: 266px; height: 400px;" src="http://1.bp.blogspot.com/_XNjT4XAs15w/THet1CfX5qI/AAAAAAAAAx4/S-Zf2TTL_rQ/s400/_MG_9249.jpg" alt="" id="BLOGGER_PHOTO_ID_5510063795824223906" border="0" /&gt;&lt;/a&gt;Two trends that were predominant on the fair and can give a glimpse of what is in store for the next year or so, were motion controllers and 3D. Nintendo has been ruling the sales with the Wii, largely due to its motion controller, the Wiimote. This holiday season, both Kinect for the Xbox 360 and Move for the PlayStation are coming out. The two new devices and completely different and both have their pros and cons.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XNjT4XAs15w/THeyBPmroHI/AAAAAAAAAy4/3_ZXPK70jO8/s1600/_MG_9166.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 400px; height: 266px;" src="http://1.bp.blogspot.com/_XNjT4XAs15w/THeyBPmroHI/AAAAAAAAAy4/3_ZXPK70jO8/s400/_MG_9166.jpg" alt="" id="BLOGGER_PHOTO_ID_5510068403549479026" border="0" /&gt;&lt;/a&gt;The PlayStation Move is a more traditional controller and somewhat similar to the Wii remote. The main controller has the usual PlayStation buttons including a trigger. It tracks motion and rotation over all axes independently and it feels quite accurate but in some games there is an annoying lag between the input move and the reaction on screen. Most of the games shown that were using the new controller were casual games made especially to take advantage of motion input. My personal favorite was on on-rail shooter that actually had similar gameplay to &lt;a href="http://en.wikipedia.org/wiki/Duck_Hunt"&gt;Duck Hunt&lt;/a&gt; for the Nintendo Entertainment System (NES) from 1984. On the other hand, the serious games using the PlayStation Move, like Killzone 3 and SOCOM 4, worked perfectly fine without it.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XNjT4XAs15w/THeyXxvCmQI/AAAAAAAAAzA/AkPbHYjzKQg/s1600/_MG_9203.jpg"&gt;&lt;img style="float: right; margin: 0pt 0pt 10px 10px; cursor: pointer; width: 266px; height: 400px;" src="http://3.bp.blogspot.com/_XNjT4XAs15w/THeyXxvCmQI/AAAAAAAAAzA/AkPbHYjzKQg/s400/_MG_9203.jpg" alt="" id="BLOGGER_PHOTO_ID_5510068790668466434" border="0" /&gt;&lt;/a&gt;&lt;div style="text-align: justify;"&gt;The Xbox 360’s Kinect takes a whole different approach by removing the controller all the way. The Kinect allows the Xbox 360 to do a full motion capture of two players in real-time, using a whole array of sensors including an infrared projector. We have all seen that after some time with the Wiimote everyone learns how to fake a move and do it with least amout of effort . Kinect on the other hand tracks the movement of the whole body in space, so you really have to jump around to make things happen in the game. I had lots of fun playing  Kinect Adventures!, Kinect Sports and even Dance Central; and if you have seen me dance you would know I not exacltythe dancing type. All of the Kinect demos were done in a protected bubble, so my main concern is the ability if the sensor to handle distractions and noise. There could be people moving in the background, dog running if front of you legs or simply having a table in the living room.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XNjT4XAs15w/THeyvXjxoXI/AAAAAAAAAzI/9YuMgwi5l_c/s1600/_MG_9163.jpg"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 400px; height: 266px;" src="http://4.bp.blogspot.com/_XNjT4XAs15w/THeyvXjxoXI/AAAAAAAAAzI/9YuMgwi5l_c/s400/_MG_9163.jpg" alt="" id="BLOGGER_PHOTO_ID_5510069195958755698" border="0" /&gt;&lt;/a&gt;3D was a big topic on the GDC and lots of games were shown in 3D later at the gamescom; even Halo Reach was playable in 3D. Crysis looked great in 3D and the effect had been carefully balanced to add to gameplay rather than just serving as an eye-candy. Sony bring  full support for 3D TV screens to the PlayStation over the HDMI  1.4 standard. But even with Nvidia’s crystal clear &lt;a href="http://www.nvidia.co.uk/object/3d-vision-home-users-uk.html"&gt;3D Vision&lt;/a&gt; my eyes get tired and headache might follow. So I'll just say that I can’t wait to see Wipeout HD in 3D. I bet this time around they can bring up &lt;a href="http://www.1up.com/news/wipeout-delayed-failing-epilepsy-tests"&gt;seizures&lt;/a&gt; even to people without epilepsy.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: justify;"&gt;&lt;div style="text-align: justify;"&gt;Regardless of the upcoming technical novelties coming in the next year, I am personally most exited about upcoming games that focus on fun gameplay, like Portal 2, Little Big Planet 2 and hopefully and plethora of good Indie games like Limbo and Burn Zombie Burn!&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XNjT4XAs15w/THewEjhs0SI/AAAAAAAAAyw/sjuNPx6nEos/s1600/_MG_9186.jpg"&gt;&lt;img style="cursor: pointer; width: 266px; height: 400px;" src="http://4.bp.blogspot.com/_XNjT4XAs15w/THewEjhs0SI/AAAAAAAAAyw/sjuNPx6nEos/s400/_MG_9186.jpg" alt="" id="BLOGGER_PHOTO_ID_5510066261413646626" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XNjT4XAs15w/THeuWCVQ_YI/AAAAAAAAAyI/iH9MCTs9aEc/s1600/_MG_9160.jpg"&gt; &lt;img style="cursor: pointer; width: 266px; height: 400px;" src="http://2.bp.blogspot.com/_XNjT4XAs15w/THeuWCVQ_YI/AAAAAAAAAyI/iH9MCTs9aEc/s400/_MG_9160.jpg" alt="" id="BLOGGER_PHOTO_ID_5510064362717511042" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XNjT4XAs15w/THevsB_Ul_I/AAAAAAAAAyo/IY8rVeXMg2c/s1600/_MG_9168.jpg"&gt;&lt;img style="cursor: pointer; width: 266px; height: 400px;" src="http://2.bp.blogspot.com/_XNjT4XAs15w/THevsB_Ul_I/AAAAAAAAAyo/IY8rVeXMg2c/s400/_MG_9168.jpg" alt="" id="BLOGGER_PHOTO_ID_5510065840094222322" border="0" /&gt;&lt;/a&gt; &lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_XNjT4XAs15w/THezOk5MijI/AAAAAAAAAzQ/yylIv5W0yyc/s1600/_MG_9159.jpg"&gt;&lt;img style="cursor: pointer; width: 266px; height: 400px;" src="http://4.bp.blogspot.com/_XNjT4XAs15w/THezOk5MijI/AAAAAAAAAzQ/yylIv5W0yyc/s400/_MG_9159.jpg" alt="" id="BLOGGER_PHOTO_ID_5510069732114205234" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XNjT4XAs15w/THrLNPE0G2I/AAAAAAAAAzY/7O0etQ96d28/s1600/_MG_9227.jpg"&gt;&lt;img style="cursor: pointer; width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_XNjT4XAs15w/THrLNPE0G2I/AAAAAAAAAzY/7O0etQ96d28/s400/_MG_9227.jpg" alt="" id="BLOGGER_PHOTO_ID_5510940522286685026" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_XNjT4XAs15w/THrLeIXlogI/AAAAAAAAAzg/kZfBqkAiCJ4/s1600/_MG_9175.jpg"&gt; &lt;img style="cursor: pointer; width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_XNjT4XAs15w/THrLeIXlogI/AAAAAAAAAzg/kZfBqkAiCJ4/s400/_MG_9175.jpg" alt="" id="BLOGGER_PHOTO_ID_5510940812544156162" border="0" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-7590582477137450578?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/7590582477137450578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/08/gamescom-2010.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7590582477137450578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7590582477137450578'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/08/gamescom-2010.html' title='Gamescom 2010'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_XNjT4XAs15w/THetnUxtLTI/AAAAAAAAAxw/cgHsB88sJh4/s72-c/_MG_9198.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-2215710374808157353</id><published>2010-05-09T13:39:00.014+02:00</published><updated>2010-05-10T21:57:35.882+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rockets'/><category scheme='http://www.blogger.com/atom/ns#' term='HD'/><category scheme='http://www.blogger.com/atom/ns#' term='maya'/><category scheme='http://www.blogger.com/atom/ns#' term='robot'/><category scheme='http://www.blogger.com/atom/ns#' term='dymaics'/><category scheme='http://www.blogger.com/atom/ns#' term='animation'/><category scheme='http://www.blogger.com/atom/ns#' term='tweeter'/><category scheme='http://www.blogger.com/atom/ns#' term='720p'/><title type='text'>Going HD and Twitter-y</title><content type='html'>I'll try not make it sound like a commercial for Utrecht University, but the projects in the last period were just pure awesome. So awesome, only to be fully captured in HD. The notebook had to be suspended in midair to get some fresh air respiration as it embarked on a three day pixel crunching journey to create the following 30 seconds of animation. Enjoy a bit of programmer's artwork.&lt;br /&gt;&lt;object width="320" height="180"&gt;&lt;param name="movie" value="http://www.youtube.com/v/Up6vvqyEyaA&amp;hl=en_US&amp;fs=1&amp;rel=0"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/Up6vvqyEyaA&amp;hl=en_US&amp;fs=1&amp;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="420" height="240"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;On top of this, I have decided to go all Twitter happy to spread some pixel furiosity a bit faster. Follow me on &lt;a href="http://twitter.com/furiouspixels"&gt;http://twitter.com/furiouspixels&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-2215710374808157353?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/2215710374808157353/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/05/going-hd-and-twitter-y.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/2215710374808157353'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/2215710374808157353'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/05/going-hd-and-twitter-y.html' title='Going HD and Twitter-y'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-6831570614207285752</id><published>2010-03-18T10:26:00.027+01:00</published><updated>2010-04-28T16:34:08.801+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maya'/><category scheme='http://www.blogger.com/atom/ns#' term='turbina'/><category scheme='http://www.blogger.com/atom/ns#' term='car'/><category scheme='http://www.blogger.com/atom/ns#' term='tutorial'/><category scheme='http://www.blogger.com/atom/ns#' term='render'/><category scheme='http://www.blogger.com/atom/ns#' term='fiat'/><category scheme='http://www.blogger.com/atom/ns#' term='modeling'/><title type='text'>Fiat Turbina - The Making of</title><content type='html'>It seems that I have one more post on ray-tracing, but now for something a bit different, a 1954 Fiat Turbina. I have chosen this model because of few reasons. It is sufficiently complex and there can be many approaches on how to model it. Equally important, it was the most aerodynamic shape of a car for 30 years, powered by a gas turbine yet technologically and commercially a complete failure, making it somewhat romantic.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/DW4SEVJAn2q8hqyjOxDjJmRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9g_dnJC0cI/AAAAAAAAAak/8i_CqtBtgMQ/s400/front.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/i3JdoxPsdUE6ULLJRLt8gWRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g_d3pi04I/AAAAAAAAAao/wc8_bU47-z4/s400/back.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/_WvdW-M3Cs4Y_42FF4mmx2Rlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9g_eArnTZI/AAAAAAAAAas/yGdOqHhCNJc/s400/front_up.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;What follows is not really a tutorial, but more a "making of". I'm not a 3D artist nor an expert on Maya, but I will try to answer any questions. I will start with the making of the wheels that will be used later. For this purpose I had set up an image projection for the side view and added tubes showing the rough dimensions of the tire and rim.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/mgruBfux7B50uRrfznbwJWRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9gp8z0pT0I/AAAAAAAAAYc/nO3oy5fqIWY/s400/1.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Then I drew a profile curve, revolved it into a tire and set up a cylindrical UV texture coordinate, needed for bump mapping.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/F-C5AyoHkA0Pq1deKPPtxmbGCMWybb-KOvIGiHJIgdM?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_XNjT4XAs15w/S9gxfaE10JI/AAAAAAAAAY8/-YFg37YdUsc/s400/2.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Next I used revolve to create the rim, the axel of the rim and then a cylinder for the rim spike.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/j4sSZ5pGGzCd1jJ2chHbGmbGCMWybb-KOvIGiHJIgdM?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9gxff1KScI/AAAAAAAAAZA/GxqPkFXwR7s/s400/3.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I cloned 32 spikes using Duplicate Special to create the complete rim.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/_OBxKHZeXYNO0nM5H6vG2WbGCMWybb-KOvIGiHJIgdM?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9gxfsAmMlI/AAAAAAAAAZE/umSxkzEorww/s400/4.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I added "Gametechnology" text as a tire brand and bended it.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/SwbUG2HHRy-BcYAVHoxjTGbGCMWybb-KOvIGiHJIgdM?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_XNjT4XAs15w/S9gxfk5oN3I/AAAAAAAAAZI/fZIwkFtrluw/s400/5.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;With the wheel done, I moved to the handle for opening the bonnet. As the handle is small and does not need to be modeled in much detail, I used polygon operations on a box to get the basic shape and then applied smooth to it. I started with a box and then pulled the vertices the get the silhouette&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/kXzIMo382AsGByjYneT3zmbGCMWybb-KOvIGiHJIgdM?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9gxfxe0eEI/AAAAAAAAAZM/XRTpJoa-iMw/s400/6.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I then extruded the top faces and re-sized them.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/3NeF6zQzGRwqbo2g1_xFs2Rlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9g03sKtUMI/AAAAAAAAAZQ/adNK8KZJWZw/s400/7.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;And finally, I extruded the actual handle part of it.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/YebBXGlp2aDDhyqQDo_S_mRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g03yMCNWI/AAAAAAAAAZU/J8ms9cxySoo/s400/8.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;With the small details done, it's time to move on to the body of the car. There are royalty free schematics on the internet for most cars, even exotic ones like the 1954 Fiat Turbine. I used three projections, one for each view.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/sEU353T_iGDrNrcvMngiJWRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g03wviIiI/AAAAAAAAAZY/iB3lWL1B698/s400/9.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In hope to work with NURBS, I drew the cross sections of the car.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/8hfS5RkEjcMZ7xc4LRUSjGRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9g04AZYAbI/AAAAAAAAAZc/XOnxKC5M2aw/s400/10.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;After few tries with NURBS, I decided to leave that to the industrial designers around the world and other skilled professionals and move on to SubD surfaces. I used Loft to join the cross sections and get a polygonal mesh, which provided a better starting point then a simple box.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/6BorwvXdoTnJ-iau7JbIZ2Rlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9g04LGQPKI/AAAAAAAAAZg/fxFXLCiDj0M/s400/11.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The next few steps show the process of refining the mesh into the car shape using just few operations like extrude, remove, append, split and merge vertex.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/zY6OFL5Nkpkq9z3Yxe8j7GRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9g6UFqMzkI/AAAAAAAAAZk/uLRbkv5Xefg/s400/12.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I also cut off the faces where the windscreen and windows will be. The original faces were curved along both axes which is usually not the case for glass, especially not in the 50's. This is very important for realistic reflections and refractions, so I decided to model them later instead of using the faces already there.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/DHjPss93CAI4gkRYoddHYGRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9g6URIi6hI/AAAAAAAAAZo/32LonEvXWs8/s400/13.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Conversion of the model into SubD showed that the topology of the model needs to be changed in order to get a smooth surface fitting the car. All the faces with more than four vertices needed to be modified and while keeping as regular structure as possible. Triangles and vertices shared by more than 4 edges were not my friend as they can break the surface too.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/4VRnYj533AjGeESEHuLjf2Rlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g6UVlsAWI/AAAAAAAAAZs/qz1_1jjf2Hk/s400/14.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/hkXZHIqckjwxEUe7uHsa9mRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_XNjT4XAs15w/S9g6U2rPCsI/AAAAAAAAAZw/kBucePF3JF0/s400/15.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Next I created the windows from the refined mesh.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/LYnkpPxOU1tQx62dCKTYMWRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9g6Uy8Aq7I/AAAAAAAAAZ0/F7E4EzoitHU/s400/16.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Early in the making of the model I decided to use bump map for some of the small details in the body instead of the modeling them. Having the low polygon mesh, I thought it would be the best time to create the UV coordinates. I used manual selection of faces and planar projection on them the get the basic layout and then manually stitch them in the UV editor.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/2bJkAsUjEZw4TwXk87lny2Rlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g65XDQqII/AAAAAAAAAZ4/f5N2WdbGOLM/s400/17.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Conversion to SubD proved to be quite destructive for the UVs as lines are mapped onto curved lattices and the tessellation is adaptive.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/xyFvd1-6QlBlsziBuBG1qGRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_XNjT4XAs15w/S9g65sf4XvI/AAAAAAAAAZ8/OGetBAQRWKU/s400/18.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I used a Subdiv proxy instead, which was easier to control because of the regular tessellation. Next few screen shots show creasing on some of the edges and vertices.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/vcAkpMEbf5_sZ_iHDmCB-mRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_XNjT4XAs15w/S9g65kScmrI/AAAAAAAAAaA/CcBV0kmSu3g/s400/19.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;With the final structure of the fully defined I moved to creating the frames for the windscreens using extrusion and later the windscreens themselves. We can also see some of the early renders.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/QSdAskIzZ0r9NOiHSAppdGRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9g654Up5-I/AAAAAAAAAaE/0Tnd8sODxjA/s400/20.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Next I added some chrome details using lofted curves on the mesh and then extruding the polygons on them. I also added some interior, which simply serves to prevent the car from looking as an empty shell.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/tWOXxKlx3OTWkLP9DqizsGRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9g65-fMPFI/AAAAAAAAAaI/Muc6DWjHaPQ/s400/21.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/uuYAGH9pwqU7IpHzALSbNmRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g8xMc9m6I/AAAAAAAAAaM/FsYSRNDi5kc/s400/22.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The geometry is finally finished, as we can see from the render below.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/AVRM9SbyK8PnSbz-0eOM52Rlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh4.ggpht.com/_XNjT4XAs15w/S9g8xTUufuI/AAAAAAAAAaQ/fIgKmeVFNUA/s400/23.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Next I added bump mapping and did refinements on the color texture mapping. To do this, I had to unwrap the UVs, as bump mapping in Maya uses world coordinates in combination with UVs and therefore did display properly on the mirrored side of the body. The screenshots shown the final UV setup for the bump map and color map&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/X7Qh0tRR-S09031snELJEGRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh5.ggpht.com/_XNjT4XAs15w/S9g8xqdG2nI/AAAAAAAAAaU/AfMoYWu3jnA/s400/24.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/fA7BNes3MR6IXBD-Jd3VcWRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g8x77e9GI/AAAAAAAAAaY/afYf_uBpxV0/s400/25.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I will not go into more details about the texturing process, since is not part of the assignment. I'll just state that it took a surprisingly big amount of the time (more than 30% of the total.&lt;br /&gt;&lt;br /&gt;With the model done it was time to render it. The materials in use are just basic blin for body, anisotropic for the chrome parts and transparent glass with index of refraction around 1.4. As all materials are highly reflective, I added some objects to the scene to be reflected into the car. First, a background was added, similar to a backdrop used in photo studios that doesn't have any visible sharp edges. In addition I added two stripes to further pronounce the shape of the body. For lighting, I used a simple three light setup with area lights and multisample shadows. All of this can be seen on the screenshot.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/D8rg8hXsreL0umEUOin9d2Rlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh6.ggpht.com/_XNjT4XAs15w/S9g8x8PiBAI/AAAAAAAAAac/K0d6SjkForM/s400/26.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;The final addition was a slight tint if green in the glass material, as this draft renders shows.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://picasaweb.google.com/lh/photo/uVf0t6NDIlOmPqfNFPCWcmRlxo9Hir2dByuGcNEac84?feat=embedwebsite"&gt;&lt;img src="http://lh3.ggpht.com/_XNjT4XAs15w/S9g_dTkZADI/AAAAAAAAAag/CM-9IicKx6k/s400/27.jpg" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Done using an Intous 4 Wacom Tablet and Maya 2009.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-6831570614207285752?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/6831570614207285752/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/03/fiat-turbina.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/6831570614207285752'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/6831570614207285752'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/03/fiat-turbina.html' title='Fiat Turbina - The Making of'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh5.ggpht.com/_XNjT4XAs15w/S9g_dnJC0cI/AAAAAAAAAak/8i_CqtBtgMQ/s72-c/front.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-7113505476424030756</id><published>2010-03-10T01:10:00.015+01:00</published><updated>2010-03-10T01:50:13.647+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='normal'/><category scheme='http://www.blogger.com/atom/ns#' term='box boxes'/><category scheme='http://www.blogger.com/atom/ns#' term='cube'/><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='ray'/><title type='text'>Tracing Boxes</title><content type='html'>This is my last post on ray tracing, and it’s on tracing boxes. Spheres alone are not all that fun and the infinite planes have the drawback of being...well infinite. Therefore, I decided to put boxes to my ray tracer. It is of course possible to use 12 triangles. This is a general solution but it is not exactly cost effective and moreover, it does not scale  well to collision detection, where boxes are often used (I am working on some physics code too). I started my journey by searching the web and of course, &lt;a href="http://realtimecollisiondetection.net/"&gt;Real-Time Collision Detection by Christer Ericson&lt;/a&gt;, which is probably the best book in its field. What I got was plenty of fast algorithms that only tell if the there is an intersection or not, some of which give the intersection position too. Also few algorithms that give the normal vector as well, but most of them did checking against all 6 planes and went through lots of boundary conditions. As a normal vector is needed in ray tracing for light calculation, I decided to make the best of the both worlds.&lt;br /&gt;The idea is very simple. Use the fast algorithm to get the intersection position and then use that information to get the normal. Say we have an axis aligned unit cube centered at the origin, a point on it and a vector to that point. The surface normal at that point is in the direction in which the vector extends the most. In case it’s not immediately obvious, let’s take one side of the cube, say the one laying on the &lt;span style="font-style: italic;"&gt;x=1&lt;/span&gt; plane. The side can be defined as an intersection of the x=1 plane and the &lt;a href="http://en.wikipedia.org/wiki/Cone_%28linear_algebra%29"&gt;cone&lt;/a&gt; made of half-spaces defined by &lt;span style="font-style: italic;"&gt;x&gt;|y|&lt;/span&gt; and &lt;span style="font-style: italic;"&gt;x&gt;|z&lt;/span&gt;|, which is exactly the same as the original statement. So now we have three steps of the algorithm.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;First, calculate the position of the center of the box and calculate the vector from it to the point on the surface.&lt;/li&gt;&lt;li&gt;Next, scale the vector into a unit cube, to cancel the scaling of the box along the axes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Finally, zero out the coordinates with smaller absolute value, and then normalize the resulting vector.&lt;/li&gt;&lt;/ul&gt;The first part of the algorithm, used to calculate the position of intersection, is taken straight from a &lt;a href="http://www.amazon.com/Fundamentals-Computer-Graphics-Peter-Shirley/dp/1568814690/ref=dp_ob_title_bk"&gt;text book on graphics&lt;/a&gt;. The relevant code from the Box class is below.&lt;pre class="brush: java"&gt;&lt;br /&gt;public class Box extends Traceable {&lt;br /&gt;&lt;br /&gt;protected Vec3;&lt;br /&gt;protected Vec3 max;&lt;br /&gt;&lt;br /&gt;// Component-wise min&lt;br /&gt;public static Vec3 min(Vec3 a, Vec3 b) {&lt;br /&gt;return new Vec3( min(a.x, b.x),&lt;br /&gt;               min(a.y, b.y),&lt;br /&gt;               min(a.z, b.z));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Component-wise max&lt;br /&gt;public static Vec3 max(Vec3 a, Vec3 b) {&lt;br /&gt;return new Vec3( max(a.x, b.x),&lt;br /&gt;               max(a.y, b.y),&lt;br /&gt;               max(a.z, b.z));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;@Override&lt;br /&gt;public IntersectionInfo intersect(Ray r) {&lt;br /&gt;// Interval based test&lt;br /&gt;Vec3 direction = new Vec3(r.direction);&lt;br /&gt;direction.normalize();&lt;br /&gt;//&lt;br /&gt;Vec3 oneoverdir = new Vec3(1.0f / direction.x, 1.0f / direction.y, 1.0f / direction.z);&lt;br /&gt;Vec3 tmin = min.minus(r.origin).times(oneoverdir);&lt;br /&gt;Vec3 tmax = max.minus(r.origin).times(oneoverdir);&lt;br /&gt;//&lt;br /&gt;Vec3 realmin = min(tmax, tmin);&lt;br /&gt;Vec3 realmax = max(tmax, tmin);&lt;br /&gt;//&lt;br /&gt;float minmax = min(min( realmax.x, realmax.y), realmax.z);&lt;br /&gt;float maxmin = max(max( realmin.x, realmin.y), realmin.z);&lt;br /&gt;&lt;br /&gt;if(minmax &gt;= maxmin &amp;amp;&amp;amp; maxmin &gt; 0.0f) { // Have intersection&lt;br /&gt; // Get position&lt;br /&gt; float t = maxmin;&lt;br /&gt; Vec3 position = r.origin.add(direction.times(t));&lt;br /&gt;&lt;br /&gt; // Get normal&lt;br /&gt; // 1. Get vector to relative position&lt;br /&gt; Vec3 center = max.add( min ).times(0.5f);&lt;br /&gt;Vec3 normal = position.minus(center);&lt;br /&gt;&lt;br /&gt; // 2. Scale to matching unit box&lt;br /&gt; normal.x /= max.x - min.x;&lt;br /&gt; normal.y /= max.y - min.y;&lt;br /&gt; normal.z /= max.z - min.z;&lt;br /&gt;&lt;br /&gt; // 3. Keep the largest axis&lt;br /&gt; if(Math.abs(normal.x) &gt; Math.abs(normal.y)) {&lt;br /&gt;    normal.y = 0.0f;&lt;br /&gt;    if(Math.abs(normal.x) &gt; Math.abs(normal.z))&lt;br /&gt;       normal.z = 0;&lt;br /&gt;    else&lt;br /&gt;       normal.x = 0;&lt;br /&gt; } else {&lt;br /&gt;    normal.x = 0;&lt;br /&gt;    if(Math.abs(normal.y) &gt; Math.abs(normal.z))&lt;br /&gt;       normal.z = 0;&lt;br /&gt;    else&lt;br /&gt;       normal.y = 0;&lt;br /&gt; }&lt;br /&gt; // 4. Normalize to unit&lt;br /&gt; normal.normalize();&lt;br /&gt; return new IntersectionInfo(position, normal, t, this);&lt;br /&gt;}&lt;br /&gt;//&lt;br /&gt;return new IntersectionInfo(false);&lt;br /&gt;}&lt;br /&gt;} // end class&lt;br /&gt;&lt;/pre&gt;This might not be the fastest algorithm, but it beats most that I have come across on the internet. Here is one very ugly image showing ray tracing of a box in room and some normal mapping. Also the scene from the post on &lt;a href="http://furiouspixels.blogspot.com/2010/01/ambient-occlusion.html"&gt;ambient occlusion&lt;/a&gt; was modeled with some boxes and a sphere.&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XNjT4XAs15w/S5boJnMUABI/AAAAAAAAAYU/C4SxVoIFL8Y/s1600-h/29.png"&gt;&lt;img style="cursor: pointer; width: 304px; height: 300px;" src="http://3.bp.blogspot.com/_XNjT4XAs15w/S5boJnMUABI/AAAAAAAAAYU/C4SxVoIFL8Y/s400/29.png" alt="" id="BLOGGER_PHOTO_ID_5446796051188285458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;The algorithm assumes that the box is axis aligned. This is not really an issue, as you can always do the intersection in the local space of the box. Transform the ray to the local space of the box with the inverse of rotation matrix of the box, find the intersection and normal and transform them back to world space with the rotation matrix of the box. Just have in mind that if you have scaling and translation applied to the box, the direction of the ray and the normal of the surface need &lt;a href="http://www.cgafaq.info/wiki/Transforming_Normals"&gt;special care&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-7113505476424030756?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/7113505476424030756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/03/tracing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7113505476424030756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/7113505476424030756'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/03/tracing.html' title='Tracing Boxes'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XNjT4XAs15w/S5boJnMUABI/AAAAAAAAAYU/C4SxVoIFL8Y/s72-c/29.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-882515374126288036</id><published>2010-01-04T15:17:00.017+01:00</published><updated>2011-09-13T01:53:06.207+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='occlusion'/><category scheme='http://www.blogger.com/atom/ns#' term='ambient'/><category scheme='http://www.blogger.com/atom/ns#' term='global ilumnation'/><category scheme='http://www.blogger.com/atom/ns#' term='gi'/><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='light'/><title type='text'>Ambient Occlusion</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div style="text-align: justify;"&gt;Ambient Occlusion is a cheap and simple way to add global illumination effect to an rendered image, especially for a ray tracer. This adds depth and realism to the image. The sample below shows the difference.&lt;/div&gt;&lt;div style="text-align: center;"&gt;An image rendered with ambient occlusion.&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_XNjT4XAs15w/S0I2INgE_MI/AAAAAAAAAW8/KFAyBS8TCG8/s1600-h/AbOcc.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5422956415998557378" src="http://1.bp.blogspot.com/_XNjT4XAs15w/S0I2INgE_MI/AAAAAAAAAW8/KFAyBS8TCG8/s400/AbOcc.png" style="cursor: pointer; height: 400px; width: 400px;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;An image rendered without ambient occlusion.&lt;a href="http://4.bp.blogspot.com/_XNjT4XAs15w/S0I2Qb4aMqI/AAAAAAAAAXE/PhDNeBEwPow/s1600-h/NoAbOcc.png"&gt;&lt;img alt="" border="0" id="BLOGGER_PHOTO_ID_5422956557297660578" src="http://4.bp.blogspot.com/_XNjT4XAs15w/S0I2Qb4aMqI/AAAAAAAAAXE/PhDNeBEwPow/s400/NoAbOcc.png" style="cursor: pointer; height: 400px; width: 400px;" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: justify;"&gt;The technique is as fake as it is straight forward, but if it's good enough for Pixar should be good enough for most purposes. Ambient occlusion for certain surface point is calculated by measuring how much light is blocked by it's surroundings. In a ray tracer this is done by casting rays from the surface point in all directions and counting how many hit the scene. In the following implementation we can also limit the radius if needed and the amount of shadowing due to occlusion.&lt;/div&gt;&lt;pre class="brush: java"&gt;int smp = Tracer.ambientOcclusionSamples;&lt;br /&gt;int c = smp;&lt;br /&gt;for(int i = 0; i &amp;lt; smp; i++) {    &lt;br /&gt;   Vec3 dir = Vec3.randomOnHemisphere(nearestHit.normal);&lt;br /&gt;   dir = dir.times(Tracer.occlusionRadius);&lt;br /&gt;   Vec3 org = nearestHit.location;&lt;br /&gt;   Ray feeler = new Ray(org, dir);&lt;br /&gt;   if( feeler.hit( nearestHit.object ) )&lt;br /&gt;      c--;&lt;br /&gt;}&lt;br /&gt;color = color.times(1.0f - Tracer.occlusionAmount) .add( color.times((c * Tracer.occlusionAmount) / (float)smp) );&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;Most of the code should be staright forward and easy to understand only the  &lt;i&gt;Vec3.randomOnHemisphere(nearestHit.normal);&lt;/i&gt; function requires some explanation. As the name states, this function returns a vector, uniformly distributed on the unit hemisphere above the given vector. This is achieved by trail and error; we create random vectors in a unit cube and discard the corers to get uniform distribution on a unit sphere and than discard all the vectors not facing the same way as the given vector using a dot product test.&lt;/div&gt;&lt;pre class="brush: java"&gt;public static Vec3 randomOnHemisphere(Vec3 direction) {&lt;br /&gt;   // Cut off the corners of the cube&lt;br /&gt;   Vec3 v;&lt;br /&gt;   do {&lt;br /&gt;   v = new Vec3(&lt;br /&gt;      2 * (float)Math.random() - 1,&lt;br /&gt;      2 * (float)Math.random() - 1,&lt;br /&gt;      2 * (float)Math.random() - 1);&lt;br /&gt;   } while(v.length() &amp;gt; 1.0f &amp;amp;&amp;amp; v.dot(direction)&lt;br /&gt;   v.normalize();&lt;br /&gt;   return v;&lt;br /&gt;}&lt;/pre&gt;&lt;div style="text-align: justify;"&gt;On average, no more than two thirds of the vectors are discarded. This might not be the most efficient method, but it does not require any vector transformations and matrix multiplication. Another way to achieve the same effect is to use a precalculated set of vectors distributed on the vertices of a regular polyhedron and transform it to face in the given direction. In a addition a random rotation around the main axis will remove the artifacts of using the same set of vectors.&lt;br /&gt;&lt;b&gt;UPDATE&lt;/b&gt;: It seams that this article is getting a lot more attention during the semester, so what better date to make a small correction than beginning of September.&lt;br /&gt;The above method treats all rays shoot from the a certain point equally, while actually they don't contribute to the illumination of that point equally. Instead their contribution needs to be weighted by the dot product of the ray direction with the normal at that point, according to the cosine law.&lt;br /&gt;I have the original sources for the tracer, but have lost the scene files. If I find them and find some time I might post an updated version of the code and a better looking image.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-882515374126288036?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/882515374126288036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2010/01/ambient-occlusion.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/882515374126288036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/882515374126288036'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2010/01/ambient-occlusion.html' title='Ambient Occlusion'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_XNjT4XAs15w/S0I2INgE_MI/AAAAAAAAAW8/KFAyBS8TCG8/s72-c/AbOcc.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-398708137205396298</id><published>2009-11-10T13:15:00.014+01:00</published><updated>2009-11-10T22:29:19.792+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='reflection'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='refraction'/><title type='text'>Reflection and Refraction</title><content type='html'>After some tinkering with the stats, I got some interesting finds. Many people coming across this blog were searching for "cream pasta", but more importantly, the rest 75% were actually searching for ray tracing topics, especially reflection and refraction. While the image from the &lt;a href="http://furiouspixels.blogspot.com/2009/10/tracing-rays.html"&gt;last post&lt;/a&gt; beautiful as it is, it does not give too much info. Some Java code snipets should help a bit more.&lt;br /&gt;Now reflection is fairly simple. The angle between the reflected ray and the normal is the same as the angle between the incoming ray and the normal.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public static Vec3 reflect(Vec3 normal, Vec3 incident) {&lt;br /&gt;float cosTheta = normal.dot(incident);&lt;br /&gt;return incident.minus( normal.times(2 * cosTheta) );&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;Calculating the direction of the ray after refraction is a bit more involved. We start with &lt;a href="http://en.wikipedia.org/wiki/Snell%27s_law"&gt;Snell's Law&lt;/a&gt;, stating that ratio of the sines of the angles of incidence and refraction is equivalent to the opposite ratio of the indices of refraction, to get the direction of the refracted ray. The outgoing angle is obviously not always defined with this formula, which bring us to the next phenomena. When the light is traveling from a medium with higher optical density to a medium with a lower one and the incident angle is larger than the critical angle total internal reflection occurs and no light leaves the medium. In fact some light is almost always reflected and the amount is governed by the &lt;a href="http://en.wikipedia.org/wiki/Fresnel_equations"&gt;Fresnel equations&lt;/a&gt;. In my implementation I just approximate the amount with the dot product (with complete disregard for all the complexities, not to mention frequency and polarization), but the visual result is good.&lt;br /&gt;With some &lt;a href="http://www.flipcode.com/archives/Reflections_and_Refraction_in_Raytracing.shtml"&gt;lengthy transformations&lt;/a&gt; we can get a formula for the direction of the refracted ray that contains the same condition, defining total internal reflection, as Snell's law. Thus, when the flowing method can't calculate the direction total internal reflection has occurred.&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;public static Vec3 refract(Vec3 normal, Vec3 incident, float n1, float n2) {&lt;br /&gt; float dn = incident.dot(normal);&lt;br /&gt;  &lt;br /&gt; float c = 1 - ((n1*n1)*(1-dn*dn) ) / (n2*n2);&lt;br /&gt; if(c &amp;lt 0)&lt;br /&gt;  return null;&lt;br /&gt;  &lt;br /&gt; Vec3 t = incident.minus( normal.times( dn ) ).times( n1/n2 )&lt;br /&gt;  .minus(&lt;br /&gt;  normal.times( (float)Math.sqrt(c)) );&lt;br /&gt; &lt;br /&gt; return t; &lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;I hope that was more insightful. Feel free to drop a comment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-398708137205396298?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/398708137205396298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2009/11/reflection-and-refraction.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/398708137205396298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/398708137205396298'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2009/11/reflection-and-refraction.html' title='Reflection and Refraction'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-1238881334712773914</id><published>2009-10-03T23:40:00.005+02:00</published><updated>2009-10-04T01:57:37.295+02:00</updated><title type='text'>Tracing Rays</title><content type='html'>&lt;div style="text-align: left;"&gt;I have never considered simple rays more precious than I do now and not just because I am building a ray tracer, but because I have recently moved Utrecht, Netherlands and sunlight is a scarce commodity here. I missed the thrill of long lectures and midterm exams, so am student yet again! Game and Media Technology postgraduate at Utrecht University and so far it's great. This brings me back to my ray tracer and no ray tracer is complete without a &lt;a href="http://en.wikipedia.org/wiki/Cornell_Box"&gt;Cornell Box&lt;/a&gt; and some balls, exhibit below:&lt;/div&gt;&lt;div&gt;&lt;img src="http://3.bp.blogspot.com/_XNjT4XAs15w/SsfXI1WS1zI/AAAAAAAAARM/dCXeWXmROUM/s400/CornellBox.png" style="cursor:pointer; cursor:hand;width: 400px; height: 400px;" border="0" alt="" id="BLOGGER_PHOTO_ID_5388512025931601714" /&gt;&lt;/div&gt;&lt;div&gt;It sports a vast number of very basic features (hugely popular in ray tracers from the early 90's) like:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Phong materials&lt;/li&gt;&lt;li&gt;Anti-aliasing&lt;/li&gt;&lt;li&gt;Light reflection&lt;/li&gt;&lt;li&gt;Light refraction (with Fresnel reflection)&lt;/li&gt;&lt;li&gt;Area light and soft shadows&lt;/li&gt;&lt;li&gt;Soft reflections&lt;/li&gt;&lt;li&gt;and more to come!&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The policy of the university on source sharing  is "No." so no code pasting this time, but I am open for questions and discussion. I don't think too many people will find the code useful anyhow and plus you can always download &lt;a href="http://www.povray.org/"&gt;POV ray&lt;/a&gt;, which is a world class open source ray tracer. &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-1238881334712773914?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/1238881334712773914/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2009/10/tracing-rays.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1238881334712773914'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1238881334712773914'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2009/10/tracing-rays.html' title='Tracing Rays'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XNjT4XAs15w/SsfXI1WS1zI/AAAAAAAAARM/dCXeWXmROUM/s72-c/CornellBox.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-5945262430453726531</id><published>2009-04-01T00:39:00.003+02:00</published><updated>2009-04-01T00:45:53.568+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='last fm last.fm pasta spinach'/><title type='text'>Last.fm and Spinach Pasta</title><content type='html'>The &lt;a href="http://blog.last.fm/2009/03/24/lastfm-radio-announcement"&gt;latest news&lt;/a&gt; from Last.fm says that users who are in countries other than USA, UK and Germany will have to subscribe for €3.00 per month for listening to Last.fm Radio. I am not too happy about this, generally because I have discovered a whole bunch of new bands and musicians with Last.fm, even with the very limited selection of songs the service has. In fact lets make an experiment. Go to &lt;a href="http://www.last.fm/listen"&gt;http://www.last.fm/listen&lt;/a&gt; and waste one of your 30 trail plays by typing "Hot Action Cop". I bet "Fever The Flava" will start in few seconds. It is a cool song, but gets a bit old after ten times in the same day. Now €3.00 is not really that much in some countries but the again in some it might be, and the selectiveness is just plain not cool. Being bought up in half country, half zoo one might think that I should have grown immune to any discrimination coming my way, but somehow this bothers me.&lt;br /&gt;Now so far this post has been somewhat informative, but not really helpful. But instead of geeky advices on how to get streaming music now when last.fm has gone all sour, I will tell you what else you can do with €3.00. How about a nice spinach and cream pasta.*&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XNjT4XAs15w/SdKcK2nlPyI/AAAAAAAAAPk/K9Wk2PQJsBw/s1600-h/pasta.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 267px;" src="http://1.bp.blogspot.com/_XNjT4XAs15w/SdKcK2nlPyI/AAAAAAAAAPk/K9Wk2PQJsBw/s400/pasta.jpg" alt="" id="BLOGGER_PHOTO_ID_5319485820152135458" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Preheat the oven to 200ºC (473 K). Boil some pasta, preferably whole wheat pasta for this one, in a big bowl. Throw about 150 gr of spinach into a sauce pan and drizzle it with olive oil. Add just a bit of garlic and salt. When the spinach is soft, but still bright green add some white cheese or alternatively some feta cheese. After a minute of stirring, add some cream. As soon as the cream gets homogeneous, reduce the heat to very low and let it simmer. The pasta should be done by now, so drain it and mix it with the creamy sauce. Add some freshly grounded pepper and grated parmesan. Put it in the oven for 20 minutes. Bon appétit!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:78%;"&gt;*Note that the quantities and costs are per serving. The total cost of the meal may vary with to electricity prices and hence country.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-5945262430453726531?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/5945262430453726531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2009/04/lastfm-and-spinach-pasta.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/5945262430453726531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/5945262430453726531'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2009/04/lastfm-and-spinach-pasta.html' title='Last.fm and Spinach Pasta'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_XNjT4XAs15w/SdKcK2nlPyI/AAAAAAAAAPk/K9Wk2PQJsBw/s72-c/pasta.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-1136156711697679506</id><published>2009-03-21T20:39:00.016+01:00</published><updated>2010-02-04T22:14:18.117+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='steering behaviors'/><category scheme='http://www.blogger.com/atom/ns#' term='silverlight'/><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='artificial intelligence'/><category scheme='http://www.blogger.com/atom/ns#' term='vehicles'/><title type='text'>Vehicle</title><content type='html'>As I wrote the previous post, this week I'll be writing about AI agents. It is a cool subject and I am eager to see what the final results will be. Now, AI might be a strong word for the dumb behavior that this vehicle displays but all the underlying math is there and should provide a basis for development of a more sophisticated system. To make thing more interesting I have decided to implement everything in &lt;a href="http://silverlight.net/"&gt;Silverlight&lt;/a&gt; so that can be available in a browser and to test  drive the technology while I am at it. Lets see the final result, and than go through the process.&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://silverlight.services.live.com/invoke/94358/SeekAndFlee/iframe.html" style="width: 400px; height: 400px;" scrolling="no" frameborder="0"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;I have used the Vehicles as a title, generally because it's the title of a vary inspirational book by Valentino Braitenberg, that touches the subject of autonomus agents as a early as 1984 and I can recomend it to anyone even remotely interested in the subject. It's just 17$ on &lt;a href=http://www.amazon.com/Vehicles-Experiments-Psychology-Valentino-Braitenberg/dp/0262521121"&gt;Amazon&lt;/a&gt;. While this book gives more than enough philosophical background, most of the engeenering is based on  the &lt;a href="http://www.red3d.com/cwr/steer/"&gt;Steering Behaviors by &lt;/a&gt;&lt;a href="http://www.red3d.com/cwr/steer/"&gt;Craig W. Reynolds&lt;/a&gt;. Steering behaviors are just simple rules that give steering directions to the vehicles. By smart use and combination of these rules we can build complex behaviors that mimic the behavior a bird or sheep in a flock. Some pepole like &lt;a href="http://www.red3d.com/cwr/steer/"&gt;Craig W. Reynolds&lt;/a&gt; have been working on steering behaviors since the 80's, making them more experinced on the subject than I am in waking, so I will not give a watered down explanation, rather just refer to their pages. What I will give is a some C# code. Now why C# and Silverlight? I have been a long time Flash user for &lt;a href="http://enci.deviantart.com/art/Robotic-Arm-IK-56448759"&gt;small demos&lt;/a&gt; like this one. But having a real programing language like C# is just too good not to try and I am not a huge fan of scripting languages, like Action Script. Plus the tools are &lt;a href="http://www.microsoft.com/express/vcsharp/"&gt;completely free&lt;/a&gt;. For this post I will implement only the most basic behavoirs &lt;a href="http://www.red3d.com/cwr/steer/SeekFlee.html"&gt;seek and flee&lt;/a&gt;. Bacause I would like to use it in a Silverlight aplication I will create a Silverlight Library project in Visual Studio. This will be our AI library and should not be aware of any drawing code, so that it can be used in a difirent project, say an XNA game. Now, the first thing that stroke me was that the &lt;a href="http://msdn.microsoft.com/en-us/library/system.windows.vector.aspx"&gt;System.Windows.Vector&lt;/a&gt; was just not available on my computer and of course I have the latest SDK. Now instead of wasting couple of days I decided to write my own implementation of a 2D Vector. I think I have done one in every language I have come across. And then a Matrix class implementation to do some transformations over the vectors (I assume knowledge basic linear algebra). With all that in place we can make a simple vehicle class which simply takes the output from the steering behavior and apply is as a force. The update method of the vehicle class looks something like this:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;virtual Update(float dt)&lt;br /&gt;{&lt;br /&gt;   Vector2 steeringForce = steering.Calculate();&lt;br /&gt;   //Acceleration = Force/Mass&lt;br /&gt;   Vector2 acceleration = steeringForce / mass;&lt;br /&gt;   velocity += acceleration * dt;&lt;br /&gt;   velocity.Truncate(maxSpeed);&lt;br /&gt;   position += velocity * dt;&lt;br /&gt;   if (velocity.LengthSq &amp;gt; 0.00000001)&lt;br /&gt;   {&lt;br /&gt;      heading = Vector2.Normalize(velocity);&lt;br /&gt;      //&lt;br /&gt;      side = heading.Perp;&lt;br /&gt;   }&lt;br /&gt;   position.WrapAround(400, 400);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;The Seek and Flee methods are extremely simple as you can see:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;Vector2 Seek(Vector2 targetPos)&lt;br /&gt;{&lt;br /&gt;   if ((targetPos - vehicle.Position).LengthSq &amp;gt; threshold)&lt;br /&gt;   {&lt;br /&gt;      Vector2 desiredVelocity = Vector2.Normalize(targetPos - vehicle.Position) * vehicle.MaxSpeed;&lt;br /&gt;      return desiredVelocity - vehicle.Velocity;&lt;br /&gt;   }&lt;br /&gt;   return new Vector2(0.0f);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private Vector2 Flee(Vector2 targetPos)&lt;br /&gt;{&lt;br /&gt;   if ((vehicle.Position - targetPos).LengthSq &amp;lt; panicDistanceSq &amp;amp;&amp;amp; (vehicle.Position - targetPos).LengthSq &amp;gt; 0.1f)&lt;br /&gt;   {&lt;br /&gt;       Vector2 desiredVelocity = Vector2.Normalize(vehicle.Position - targetPos) * vehicle.MaxSpeed;&lt;br /&gt;      return desiredVelocity - vehicle.Velocity;&lt;br /&gt;   }&lt;br /&gt;   return newVector2(0.0f);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;In the Calculate method we just average the force from both, like so:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;Vector2 Calculate()&lt;br /&gt;{&lt;br /&gt;return (Seek(target1) + Flee(target2)) * 0.8f;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now I want to use that in the Silverlight application, and one of the coolest features in Silverlight, the MatrixTransform class enabling us to apply some &lt;a href="http://www.senocular.com/flash/tutorials/transformmatrix/"&gt;affine transformations&lt;/a&gt; fast. Anyone who has done some graphics programming will appreciate this. All we need to do is take the heading vector from the vehicle, its perpendicular vector and the position of the vehicle and we have our transformation matrix:&lt;br /&gt;&lt;pre class="brush: java"&gt;&lt;br /&gt;transformMatrix.M11 = vehicle.Heading.x;&lt;br /&gt;transformMatrix.M12 = vehicle.Heading.y;&lt;br /&gt;transformMatrix.M21 = vehicle.Heading.Perp.x;&lt;br /&gt;transformMatrix.M22 = vehicle.Heading.Perp.y;&lt;br /&gt;transformMatrix.OffsetX = vehicle.Position.x;&lt;br /&gt;transformMatrix.OffsetY = vehicle.Position.y;&lt;br /&gt;transform.Matrix = transformMatrix;                // Makes sense ha?&lt;br /&gt;shape.RenderTransform = transform;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Just be careful with the origin of the transformation. Expression Blend uses the center by default, while the API will use top left. You can download the code &lt;a href="http://cid-5ffdbec9f294a379.skydrive.live.com/self.aspx/Public/Agents.zip"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Next week pizza! Just kidding, I’ll be adding obstacles.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-1136156711697679506?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/1136156711697679506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2009/03/vehicle.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1136156711697679506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1136156711697679506'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2009/03/vehicle.html' title='Vehicle'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-9167420514311334537</id><published>2009-03-15T10:46:00.008+01:00</published><updated>2009-03-21T21:29:38.983+01:00</updated><title type='text'>Cave Day</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_XNjT4XAs15w/ScVL4jT9gVI/AAAAAAAAAPM/iId59yRbpY8/s1600-h/postojna.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 267px;" src="http://3.bp.blogspot.com/_XNjT4XAs15w/ScVL4jT9gVI/AAAAAAAAAPM/iId59yRbpY8/s400/postojna.jpg" alt="" id="BLOGGER_PHOTO_ID_5315738370104459602" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Lets start in a completely reverse order, with a nice photo of the Postojna Cave.&lt;br /&gt;It has been confirmed by a comity of four friends that this place is actually more humid than my apartment in Ljubljana. Which brings me to another topic, I currently live in Ljubljana, Slovenia, where I work for &lt;a href="http://www.zootfly.com/"&gt;ZootFly&lt;/a&gt;, a medium size game studio. The studio is very busy developing a game based on popular TV series by Fox that has lot to do with someone escaping from place where you put convicts in. This somewhat explains the hiatus on this blog. Now to add some twist, next post will be on simple AI agents.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-9167420514311334537?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/9167420514311334537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2009/03/cave-day.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/9167420514311334537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/9167420514311334537'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2009/03/cave-day.html' title='Cave Day'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_XNjT4XAs15w/ScVL4jT9gVI/AAAAAAAAAPM/iId59yRbpY8/s72-c/postojna.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-4075299121461470883</id><published>2008-01-17T12:05:00.002+01:00</published><updated>2009-03-21T21:22:28.631+01:00</updated><title type='text'>The Cake is a Lie!</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XNjT4XAs15w/ScVMf7fKb9I/AAAAAAAAAPc/BwNLdBgXwt4/s1600-h/Portal_Screen07.jpg"&gt;&lt;img style="cursor: pointer; width: 400px; height: 225px;" src="http://1.bp.blogspot.com/_XNjT4XAs15w/ScVMf7fKb9I/AAAAAAAAAPc/BwNLdBgXwt4/s400/Portal_Screen07.jpg" alt="" id="BLOGGER_PHOTO_ID_5315739046608793554" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://orange.half-life2.com/portal.html"&gt;Portal&lt;/a&gt; is by far the best game I've played in years. For those who haven't tried Portal yet, this is one of the most innovative games in quite some time, with a nice dose of cynical humor. It's a 3d puzzle game from &lt;a href="http://www.valvesoftware.com/"&gt;Valve&lt;/a&gt;, where you pass through the level by manipulating portals. Gamespot has a detailed &lt;a href="http://www.gamespot.com/xbox360/action/halflife2episode2/review.html?om_act=convert&amp;amp;om_clk=tabs&amp;amp;tag=tabs;reviews"&gt;review&lt;/a&gt; of the game, so I will not go into details.&lt;br /&gt;&lt;br /&gt;What I find cool about the game is that its gameplay mechanics come from &lt;a href="http://www.fileplanet.com/161458/160000/fileinfo/Narbacular-Drop-%5BFree-Game%5D"&gt;Narbacular Drop&lt;/a&gt;&lt;i&gt;, &lt;/i&gt;an independent game developed by students of the &lt;a href="http://en.wikipedia.org/wiki/DigiPen" title="DigiPen"&gt;DigiPen Institute of Technology&lt;/a&gt;. The guys were employed by Valve to work on the project.&lt;br /&gt;So enough fooling around, I'd better graduate soon, so I can apply somewhere and create an awesome game.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-4075299121461470883?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/4075299121461470883/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2008/01/cake-is-lie.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/4075299121461470883'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/4075299121461470883'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2008/01/cake-is-lie.html' title='The Cake is a Lie!'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_XNjT4XAs15w/ScVMf7fKb9I/AAAAAAAAAPc/BwNLdBgXwt4/s72-c/Portal_Screen07.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-2091661875993838063</id><published>2007-09-19T23:45:00.000+02:00</published><updated>2007-09-20T22:36:48.717+02:00</updated><title type='text'>Microsoft Vizija 2007</title><content type='html'>I will be talking about XNA next month at the &lt;a href="http://www.microsoft.com.mk/Vizija/Default.aspx?tabindex=0&amp;amp;tabid=1"&gt;Microsoft Vizija&lt;/a&gt; conference. I hope to familiarize  people here in Skopje with the platform, create some interest and maybe even find someone enthusiastic enough to work with. If I have the time to fix some bugs in the Tunnel Vision game before the conference it would be great. Here is the &lt;a href="http://www.microsoft.com.mk/Vizija/Default.aspx?tabindex=0&amp;amp;tabid=102"&gt;timetable&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-2091661875993838063?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/2091661875993838063/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2007/09/microsoft-vizija-2007.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/2091661875993838063'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/2091661875993838063'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2007/09/microsoft-vizija-2007.html' title='Microsoft Vizija 2007'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-1510131603248473157</id><published>2007-08-17T11:00:00.003+02:00</published><updated>2009-03-21T21:28:33.888+01:00</updated><title type='text'>Home Again</title><content type='html'>Well, vacation is over. I had some really nice time.&lt;br /&gt;Did some traveling&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_XNjT4XAs15w/RsVlCMvu1EI/AAAAAAAAADU/cT0BinkX1so/s1600-h/backpack.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_XNjT4XAs15w/RsVlCMvu1EI/AAAAAAAAADU/cT0BinkX1so/s400/backpack.jpg" alt="" id="BLOGGER_PHOTO_ID_5099593241522525250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Went high&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_XNjT4XAs15w/ScVMOH9p6kI/AAAAAAAAAPU/069wVo-1rOc/s1600-h/high.jpg"&gt;&lt;img style="cursor: pointer; width: 179px; height: 400px;" src="http://1.bp.blogspot.com/_XNjT4XAs15w/ScVMOH9p6kI/AAAAAAAAAPU/069wVo-1rOc/s400/high.jpg" alt="" id="BLOGGER_PHOTO_ID_5315738740720265794" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Went deep&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_XNjT4XAs15w/RsVlCMvu1FI/AAAAAAAAADc/95XeL9yGMxs/s1600-h/deep.jpg"&gt;&lt;img style="cursor: pointer; width: 252px; height: 375px;" src="http://bp1.blogger.com/_XNjT4XAs15w/RsVlCMvu1FI/AAAAAAAAADc/95XeL9yGMxs/s400/deep.jpg" alt="" id="BLOGGER_PHOTO_ID_5099593241522525266" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ate (and cooked) some fantastic food&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_XNjT4XAs15w/RsVxFcvu1GI/AAAAAAAAADk/e6bWCXQ6h5M/s1600-h/food.jpg"&gt;&lt;img style="cursor: pointer; width: 255px; height: 170px;" src="http://bp2.blogger.com/_XNjT4XAs15w/RsVxFcvu1GI/AAAAAAAAADk/e6bWCXQ6h5M/s400/food.jpg" alt="" id="BLOGGER_PHOTO_ID_5099606491496633442" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And now its time to go back to everyday life.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-1510131603248473157?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/1510131603248473157/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2007/08/back-home.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1510131603248473157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/1510131603248473157'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2007/08/back-home.html' title='Home Again'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_XNjT4XAs15w/RsVlCMvu1EI/AAAAAAAAADU/cT0BinkX1so/s72-c/backpack.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-9198439836388278287</id><published>2007-07-08T18:49:00.000+02:00</published><updated>2007-09-17T12:44:57.547+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.net'/><category scheme='http://www.blogger.com/atom/ns#' term='xna'/><category scheme='http://www.blogger.com/atom/ns#' term='game'/><title type='text'>Tunnel Vision</title><content type='html'>After weeks of hard work it is finally done. Tunnel Vision has reached a playable version that you can grab &lt;a href="http://cid-5ffdbec9f294a379.skydrive.live.com/self.aspx/Public/TunnelVision.zip"&gt;here&lt;/a&gt;. Here are some screenshots too.&lt;br /&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="text-align: center;" class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_XNjT4XAs15w/RpO9F731KlI/AAAAAAAAAC0/fYalFl5sJwg/s1600-h/screen007.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_XNjT4XAs15w/RpO9F731KlI/AAAAAAAAAC0/fYalFl5sJwg/s400/screen007.jpg" alt="" id="BLOGGER_PHOTO_ID_5085616313900280402" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="text-align: center;" class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_XNjT4XAs15w/RpO9Z731KmI/AAAAAAAAAC8/8SSEHWcqZOY/s1600-h/screen011.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_XNjT4XAs15w/RpO9Z731KmI/AAAAAAAAAC8/8SSEHWcqZOY/s400/screen011.jpg" alt="" id="BLOGGER_PHOTO_ID_5085616657497664098" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="text-align: center;" class="MsoNormal"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_XNjT4XAs15w/RpO9s731KnI/AAAAAAAAADE/6169I5vwKYg/s1600-h/screen017.jpg"&gt;&lt;img style="cursor: pointer;" src="http://bp1.blogger.com/_XNjT4XAs15w/RpO9s731KnI/AAAAAAAAADE/6169I5vwKYg/s400/screen017.jpg" alt="" id="BLOGGER_PHOTO_ID_5085616983915178610" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p class="MsoNormal"&gt; The game features nice graphics, fast gameplay and a great soundtrack. The aim is to simply pass the track in the shortest time possible.&lt;br /&gt;The vehicle control is inspired by the Xbox 360 controller, and therefore is best played with it. The game can also be played with mouse or/and keyboard.&lt;br /&gt;The game is incredibly easily expandable. Tracks and vessels are stored as XML, and can be added within minutes, so if anyone that feels like joining in drop an email.&lt;/p&gt;&lt;p class="MsoNormal"&gt;&lt;br /&gt;&lt;/p&gt;  &lt;p class="MsoNormal"&gt;System requirements:&lt;/p&gt;              &lt;p class="MsoNormal"&gt;Windows XP SP2&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=a7da4763-6807-4bd5-8d18-18c60c437f93&amp;amp;displaylang=en"&gt;&lt;/a&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=0856EACB-4362-4B0D-8EDD-AAB15C5E04F5&amp;amp;displaylang=en"&gt;.NET 2.0&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=0A9B6820-BFBB-4799-9908-D418CDEAC197&amp;amp;displaylang=en"&gt;DirectX 9.0c&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=A7DA4763-6807-4BD5-8D18-18C60C437F93&amp;amp;displaylang=en"&gt;XNA Runtime&lt;/a&gt;&lt;br /&gt;Approx 50MB Hard disk space&lt;br /&gt;Video card supporting Shader Model 2.0&lt;br /&gt;&lt;span style=""&gt;&lt;/span&gt;Standard audio card &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-9198439836388278287?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/9198439836388278287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2007/07/after-weeks-of-hard-work-it-is-finally.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/9198439836388278287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/9198439836388278287'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2007/07/after-weeks-of-hard-work-it-is-finally.html' title='Tunnel Vision'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_XNjT4XAs15w/RpO9F731KlI/AAAAAAAAAC0/fYalFl5sJwg/s72-c/screen007.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1395042463187467672.post-3225734050635470289</id><published>2007-07-04T09:23:00.000+02:00</published><updated>2007-07-04T09:25:05.106+02:00</updated><title type='text'>About This Blog</title><content type='html'>&lt;p class="MsoNormal"&gt;I made Furious Pixels as a blog for posting about my projects, some technology info and general geek stuff. Most of my projects will probably be in computer graphics. &lt;/p&gt;  &lt;p class="MsoNormal"&gt;My current project is a game called Tunnel Vision. An update on its progress will soon follow.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1395042463187467672-3225734050635470289?l=furiouspixels.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://furiouspixels.blogspot.com/feeds/3225734050635470289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://furiouspixels.blogspot.com/2007/07/about-this-blog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/3225734050635470289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1395042463187467672/posts/default/3225734050635470289'/><link rel='alternate' type='text/html' href='http://furiouspixels.blogspot.com/2007/07/about-this-blog.html' title='About This Blog'/><author><name>enci</name><uri>http://www.blogger.com/profile/13434591769476122979</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_XNjT4XAs15w/SbzOGgwVvaI/AAAAAAAAANg/dTWZ7EM1Sqo/S220/flickr_faca.jpg'/></author><thr:total>0</thr:total></entry></feed>
