XNA Tutorials, Samples and Thoughts
- 2D 2009 2010 Amused Sloth AmusedSloth Animation Announcement Chickens Can't Fly Chickens Can Dream code Community Games DBP Deferred Rendering details Finally! Gamasutra license MVP News postprocessing Rebellion Rise Roy Sample Shadows summary Summit Trailer tutorial Windows Phone Windows Phone 7 WP7 XBLIG XNA XNA 4.0
- September 2011 (1)
- June 2011 (2)
- March 2011 (1)
- February 2011 (1)
- January 2011 (2)
- December 2010 (2)
- July 2010 (1)
- May 2010 (1)
- April 2010 (1)
- November 2009 (1)
- October 2009 (2)
- September 2009 (2)
- August 2009 (1)
- July 2009 (1)
- June 2009 (4)
- April 2009 (3)
- March 2009 (2)
- February 2009 (2)
- January 2009 (5)
- December 2008 (1)
- November 2008 (2)
- October 2008 (4)
- September 2008 (5)
- August 2008 (1)
- July 2008 (7)
- June 2008 (1)
- May 2008 (4)
- April 2008 (3)
- March 2008 (3)
- February 2008 (4)
- January 2008 (2)
- Small pre-pre-beta shadow mapping lirary (36)
- Working on shadows… (34)
- My technique for the shader-based dynamic 2D shadows (29)
- April Sample Online! (20)
- 2D Skeletal Animations (20)
- School Projects with XNA (17)
- Mass Effect Dialogue Sample (17)
- Welcome! (14)
- My experience with Toon Boom Studio (12)
- Adding softness to shadows (12)
AddictiveColors: Awesome idea, this screen space solution looks to be quite neat for games with many shadow casting...
meizitang: These healthy weight loss tips that will make it easier to take those first steps towards pursuing...
Adding the Effect files | Project Vanquish: [...] are unfamiliar with HLSL, Microsoft wrote a brilliant guide about programming in HLSL. And,...
Welcome to Project Vanquish! | Project Vanquish: [...] searching in the past regarding XNA and Deferred Rendering. The example that crops up the ...
De leukste filmpjes gratis plaatsen en bekijken.: De leukste filmpjes gratis plaatsen en bekijken.... [...]2D Skeletal Animations[...]...
Tim Stern: Hi Catalin, I discovered a possible mistake in your file Transformation.cs, function public...
louis vuitton: I'm glad I located your post. I would never have created sense of this subject on my own. I're...
consultoria de sistemas: consultoria de sistemas... [...]2D Skeletal Animations[...]...

about 3 years ago
YO! Nice sample! I have some problems with adding soft shadows and unable to rotate convex hull. would u be so kind as to help me?
about 3 years ago
How to add the Height property to the convex hull class?
about 3 years ago
I haven’t yet tried doing soft shadows, so I can’t help you there. As for rotating the objects…. you could probably transform each vertex manually.
about 3 years ago
Yeap. 10x i will try
about 2 years ago
Excellent sample.
Can this code be used in a commercial project?
about 2 years ago
@greg: It’s fine by me to use it however you want.
about 2 years ago
Just what I was looking for. Great stuff.
Thanks, and keep up the good work!
about 2 years ago
Hey Catalina, have a question for you if you have the time for a discussion. I downloaded and started up your sample and added a frame counter to it. With one added light to the player( just a different texture to simulate a cone light ) and the original 37 objects the framerate was running at 24 fps average. After profiling I discovered the called operations( and looking at the algorithm ) I discovered that the shadow generation algorithm was being called on each object for every light. This made sense to me as a sample so don’t think I’m knocking it in any way.
So, I fixed that with a quick and dirty SAT test against a bounding box for the hull, and the bounding circle for the light. If it passes the test, then I do the light calculations. This brough the number of shadows being cast from 259 to 61 at the starting position. Additionally I wanted to speed up the shadow generation algorithm so I moved the edge creation code into the constructor. (I also added convex hull rotation and movement into it, but that is seperate)
However, this only increased the frame rate from 22-24 up to 30-34. I know, around a 30 percent increase… but not good enough for a really robust system. It was apparent additional profiling was needed. That yielded the fact that calls were down to the shadow generation algorithm… but over 75% of the draw function was spent in draw lightmaps, and 52% of that was spent in the draw lightmaps function itself and not its callees.
It seems the culprit might be the renderstate changes in between each light. There isn’t much more I can do to opt out of shadow generation, so my optomizations have to focus on the creation of the lightmap now.
Here is where I was hoping you had an insight or a resource I have missed. Do you know of another technique for drawing the shadow areas besides using the alpha channel?
about 2 years ago
Yeah, those two are the bottlenecks at the moment. I tried to think of many ways to do the shadow generation in a vertex shader, but unfortunately didn’t find a solution.
One possible solution could be replacing the usage of the alpha channel for lightmaps with the usage of the stencil buffer. This might cut down on the number of renderstates that need to be set for each light, and maybe it is faster. The idea is mainly the same. Draw the shadows and while doing that, the affected pixels are marked in the stencil buffer. And then, when drawing the light, a test is made and only unmarked pixels are written.
about 2 years ago
Actually, a guy named Michael Anderson figured that one out and put it on his MSDN blog. Manders vs. Machine…
http://blogs.msdn.com/manders/archive/2007/03/14/shadows-in-2d.aspx
He even has the source for you to browse. I was thinking of using his shader program to speed up the shadow generation but that still leaves me with the main problem of render state switches.
I’ll have a look into the stencil test method. Only thing I’m having a hard time warpping my head around is how a stencil test will handle overlapping shadows. Reason the current system works is because we clear the alpha map for each light… And I’m not currently sure how to clear the stencil buffer. If I can get it to work though I think it would eliminate the renderstate changes. I could render the shadows to a seperate render target just to fill in the stencil buffer. Then use that to render the lights.
Do you think this discussion should be conducted in the Creator’s club forum?
about 2 years ago
to clear the stencil buffer: GraphicsDevice.Clear(ClearOptions.Stencil, Color.Black, 0, 0);
By moving it to Creator’s Club Forums, it’s possible you’ll have other people look at the problem and come up with more ideas.
about 2 years ago
How could i implement a scrolling background with this?
I tried messing around with the viewMatrix, but i have no idea how it’s supposed to work.
Currently my spritebatch uses Matrix.CreateTranslation(new Vector3(-Position, 0f)) that formula to have a moving background, but i have no idea how i would apply it to the shadows too.
about 2 years ago
Rautapalli:
i have a camera that i apply to spritebatch so that i can use world coordinates for all my objects and just move the camera for movement.
(i use World1.cam.get_transformation(GraphicsDevice)); in my spriteBatch.Begin())
//I get all my hull objects from this call
World1.GatherShadows();
DrawLightmap();
graphics.GraphicsDevice.Clear(Color.White);
// TODO: This is where i do my map drawing spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState, World1.cam.get_transformation(GraphicsDevice)); /*Send the variable that has your graphic device here*/
spriteBatch.End();
//Now draw all shadows
spriteBatch.Begin(SpriteBlendMode.None, SpriteSortMode.Immediate, SaveStateMode.SaveState, World1.cam.get_transformation(GraphicsDevice)); /*Send the variable that has your graphic device here*/
//World1.Worldobjects are all my stored hull objects
foreach (ConvexHull hull in World1.Worldobjects)
{
hull.Draw(gameTime, World1.cam.get_transformation(GraphicsDevice));
}
spriteBatch.End();
//Now draw the actual light
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState); /*Send the variable that has your graphic device here*/
GraphicsDevice.RenderState.SourceBlend = Blend.Zero;
GraphicsDevice.RenderState.DestinationBlend = Blend.SourceColor;
GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;
spriteBatch.Draw(lightMap.GetTexture(), Vector2.Zero + new Vector2(400,300), null, Color.White, 0.0f, new Vector2(400.0f, 300.0f), 1.0f, 0, 0);
spriteBatch.End();
base.Draw(gameTime);
//———————————————————
Now notice the changes in the class. I made no changes to the light class because it takes spritebatch in its draw and if you noticed above i already used the World1.cam.get_transformation(GraphicsDevice) in the spriteBatch.Begin(….
however in the ConvexHull.cs
concentrate on 2 subs
//Draw
public void Draw(GameTime gameTime, Matrix TransformWorld)
{
GraphicsDevice device = game.GraphicsDevice;
device.RenderState.CullMode = CullMode.None;
device.RenderState.AlphaBlendEnable = false;
device.VertexDeclaration = vertexDecl;
drawingEffect.World = Matrix.CreateTranslation(position.X, position.Y, 0) * TransformWorld;
drawingEffect.Begin();
foreach (EffectPass pass in drawingEffect.CurrentTechnique.Passes)
{
pass.Begin();
device.DrawUserIndexedPrimitives(PrimitiveType.TriangleFan, vertices, 0, vertices.Length, indices, 0, vertexCount);
pass.End();
}
drawingEffect.End();
}
//DrawShadow
public void DrawShadows(LightSource lightSource, Matrix TransformWorld)
{
//compute facing of each edge, using N*L
for (int i = 0; i 0)
backFacing[i] = false;
else
backFacing[i] = true;
}
//find beginning and ending vertices which
//belong to the shadow
int startingIndex = 0;
int endingIndex = 0;
for (int i = 0; i startingIndex)
shadowVertexCount = endingIndex – startingIndex + 1;
else
shadowVertexCount = vertexCount + 1 – startingIndex + endingIndex;
shadowVertices = new VertexPositionColor[shadowVertexCount * 2];
//create a triangle strip that has the shape of the shadow
int currentIndex = startingIndex;
int svCount = 0;
while (svCount != shadowVertexCount * 2)
{
Vector3 vertexPos = vertices[currentIndex].Position + new Vector3(position, 0);
//one vertex on the hull
shadowVertices[svCount] = new VertexPositionColor();
shadowVertices[svCount].Color = Color.TransparentBlack;
shadowVertices[svCount].Position = vertexPos;
//one extruded by the light direction
shadowVertices[svCount + 1] = new VertexPositionColor();
shadowVertices[svCount + 1].Color = Color.TransparentBlack;
Vector3 L2P = vertexPos – new Vector3(lightSource.Position, 0);
L2P.Normalize();
shadowVertices[svCount + 1].Position = new Vector3(lightSource.Position, 0) + L2P * 9000;
svCount += 2;
currentIndex = (currentIndex + 1) % vertexCount;
}
Matrix NewTemp = Matrix.Identity;
//draw the shadow geometry
game.GraphicsDevice.VertexDeclaration = vertexDecl;
drawingEffect.World = TransformWorld;
drawingEffect.Begin();
drawingEffect.CurrentTechnique.Passes[0].Begin();
game.GraphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, shadowVertices, 0, shadowVertexCount * 2 – 2);
drawingEffect.CurrentTechnique.Passes[0].End();
drawingEffect.End();
}
//hope this helps.
about 2 years ago
I do have a question though. With black the shadows dont cross past their hulls. However if i set the color to anythign else shadows show on the hulls. Is there a way to prevent this.
about 2 years ago
hmm well i figured it out.
within the DrawLightmap method
I moved the
foreach (ConvexHull hull in World1.Worldobjects)
{
hull.Draw(gT, World1.cam.get_transformation(GraphicsDevice));
}
right after the
foreach (ConvexHull ch in World1.Worldobjects)
{
//draw shadow
if (ch != null)
{
ch.DrawShadows(light, World1.cam.get_transformation(GraphicsDevice));
}
}
so to recap in DrawLightmap method it should look like the following:
foreach (LightSource light in lights)
{
//clear alpha to 1
ClearAlphaToOne();
//draw all shadows
//write only to the alpha channel, which sets alpha to 0
GraphicsDevice.RenderState.ColorWriteChannels = ColorWriteChannels.Alpha;
GraphicsDevice.RenderState.CullMode = CullMode.None;
GraphicsDevice.RenderState.AlphaBlendEnable = true;
GraphicsDevice.RenderState.DestinationBlend = Blend.Zero;
GraphicsDevice.RenderState.SourceBlend = Blend.One;
foreach (ConvexHull ch in World1.Worldobjects)
{
//draw shadow
if (ch != null)
{
ch.DrawShadows(light, World1.cam.get_transformation(GraphicsDevice));
}
}
foreach (ConvexHull hull in World1.Worldobjects)
{
hull.Draw(gT, World1.cam.get_transformation(GraphicsDevice));
}
GraphicsDevice.RenderState.ColorWriteChannels = ColorWriteChannels.All;
//draw the light shape
//where Alpha is 0, nothing will be written
//This is the light
spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState, World1.cam.get_transformation(GraphicsDevice));
GraphicsDevice.RenderState.DestinationBlend = Blend.One;
GraphicsDevice.RenderState.SourceBlend = Blend.DestinationAlpha;
GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;
GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = true;
light.Draw(spriteBatch);
spriteBatch.End();
}
Now this will have the hulls lit up (fully) when light touches it
If you would prefer them without light then make sure your color value is passed with an alpha of 0.
this is my line to create the object (hull)
objects = new ConvexHull(game2, Points, new Color(0,0,0,0), new Vector2(X, Y));
Well this seems to have worked for me anyway.
about 1 year ago
Hi Catalin, I’m stuck with something and I though maybe you can help me out (please). I’m using your dynamic 2D shadows code (can I mention you in the credits in the game by the way?), and everything’s working fine. I’ve made some optimizations and it’s looking quite good.
But now I’m trying to add some static shadows to my game, and for that I’m trying to calculate all the static shadows during the level loading period, and then just draw a texture with the static lights and shadows. The problem is that I’m not very good at graphics programming, and although I’m storing all the precalculated shadows in a big texture (with RenderTarget2D.GetTexture()) my problem is when my camera scrolls. RenderTarget2D gives me a texture with the viewport’s size, so when I move around and the camera moves, the rectangle containing the shadows stays in place :S What I need (I guess) is a bigger RenderTarget2D, with the size of the whole level, but I don’t know how to do this (gives me error when I try this. Any ideas?
With dynamic shadows I have no problem, as it calculates on each frame the lights and shadows position related to the camera position.
Thanks, sorry for the huge question.
about 1 year ago
Sorry, me again
What I want to do is only draw the cached “cutted” static lights (by cutted, I mean, the light source and removing the parts that are shadowed), as the shadows are already in the dynamic shadows’ RenderTarget2D.
about 1 year ago
I’m trying to get this to work with a camera and all is well except that the shadows will only draw correctly if the convex hull position is at (0,0). Any suggestions? Thanks.
about 1 year ago
Is anyone interested in a GPU based shadowing method?
about 1 year ago
Hi Catalin,
Awesome sample and thanks for sharing. I’m going to take a look at it and try to incorperate it into one of my mini 2d projects.
-John
about 1 year ago
Wow, thats real awsome! You also can use this for tile Based games (32×32 tiles, 800×600), and it’s still very fast!
Thank you very much!
FlySoft
about 1 year ago
Hey!! This sample is very nice!!!
I still trying to understand it! but I am a beginner in XNA!
Unfortunately I am trying to port it to the 4.0 version, withou success… Any tips???
Thank you!
about 11 months ago
Hello!
I’ve created an extremely fast (full hd ready, 100+ lights) vertex-based 2D lighting engine, optimised for both PC and the Xbox 360, running on the XNA 4.0 framework. If anyone is interested in a ready-to-use, opensource 2D engine, rather than implementing your own solution, you can check out http://Krypton.codeplex.com/
Props to OrangyTang and Catalin!