XNA for C#
DirectX 9 for C#
DirectX 9 for C++
DirectX 9 for VB
Forum
   
My XNA Book
      
       Go to section on this site

Additional info


Latest Forum posts

 Account settings
  Posted by: Anonymous
  When: 07/05/2014 at 09:48:39

 forced subtitle
  Posted by: Applefly
  When: 07/05/2014 at 06:00:48

 convert DVD into PMS
  Posted by: Applefly
  When: 07/05/2014 at 05:55:25

 DVD to Digital Copy easily
  Posted by: VIKIVannessa
  When: 05/05/2014 at 06:52:29

 DVD on Xbox 360/Xbox One Console
  Posted by: VIKIVannessa
  When: 05/05/2014 at 06:51:47

 Extract .Srt Subtitles
  Posted by: Applefly
  When: 04/05/2014 at 03:54:38

 Encode Movie collection
  Posted by: Applefly
  When: 04/05/2014 at 03:52:41

 Convert DVD to WMV
  Posted by: Applefly
  When: 29/04/2014 at 05:53:50

 rip DVDs into digital files
  Posted by: Applefly
  When: 29/04/2014 at 05:51:20

 iTunes movies/music to Kindle Fire
  Posted by: ciciyu80
  When: 29/04/2014 at 05:10:20


Ads

Changing the shape of our light

OK, we’ve got a square light, casting shadows on our scene. How can we make it look more like a real light? A real light shines a round beam of light, so let’s start with that. To determine the pixels that are part of the round beam, we could add some mathematical checks (see Recipe 6-8). That would be OK for a normal light, but for the headlights of a car? This should have 2 beams, so more maths..

In my opinion, a much easier method is to throw in another texture that can be used by our pixel shader:




By looking at the image above I think you get the idea: only the white part will be lit. You can download it by right-clicking on it or by clicking here. We can already add the texture sampler to our HLSL code:
Texture xCarLightTexture;

sampler CarLightSampler = sampler_state { texture = <xCarLightTexture> ; magfilter = LINEAR; minfilter=LINEAR; mipfilter = LINEAR; AddressU = clamp; AddressV = clamp;};
Now we can simply sample the color value of this image, which gives us a value between 0 and 1. We simply need to multiply our final color by this value, so this is the core of our pixel shader:

diffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3D, PSIn.Normal);
diffuseLightingFactor = saturate(diffuseLightingFactor);
diffuseLightingFactor *= xLightPower;            
            
float lightTextureFactor = tex2D(CarLightSampler, ProjectedTexCoords).r;
diffuseLightingFactor *= lightTextureFactor;

That’s it for the HLSL code! In our XNA code, we’re going to load the texture file, so import it into your project and add this variable to our code:

 Texture2D carLight;

And this line to our LoadContent method:


carLight = Content.Load<Texture2D> ("carlight");
Now we still need to pass the texture to our effect file. In our DrawScene method, add this line to the list of XNA-to-HLSL parameters we’re passing to the graphics device:

 effect.Parameters["xCarLightTexture"].SetValue(carLight);

And this line in the DrawModel method:

 currentEffect.Parameters["xCarLightTexture"].SetValue(carLight);

Et voila! That’s all there is to it. You should see the image below:




DirectX Tutorial 16 - Shaping the light

If you appreciate the amount of time I spend creating and updating
these pages, feel free to donate -- any amount is welcome !



Click here to go to the forum on this chapter!

Or click on one of the topics on this chapter to go there:
  • Custom Effect issue
          Hi Riemers, Thank you for this tutorial. This sit...
  • Shadow - models with no texture
          How to modify the code to use models with no textu...
  • how to move car in
          hello how to move the car in differen...
  • Blank Screen
          When i add this section the whole image goes black...


    You can also use shaping images with other values than completely white/black. Grey pixels will be lit with less light than white pixels!

    The HLSL code:

    float4x4 xWorldViewProjection;
    float4x4 xLightsWorldViewProjection;
    float4x4 xWorld;
    float3 xLightPos;
    float xLightPower;
    float xAmbient;

    Texture xTexture;

    sampler TextureSampler = sampler_state { texture = <xTexture> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = mirror; AddressV = mirror;};Texture xShadowMap;

    sampler ShadowMapSampler = sampler_state { texture = <xShadowMap> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = clamp; AddressV = clamp;};
     Texture xCarLightTexture;

    sampler CarLightSampler = sampler_state { texture = <xCarLightTexture> ; magfilter = LINEAR; minfilter=LINEAR; mipfilter = LINEAR; AddressU = clamp; AddressV = clamp;};


    struct VertexToPixel
    {
        float4 Position     : POSITION;    
        float2 TexCoords    : TEXCOORD0;
        float3 Normal        : TEXCOORD1;
        float3 Position3D    : TEXCOORD2;
    };

    struct PixelToFrame
    {
        float4 Color        : COLOR0;
    };

    float DotProduct(float3 lightPos, float3 pos3D, float3 normal)
    {
        float3 lightDir = normalize(pos3D - lightPos);
        return dot(-lightDir, normal);    
    }

    VertexToPixel SimplestVertexShader( float4 inPos : POSITION0, float3 inNormal: NORMAL0, float2 inTexCoords : TEXCOORD0)
    {
        VertexToPixel Output = (VertexToPixel)0;
        
        Output.Position =mul(inPos, xWorldViewProjection);
        Output.TexCoords = inTexCoords;
        Output.Normal = normalize(mul(inNormal, (float3x3)xWorld));    
        Output.Position3D = mul(inPos, xWorld);

        return Output;
    }

    PixelToFrame OurFirstPixelShader(VertexToPixel PSIn)
    {
        PixelToFrame Output = (PixelToFrame)0;    

        float diffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3D, PSIn.Normal);
        diffuseLightingFactor = saturate(diffuseLightingFactor);
        diffuseLightingFactor *= xLightPower;

        PSIn.TexCoords.y--;
        float4 baseColor = tex2D(TextureSampler, PSIn.TexCoords);
        Output.Color = baseColor*(diffuseLightingFactor + xAmbient);

        return Output;
    }

    technique Simplest
    {
        pass Pass0
        {
            VertexShader = compile vs_2_0 SimplestVertexShader();
            PixelShader = compile ps_2_0 OurFirstPixelShader();
        }
    }

    struct SMapVertexToPixel
    {
        float4 Position     : POSITION;
        float4 Position2D    : TEXCOORD0;
    };

    struct SMapPixelToFrame
    {
        float4 Color : COLOR0;
    };


    SMapVertexToPixel ShadowMapVertexShader( float4 inPos : POSITION)
    {
        SMapVertexToPixel Output = (SMapVertexToPixel)0;

        Output.Position = mul(inPos, xLightsWorldViewProjection);
        Output.Position2D = Output.Position;

        return Output;
    }

    SMapPixelToFrame ShadowMapPixelShader(SMapVertexToPixel PSIn)
    {
        SMapPixelToFrame Output = (SMapPixelToFrame)0;            

        Output.Color = PSIn.Position2D.z/PSIn.Position2D.w;

        return Output;
    }


    technique ShadowMap
    {
        pass Pass0
        {
            VertexShader = compile vs_2_0 ShadowMapVertexShader();
            PixelShader = compile ps_2_0 ShadowMapPixelShader();
        }
    }


    struct SSceneVertexToPixel
    {
        float4 Position             : POSITION;
        float4 Pos2DAsSeenByLight    : TEXCOORD0;
        float2 TexCoords            : TEXCOORD1;
        float3 Normal                : TEXCOORD2;
        float4 Position3D            : TEXCOORD3;
    };

    struct SScenePixelToFrame
    {
        float4 Color : COLOR0;
    };

    SSceneVertexToPixel ShadowedSceneVertexShader( float4 inPos : POSITION, float2 inTexCoords : TEXCOORD0, float3 inNormal : NORMAL)
    {
        SSceneVertexToPixel Output = (SSceneVertexToPixel)0;

        Output.Position = mul(inPos, xWorldViewProjection);    
        Output.Pos2DAsSeenByLight = mul(inPos, xLightsWorldViewProjection);    
        Output.Normal = normalize(mul(inNormal, (float3x3)xWorld));    
        Output.Position3D = mul(inPos, xWorld);
        Output.TexCoords = inTexCoords;    

        return Output;
    }

    SScenePixelToFrame ShadowedScenePixelShader(SSceneVertexToPixel PSIn)
    {
        SScenePixelToFrame Output = (SScenePixelToFrame)0;    

        float2 ProjectedTexCoords;
        ProjectedTexCoords[0] = PSIn.Pos2DAsSeenByLight.x/PSIn.Pos2DAsSeenByLight.w/2.0f +0.5f;
        ProjectedTexCoords[1] = -PSIn.Pos2DAsSeenByLight.y/PSIn.Pos2DAsSeenByLight.w/2.0f +0.5f;
        
        float diffuseLightingFactor = 0;
        if ((saturate(ProjectedTexCoords).x == ProjectedTexCoords.x) && (saturate(ProjectedTexCoords).y == ProjectedTexCoords.y))
        {
            float depthStoredInShadowMap = tex2D(ShadowMapSampler, ProjectedTexCoords).r;
            float realDistance = PSIn.Pos2DAsSeenByLight.z/PSIn.Pos2DAsSeenByLight.w;
            if ((realDistance - 1.0f/100.0f) <= depthStoredInShadowMap)
            {
                diffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3D, PSIn.Normal);
                diffuseLightingFactor = saturate(diffuseLightingFactor);
                diffuseLightingFactor *= xLightPower;            
        

                     float lightTextureFactor = tex2D(CarLightSampler, ProjectedTexCoords).r;
                 diffuseLightingFactor *= lightTextureFactor;

            }
        }
            
        float4 baseColor = tex2D(TextureSampler, PSIn.TexCoords);                
        Output.Color = baseColor*(diffuseLightingFactor + xAmbient);

        return Output;
    }

    technique ShadowedScene
    {
        pass Pass0
        {
            VertexShader = compile vs_2_0 ShadowedSceneVertexShader();
            PixelShader = compile ps_2_0 ShadowedScenePixelShader();
        }
    }


    And the XNA code:

     using System;
     using System.Collections.Generic;
     using Microsoft.Xna.Framework;
     using Microsoft.Xna.Framework.Audio;
     using Microsoft.Xna.Framework.Content;
     using Microsoft.Xna.Framework.GamerServices;
     using Microsoft.Xna.Framework.Graphics;
     using Microsoft.Xna.Framework.Input;
     using Microsoft.Xna.Framework.Net;
     using Microsoft.Xna.Framework.Storage;
     
     namespace XNAseries3
     {
         public struct MyOwnVertexFormat
         {
             public Vector3 position;
             private Vector2 texCoord;
             private Vector3 normal;
     
             public MyOwnVertexFormat(Vector3 position, Vector2 texCoord, Vector3 normal)
             {
                 this.position = position;
                 this.texCoord = texCoord;
                 this.normal = normal;
             }
     
             public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
                  (
                      new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
                      new VertexElement(sizeof(float) * 3, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
                      new VertexElement(sizeof(float) * (3+2), VertexElementFormat.Vector3, VertexElementUsage.Normal, 0)
                  );
         }
     
         public class Game1 : Microsoft.Xna.Framework.Game
         {
             GraphicsDeviceManager graphics;
             GraphicsDevice device;
     
             Effect effect;
             Matrix viewMatrix;
             Matrix projectionMatrix;
             VertexBuffer vertexBuffer;
             Vector3 cameraPos;
             Texture2D streetTexture;
             Model lamppostModel;
             Texture2D[] lamppostTextures;
             Model carModel;
             Texture2D[] carTextures;
             Vector3 lightPos;
             float lightPower;
             float ambientPower;
             Matrix lightsViewProjectionMatrix;
             RenderTarget2D renderTarget;
             Texture2D shadowMap;
             Texture2D carLight;
     
             public Game1()
             {
                 graphics = new GraphicsDeviceManager(this);
                 Content.RootDirectory = "Content";
             }
     
             protected override void Initialize()
             {
                 graphics.PreferredBackBufferWidth = 500;
                 graphics.PreferredBackBufferHeight = 500;
                 graphics.IsFullScreen = false;
                 graphics.ApplyChanges();
                 Window.Title = "Riemer's XNA Tutorials -- Series 3";
     
                 base.Initialize();
             }
     
             protected override void LoadContent()
             {
                 device = GraphicsDevice;
     

                effect = Content.Load<Effect> ("OurHLSLfile");            SetUpVertices();
                SetUpCamera();


                streetTexture = Content.Load<Texture2D> ("streettexture");            carModel = LoadModel("car", out carTextures);

                PresentationParameters pp = device.PresentationParameters;
                renderTarget = new RenderTarget2D(device, pp.BackBufferWidth, pp.BackBufferHeight, true, device.DisplayMode.Format, DepthFormat.Depth24);



                carLight = Content.Load<Texture2D> ("carlight");
             }
     
             private Model LoadModel(string assetName, out Texture2D[] textures)
             {

                Model newModel = Content.Load<Model> (assetName);
                textures = new Texture2D[7];
                int i = 0;
                foreach (ModelMesh mesh in newModel.Meshes)
                    foreach (BasicEffect currentEffect in mesh.Effects)
                        textures[i++] = currentEffect.Texture;

                foreach (ModelMesh mesh in newModel.Meshes)
                    foreach (ModelMeshPart meshPart in mesh.MeshParts)
                        meshPart.Effect = effect.Clone();

                return newModel;
            }

            private void SetUpVertices()
            {
                MyOwnVertexFormat[] vertices = new MyOwnVertexFormat[18];

                vertices[0] = new MyOwnVertexFormat(new Vector3(-20, 0, 10), new Vector2(-0.25f, 25.0f), new Vector3(0, 1, 0));
                vertices[1] = new MyOwnVertexFormat(new Vector3(-20, 0, -100), new Vector2(-0.25f, 0.0f), new Vector3(0, 1, 0));
                vertices[2] = new MyOwnVertexFormat(new Vector3(2, 0, 10), new Vector2(0.25f, 25.0f), new Vector3(0, 1, 0));
                vertices[3] = new MyOwnVertexFormat(new Vector3(2, 0, -100), new Vector2(0.25f, 0.0f), new Vector3(0, 1, 0));
                vertices[4] = new MyOwnVertexFormat(new Vector3(2, 0, 10), new Vector2(0.25f, 25.0f), new Vector3(-1, 0, 0));
                vertices[5] = new MyOwnVertexFormat(new Vector3(2, 0, -100), new Vector2(0.25f, 0.0f), new Vector3(-1, 0, 0));
                vertices[6] = new MyOwnVertexFormat(new Vector3(2, 1, 10), new Vector2(0.375f, 25.0f), new Vector3(-1, 0, 0));
                vertices[7] = new MyOwnVertexFormat(new Vector3(2, 1, -100), new Vector2(0.375f, 0.0f), new Vector3(-1, 0, 0));
                vertices[8] = new MyOwnVertexFormat(new Vector3(2, 1, 10), new Vector2(0.375f, 25.0f), new Vector3(0, 1, 0));
                vertices[9] = new MyOwnVertexFormat(new Vector3(2, 1, -100), new Vector2(0.375f, 0.0f), new Vector3(0, 1, 0));
                vertices[10] = new MyOwnVertexFormat(new Vector3(3, 1, 10), new Vector2(0.5f, 25.0f), new Vector3(0, 1, 0));
                vertices[11] = new MyOwnVertexFormat(new Vector3(3, 1, -100), new Vector2(0.5f, 0.0f), new Vector3(0, 1, 0));
                vertices[12] = new MyOwnVertexFormat(new Vector3(13, 1, 10), new Vector2(0.75f, 25.0f), new Vector3(0, 1, 0));
                vertices[13] = new MyOwnVertexFormat(new Vector3(13, 1, -100), new Vector2(0.75f, 0.0f), new Vector3(0, 1, 0));
                vertices[14] = new MyOwnVertexFormat(new Vector3(13, 1, 10), new Vector2(0.75f, 25.0f), new Vector3(-1, 0, 0));
                vertices[15] = new MyOwnVertexFormat(new Vector3(13, 1, -100), new Vector2(0.75f, 0.0f), new Vector3(-1, 0, 0));
                vertices[16] = new MyOwnVertexFormat(new Vector3(13, 21, 10), new Vector2(1.25f, 25.0f), new Vector3(-1, 0, 0));
                vertices[17] = new MyOwnVertexFormat(new Vector3(13, 21, -100), new Vector2(1.25f, 0.0f), new Vector3(-1, 0, 0));

                vertexBuffer = new VertexBuffer(device, MyOwnVertexFormat.VertexDeclaration, vertices.Length, BufferUsage.WriteOnly);
                vertexBuffer.SetData(vertices);
            }

            private void SetUpCamera()
            {
                cameraPos = new Vector3(-25, 13, 18);
                viewMatrix = Matrix.CreateLookAt(cameraPos, new Vector3(0, 2, -12), new Vector3(0, 1, 0));
                projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, device.Viewport.AspectRatio, 1.0f, 200.0f);
            }

            protected override void UnloadContent()
            {
            }

            protected override void Update(GameTime gameTime)
            {
                if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                    this.Exit();

                UpdateLightData();

                base.Update(gameTime);
            }

            private void UpdateLightData()
            {
                ambientPower = 0.2f;

                lightPos = new Vector3(-18, 5, -2);
                lightPower = 2f;

                Matrix lightsView = Matrix.CreateLookAt(lightPos, new Vector3(-2, 3, -10), new Vector3(0, 1, 0));
                Matrix lightsProjection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver2, 1f, 5f, 100f);

                lightsViewProjectionMatrix = lightsView * lightsProjection;
            }


            protected override void Draw(GameTime gameTime)
            {
                device.SetRenderTarget(renderTarget);            
                device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);

                DrawScene("ShadowMap");

                device.SetRenderTarget(null);
                shadowMap = (Texture2D)renderTarget;

                device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);            
                DrawScene("ShadowedScene");
                shadowMap = null;

                base.Draw(gameTime);
            }

            private void DrawScene(string technique)
            {
                effect.CurrentTechnique = effect.Techniques[technique];
                effect.Parameters["xWorldViewProjection"].SetValue(Matrix.Identity * viewMatrix * projectionMatrix);
                effect.Parameters["xTexture"].SetValue(streetTexture);
                effect.Parameters["xWorld"].SetValue(Matrix.Identity);
                effect.Parameters["xLightPos"].SetValue(lightPos);
                effect.Parameters["xLightPower"].SetValue(lightPower);
                effect.Parameters["xAmbient"].SetValue(ambientPower);
                effect.Parameters["xLightsWorldViewProjection"].SetValue(Matrix.Identity * lightsViewProjectionMatrix);
                effect.Parameters["xShadowMap"].SetValue(shadowMap);

                 effect.Parameters["xCarLightTexture"].SetValue(carLight);
     
                 foreach (EffectPass pass in effect.CurrentTechnique.Passes)
                 {
                     pass.Apply();
     
                     device.SetVertexBuffer(vertexBuffer);
                     device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 16);
                 }
     
                 Matrix car1Matrix = Matrix.CreateScale(4f) * Matrix.CreateRotationY(MathHelper.Pi) * Matrix.CreateTranslation(-3, 0, -15);
                 DrawModel(carModel, carTextures, car1Matrix, technique);
     
                 Matrix car2Matrix = Matrix.CreateScale(4f) * Matrix.CreateRotationY(MathHelper.Pi * 5.0f / 8.0f) * Matrix.CreateTranslation(-28, 0, -1.9f);
                 DrawModel(carModel, carTextures, car2Matrix, technique);
             }
     
             private void DrawModel(Model model, Texture2D[] textures, Matrix wMatrix, string technique)
             {
                 Matrix[] modelTransforms = new Matrix[model.Bones.Count];
                 model.CopyAbsoluteBoneTransformsTo(modelTransforms);
                 int i = 0;
                 foreach (ModelMesh mesh in model.Meshes)
                 {
                     foreach (Effect currentEffect in mesh.Effects)
                     {
                         Matrix worldMatrix = modelTransforms[mesh.ParentBone.Index] * wMatrix;
                         currentEffect.CurrentTechnique = currentEffect.Techniques[technique];
                         currentEffect.Parameters["xWorldViewProjection"].SetValue(worldMatrix * viewMatrix * projectionMatrix);
                         currentEffect.Parameters["xTexture"].SetValue(textures[i++]);
                         currentEffect.Parameters["xWorld"].SetValue(worldMatrix);
                         currentEffect.Parameters["xLightPos"].SetValue(lightPos);
                         currentEffect.Parameters["xLightPower"].SetValue(lightPower);
                         currentEffect.Parameters["xAmbient"].SetValue(ambientPower);
                         currentEffect.Parameters["xLightsWorldViewProjection"].SetValue(worldMatrix * lightsViewProjectionMatrix);
                         currentEffect.Parameters["xShadowMap"].SetValue(shadowMap);
                         currentEffect.Parameters["xCarLightTexture"].SetValue(carLight);
                     }
                     mesh.Draw();
                 }
             }
     
         }
     }
     


    Google
     
    Webwww.riemers.net


    If you appreciate the amount of time I spend creating and updating
    these pages, feel free to donate -- any amount is welcome !



    - Website design & XNA + DirectX code : Riemer Grootjans -
    ©2003 - 2011 Riemer Grootjans
  • Translations

    This site in English
    This site in Korean
    This site in Czech

    Microsoft MVP Award



    2007 - 2011 MVP Award
    DirectX - XNA

    Contents

    News
    Home
    Forum
    XNA 2.0 Recipes Book (8)
    XNA 3.0 Recipes Book (8)
    Downloads
    Extra Reading (3)
    Matrices: geometrical
    Matrix Mathematics
    Homogenous matrices
    Community Projects (1)
    Tutorials (160)
    XNA 4.0 using C# (89)
    2D Series: Shooters (22)
    3D Series 1: Terrain (13)
    3D Series 2: Flightsim (14)
    3D Series 3: HLSL (18)
    Starting point
    HLSL introduction
    Vertex format
    Vertex shader
    Pixel shader
    Per-pixel colors
    Textured triangle
    Triangle strip
    World transform
    World normals
    Per-pixel lighting
    Shadow map
    Render to texture
    Projective texturing
    Real shadow
    Shaping the light
    Preshaders
    3D Series 4: Adv. terrain (19)
    Short Tuts (3)
    DirectX using C# (54)
    DirectX using C++ (15)
    DirectX using VB (2)
    -- Expand all --


    Thank you!

    Support this site --
    any amount is welcome !

    Stay up-to-date

    I don't have the time to keep a News section, so stay informed about the updates by clicking on this RSS file!