Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Microsoft XNA 4.0 Game Development Cookbook

You're reading from   Microsoft XNA 4.0 Game Development Cookbook This book goes further than the basic manuals to help you exploit Microsoft XNA to create fantastic virtual worlds and effects in your 2D or 3D games. Includes 35 essential recipes for game developers.

Arrow left icon
Product type Paperback
Published in Jun 2012
Publisher Packt
ISBN-13 9781849691987
Length 356 pages
Edition 1st Edition
Languages
Arrow right icon
Author (1):
Arrow left icon
Luke Drumm Luke Drumm
Author Profile Icon Luke Drumm
Luke Drumm
Arrow right icon
View More author details
Toc

Table of Contents (15) Chapters Close

Microsoft XNA 4.0 Game Development Cookbook
Credits
About the Author
About the Reviewers
www.PacktPub.com
1. Preface
1. Applying Special Effects FREE CHAPTER 2. Building 2D and 3D Terrain 3. Procedural Modeling 4. Creating Water and Sky 5. Non-Player Characters 6. Playing with Animation 7. Creating Vehicles 8. Receiving Player Input 9. Networking

Implementing lens flare within the HiDef profile


Modern GPUs are very good at determining whether one set of polygons is obscured by another set. We can use this to our advantage when creating lens flares within a HiDef profile.

Getting ready

This recipe assumes that you've already got a scene, rendering correctly, albeit without a lens flare.

How to do it...

To create a lens flare within the HiDef profile:

  1. 1. Create a new class to hold the lens flare behavior:

    class HiDefLensFlare
    {
    
  2. 2. Add some instance-level variables to hold the details of the occlusion test, the lighting, and the glow image:

    SpriteBatch spriteBatch;
    GraphicsDevice graphicsDevice;
    public BasicEffect ShadowCaptureEffect;
    OcclusionQuery occlusionQuery;
    bool occlusionQueryActive;
    float occlusionAlpha;
    const float querySize = 50;
    VertexPositionColor[] queryVertices;
    public Vector3 LightDirection = Vector3.Normalize(new Vector3(0.5f, -0.1f, 0.5f));
    Vector2 lightPosition;
    bool lightBehindCamera;
    Texture2D glow;
    Vector2 glowOrigin;
    float glowScale = 400f;
    
  3. 3. Next, add a constructor to set up the occlusion test prerequisites and load the glow texture:

    public HiDefLensFlare(GraphicsDevice graphicsDevice, ContentManager content)
    {
    this.graphicsDevice = graphicsDevice;
    spriteBatch = new SpriteBatch(graphicsDevice);
    ShadowCaptureEffect = new BasicEffect(graphicsDevice)
    {
    View = Matrix.Identity,
    VertexColorEnabled = true
    };
    occlusionQuery = new OcclusionQuery(graphicsDevice);
    queryVertices = new VertexPositionColor[4];
    queryVertices[0].Position = new Vector3(-querySize / 2, -querySize / 2, -1);
    queryVertices[1].Position = new Vector3(querySize / 2, -querySize / 2, -1);
    queryVertices[2].Position = new Vector3(-querySize / 2, querySize / 2, -1);
    queryVertices[3].Position = new Vector3(querySize / 2, querySize / 2, -1);
    glow = content.Load<Texture2D>(@"lensflare/glow");
    glowOrigin = new Vector2(glow.Width, glow.Height) / 2;
    }
    
  4. 4. Create a new BlendState instance-level variable so the ocular test can proceed without changing the visible image:

    static readonly BlendState ColorWriteDisable = new BlendState
    {
    ColorWriteChannels = ColorWriteChannels.None
    };
    
  5. 5. Add a new method to perform the ocular test:

    public void Measure(Matrix view, Matrix projection)
    {
    
  6. 6. Calculate the position of the lens flare on screen, and exit early if it's behind the player's viewpoint:

    var infiniteView = view;
    infiniteView.Translation = Vector3.Zero;
    var viewport = graphicsDevice.Viewport;
    var projectedPosition = viewport.Project(
    -LightDirection, projection,
    infiniteView, Matrix.Identity);
    if ((projectedPosition.Z < 0) ||
    (projectedPosition.Z > 1))
    {
    lightBehindCamera = true;
    return;
    }
    lightPosition = new Vector2(projectedPosition.X, projectedPosition.Y);
    lightBehindCamera = false;
    
  7. 7. Add the calculation for how much of the lens flare test area is occluded by the scene once the previous occlusion test has completed:

    if (occlusionQueryActive)
    {
    if (!occlusionQuery.IsComplete)
    {
    return;
    }
    const float queryArea = querySize * querySize;
    occlusionAlpha = Math.Min(
    occlusionQuery.PixelCount / queryArea, 1);
    }
    
  8. 8. Set up for the next occlusion query:

    graphicsDevice.BlendState = ColorWriteDisable;
    graphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
    ShadowCaptureEffect.World = Matrix.CreateTranslation(
    lightPosition.X,
    lightPosition.Y, 0);
    ShadowCaptureEffect.Projection = Matrix.CreateOrthographicOffCenter(0,
    viewport.Width,
    viewport.Height,
    0, 0, 1);
    ShadowCaptureEffect.CurrentTechnique.Passes[0].Apply();
    
  9. 9. Render the lens flare test vertices inside the occlusion test to determine how many pixels were rendered:

    occlusionQuery.Begin();
    graphicsDevice.DrawUserPrimitives(PrimitiveType.TriangleStrip, queryVertices, 0, 2);
    occlusionQuery.End();
    occlusionQueryActive = true;
    
  10. 10. Complete the class by adding a Draw() method to render the glow:

    public void Draw()
    {
    if (lightBehindCamera || occlusionAlpha <= 0)
    return;
    Color color = Color.White * occlusionAlpha;
    Vector2 origin = new Vector2(glow.Width, glow.Height) / 2;
    float scale = glowScale * 2 / glow.Width;
    spriteBatch.Begin();
    spriteBatch.Draw(glow, lightPosition, null, color, 0,
    origin, scale, SpriteEffects.None, 0);
    spriteBatch.End();
    }
    

How it works...

XNA and the underlying DirectX infrastructure contain a rather handy little diagnostic tool in the form of the occlusion test. With this test, you can count how many pixels were filled when trying to render a particular portion of a scene.

We utilize this in the lens flare example by attempting to render a small rectangle across the opposite side of the scene from the player's viewpoint, and measuring how much of it is obscured by the scene's meshes. With this number, we adjust the opacity of the lens flare's glow texture up or down to simulate the sun disappearing either partially or completely behind an object.

You have been reading a chapter from
Microsoft XNA 4.0 Game Development Cookbook
Published in: Jun 2012
Publisher: Packt
ISBN-13: 9781849691987
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image