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

 40% OFF Pavtube DVD Ripper for Mac
  Posted by: VIKIVannessa
  When: 19/04/2014 at 02:02:54

 DVD Ripper with 40% off
  Posted by: VIKIVannessa
  When: 19/04/2014 at 02:02:22

 Get DVD Ripper Wind/Mac + $14 Coupon
  Posted by: VIKIVannessa
  When: 19/04/2014 at 02:02:03

 Backup DVD Escape Plan
  Posted by: Applefly
  When: 17/04/2014 at 06:00:12

 Disney DVDs to MP4
  Posted by: Applefly
  When: 17/04/2014 at 05:56:07

 DVD movies through media streamer
  Posted by: VIKIVannessa
  When: 16/04/2014 at 02:25:09

 DVD movies to play on Galaxy Tab 3 10.1
  Posted by: VIKIVannessa
  When: 16/04/2014 at 02:20:51

 Blu-ray to Apple ProRes
  Posted by: Applefly
  When: 12/04/2014 at 00:47:46

 HD H.264 MP4 format
  Posted by: Applefly
  When: 12/04/2014 at 00:43:23

 DVD collection to computer
  Posted by: VIKIVannessa
  When: 04/04/2014 at 07:13:33


Ads

Adding ambient lighting – processing in 2D screen coordinates

Welcome to this last chapter in the HLSL series. Maybe I should have put this chapter before the other chapters on lighting, as ambient lighting is a lot easier: it is done by adding a constant amount of light to the scene. As a little extra, we’ll be adding the glow around the light bulbs of our lampposts.

There is very little we have to do in our DirectX code. We’ll start by setting the amount of diffuse lighting, so add this line to your UpdateLightData method:

 effect.SetValue("xAmbient", 0.4f);

We’ll also be needing the 3D position of our Camera, so add this line to the bottom of the SetUpCamera method:

 effect.SetValue("xCameraPos", new Vector4(CameraPos.X, CameraPos.Y, CameraPos.Z, 1));

Of course, we need to receive these variables in our HLSL file:

float4 xCameraPos;

float xAmbient;

We will be adding a simple vertex and pixel shader, which we will call from the ShadowedScene technique in a last pass, so add this pass to the end of your code:

pass Pass3
{
    VertexShader = compile vs_2_0 AmbientVertexShader();
    PixelShader = compile ps_2_0 AmbientPixelShader();
}

Let’s start by defining the interfaces between our vertex and pixel shader. As always, we will need to provide the 2D screen position of every vertex. Because the glow around the lampposts will be added to the final 2D image, we will also need these 2D coordinates in our pixel shader, so we’ll need to pass them in the Position2D variable. As we’re doing lighting, we’ll also need to pass in the texture coodinates.:

struct AmbientVertexToPixel
{
    float4 Position             : POSITION;
    float2 TexCoords            : TEXCOORD0;
    float4 Position2D            : TEXCOORD1;
};

Our pixel shader will simply blend in some colors:

struct AmbientPixelToFrame
{
    float4 Color : COLOR0;
};

As we’ve already seen how to calculate these outputs of the vertex shader, I’m not going to discuss it once more and simply list the code:

AmbientVertexToPixel AmbientVertexShader( float4 inPos : POSITION, float2 inTexCoords : TEXCOORD0)
{
    AmbientVertexToPixel Output = (AmbientVertexToPixel)0;
    float4x4 preWorld = mul(xRotate, xTranslateAndScale);
    float4x4 preCameraWorldViewProjection = mul (preWorld, xCameraViewProjection);

    Output.Position = mul(inPos, preCameraWorldViewProjection);
    Output.Position2D = Output.Position;
    Output.TexCoords = inTexCoords;
    
    return Output;    
}

If we want our pixel shader simply to add ambient lighting, this would be the code:

AmbientPixelToFrame AmbientPixelShader(AmbientVertexToPixel PSIn)
{
    AmbientPixelToFrame Output = (AmbientPixelToFrame)0;

    Output.Color = tex2D(ColoredTextureSampler, PSIn.TexCoords)*xAmbient;

    return Output;
}

We simply multiply the color found in the texture by the ambient lighting factor. This seems too simple to be a real pixel shader, so let’s add the glow around the light bulbs.

The concept is very easy, but it shows calculations in 2D screen space, so it’s worth to be included in a tutorial. We will calculate the 2D screen position of the light. Then we calculate the distance between the 2D screen pos of the light, and the 2D screen pos of the current pixel. If this distance is smaller than a certain amount, we add some white.

First we should calculate the 2D screen pos. We have done this before, so here is the code:

float2 ScreenPos;
ScreenPos[0] = PSIn.Position2D.x/PSIn.Position2D.w/2.0f +0.5f;
ScreenPos[1] = -PSIn.Position2D.y/PSIn.Position2D.w/2.0f +0.5f;

For the remainder of the code, we have to iterate through our 2 lampposts:

for (int CurrentLight=1; CurrentLight<3; CurrentLight++)    
{
}

Next we will calculate the 2D position of the light. This is done exactly the same way: first we multiply the 3D position by the worldviewprojection matrix, after which we map the coordinates to the [0 1] region.

float4 Light3DPos = mul(xLightPos[CurrentLight],xCameraViewProjection);
float2 LightScreenPos;
LightScreenPos[0] = Light3DPos.x/Light3DPos.w/2.0f +0.5f;
LightScreenPos[1] = -Light3DPos.y/Light3DPos.w/2.0f +0.5f;    

Now we have both the 2D positions of the light and the pixel, we can calculate the distance between them. We can use the ‘distance’ method of HLSL:

float dist = distance(ScreenPos, LightScreenPos);

Before we move on, we have to define the maximal radius of the glow around our lights. If the light is further away from our camera, the radius of the glow around this light has to decrease, so it has to be inversely related to the distance between our camera and the light:

float radius = 3.5f/distance(xCameraPos, xLightPos[CurrentLight]);

Note that this time the distance between 2 3D coordinates is being calculated, while in the previous case we were dealing with 2 2D coordinates. Adjust the 3.5f value to size you glows.

Now we have all data we need! We can check if the distance between the pixel and the light is smaller than the maximal radius. If this is the case, we will add an amount of light that is related to this distance:

if (dist < radius)
{
     Output.Color.rgb += (radius-dist)*8.0f;
}

That’s it! Running this code should already give you the image you can see the final image of the series. However, if we take a look at the calculations done by the last pixel shader, we notice a lot of constant calculations are being done, such as the 2D position of our lights, the dist and the radius values. These are being calculated for every pixel, while they will always remain the same!

Not completely true. Remember the chapter on preshaders? Our compiler was able to identify blocks of code inside our vertex shader that remained constant for each vertex. The same is true for constant code in pixel shaders! This means this code will be stripped out and calculated once on the CPU. If you don’t believe me, you can always have a look at the assembler output, as I showed you in the chapter on preshaders.




DirectX Tutorial 19 - Finishing touch

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:
  • Drawing order in shadow map
          Hi! I followed your DirectX using C# tutorials ...
  • Is there a sample I can download
          The code in this series is laid out nicely , howev...
  • Point lights...
          Hello! At first I would like to say BIG thank y...


    This concludes this Series on HLSL. We started with a small theoretic introduction to HLSL, and up to chapter 10 all basic HLSL stuff was explained. From then on, we’ve seen a lot of more advanced topics, such as preshaders and setting individual depth values. With all this, you were able to construct a technique that casts shadows of multiple lights on your scene.

    Our final DirectX code:

     using System;
     using System.Drawing;
     using System.Collections;
     using System.ComponentModel;
     using System.Windows.Forms;
     using System.Data;
     using Microsoft.DirectX;
     using Microsoft.DirectX.Direct3D;
     using D3D = Microsoft.DirectX.Direct3D;
     
     namespace DirectX_Tutorial
     {
         struct myownvertexformat
         {
             public Vector3 Pos;
             public Vector3 Normal;
             public Vector2 TexCoord;
     
             public myownvertexformat(Vector3 _Pos, Vector3 _Normal, float texx, float texy)
             {
                 Pos = _Pos;
                 Normal = _Normal;
                 TexCoord.X = texx;
                 TexCoord.Y = texy;
             }
         }
     
         public class WinForm : System.Windows.Forms.Form
         {        
             private System.ComponentModel.Container components = null;
             private D3D.Device device;        
             private VertexBuffer vb;
             private Vector3 CameraPos;
             private VertexDeclaration vd;
             private Effect effect;
     
             private Texture StreetTexture;
             private Texture CarLight;
             private Texture SpotLight;
             private Mesh Lamppost;
             private Material[] LamppostMaterials;
             private Texture[] LamppostTextures;
             private Mesh Car;
             private Material[] CarMaterials;
             private Texture[] CarTextures;
     
             private Matrix matView;
             private Matrix matProjection;
     
             private int LastTickCount = 1;
             private int Frames = 0;
             private float LastFrameRate = 0;
             private D3D.Font text;
     
             private RenderToSurface RtsHelper;
             private Texture RenderTexture;
             private Surface RenderSurface;
             private int RenderSurfaceSize = 512;
     
             public WinForm()
             {
                 InitializeComponent();
                 this.SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
             }
     
             public void InitializeDevice()
             {
                 PresentParameters presentParams = new PresentParameters();
                 presentParams.Windowed = true;
                 presentParams.SwapEffect = SwapEffect.Discard;
                 presentParams.AutoDepthStencilFormat = DepthFormat.D16;
                 presentParams.EnableAutoDepthStencil = true;
     
                 Caps DevCaps = D3D.Manager.GetDeviceCaps(0, D3D.DeviceType.Hardware);
                 D3D.DeviceType DevType = D3D.DeviceType.Reference;
                 CreateFlags DevFlags = CreateFlags.SoftwareVertexProcessing;
                 if ((DevCaps.VertexShaderVersion >= new Version(2, 0)) && (DevCaps.PixelShaderVersion >= new Version(2, 0)))
                 {
                     DevType = D3D.DeviceType.Hardware;                
                     if (DevCaps.DeviceCaps.SupportsHardwareTransformAndLight)
                     {
                         DevFlags = CreateFlags.HardwareVertexProcessing;
                         if (DevCaps.DeviceCaps.SupportsPureDevice)
                         {
                             DevFlags |= CreateFlags.PureDevice;
                         }
                     }                
                 }
     
                 device = new D3D.Device(0, DevType, this, DevFlags, presentParams);
                 device.DeviceReset += new EventHandler(this.HandleDeviceReset);            
             }
     
             private void HandleDeviceReset(object sender, EventArgs e)
             {
                 FillResources();        
             }
     
             private void AllocateResources()
             {
                 vb = new VertexBuffer(typeof(myownvertexformat), 18, device, Usage.WriteOnly, VertexFormats.Position | VertexFormats.Normal | VertexFormats.Texture0, Pool.Managed);                        
                 InitializeFont();
                 effect = D3D.Effect.FromFile(device, @"../../OurHLSLFile.fx", null, null, ShaderFlags.None, null);
             }
     
             private void FillResources()
             {
                 myownvertexformat[] vertices = new myownvertexformat[18];
     
                 vertices[0] = new myownvertexformat(new Vector3(20, -10, 0), new Vector3(0, 0, 1), -0.25f, 25.0f);
                 vertices[1] = new myownvertexformat(new Vector3(20, 100, 0), new Vector3(0, 0, 1), -0.25f, 0.0f);
                 vertices[2] = new myownvertexformat(new Vector3(-2, -10, 0), new Vector3(0, 0, 1), 0.25f, 25.0f);                        
                 vertices[3] = new myownvertexformat(new Vector3(-2, 100, 0), new Vector3(0, 0, 1), 0.25f, 0.0f);
                 vertices[4] = new myownvertexformat(new Vector3(-2, -10, 0), new Vector3(1, 0, 0), 0.25f, 25.0f);                        
                 vertices[5] = new myownvertexformat(new Vector3(-2, 100, 0), new Vector3(1, 0, 0), 0.25f, 0.0f);
                 vertices[6] = new myownvertexformat(new Vector3(-2, -10, 1), new Vector3(1, 0, 0), 0.375f, 25.0f);
                 vertices[7] = new myownvertexformat(new Vector3(-2, 100, 1), new Vector3(1, 0, 0), 0.375f, 0.0f);
                 vertices[8] = new myownvertexformat(new Vector3(-2, -10, 1), new Vector3(0, 0, 1), 0.375f, 25.0f);
                 vertices[9] = new myownvertexformat(new Vector3(-2, 100, 1), new Vector3(0, 0, 1), 0.375f, 0.0f);
                 vertices[10] = new myownvertexformat(new Vector3(-3, -10, 1), new Vector3(0, 0, 1), 0.5f, 25.0f);
                 vertices[11] = new myownvertexformat(new Vector3(-3, 100, 1), new Vector3(0, 0, 1), 0.5f, 0.0f);
                 vertices[12] = new myownvertexformat(new Vector3(-13, -10, 1), new Vector3(0, 0, 1), 0.75f, 25.0f);
                 vertices[13] = new myownvertexformat(new Vector3(-13, 100, 1), new Vector3(0, 0, 1), 0.75f, 0.0f);
                 vertices[14] = new myownvertexformat(new Vector3(-13, -10, 1), new Vector3(1, 0, 0), 0.75f, 25.0f);
                 vertices[15] = new myownvertexformat(new Vector3(-13, 100, 1), new Vector3(1, 0, 0), 0.75f, 0.0f);
                 vertices[16] = new myownvertexformat(new Vector3(-13, -10, 21), new Vector3(1, 0, 0), 1.25f, 25.0f);
                 vertices[17] = new myownvertexformat(new Vector3(-13, 100, 21), new Vector3(1, 0, 0), 1.25f, 0.0f);
                 
                 vb.SetData(vertices, 0, LockFlags.None);
     
                 SetUpCamera();
     
                 VertexElement[] velements = new VertexElement[]
                 {
                     new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0),
                     new VertexElement(0, 12, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Normal, 0),
                     new VertexElement(0, 24, DeclarationType.Float2, DeclarationMethod.Default, DeclarationUsage.TextureCoordinate, 0),
                     VertexElement.VertexDeclarationEnd
                 };
                 vd = new VertexDeclaration(device, velements);
     
                 StreetTexture = TextureLoader.FromFile(device, "streettexture.jpg");
                 CarLight = TextureLoader.FromFile(device, "carlight.jpg");
                 SpotLight = TextureLoader.FromFile(device, "spotlight.jpg");
                 effect.SetValue("xColoredTexture", StreetTexture);
                 effect.SetValue("xCarLightTexture", CarLight);
                 effect.SetValue("xSpotLightTexture", SpotLight);
     
                 LoadMesh("lamppost.x", ref Lamppost, ref LamppostMaterials, ref LamppostTextures);
                 LoadMesh("car.x", ref Car, ref CarMaterials, ref CarTextures);            
     
                 RtsHelper = new RenderToSurface(device, RenderSurfaceSize, RenderSurfaceSize, Format.X8R8G8B8, true, DepthFormat.D16);
                 RenderTexture = new Texture(device, RenderSurfaceSize, RenderSurfaceSize, 1, Usage.RenderTarget, Format.X8R8G8B8, Pool.Default);
                 RenderSurface = RenderTexture.GetSurfaceLevel(0);
             }
     
             private void InitializeFont()
             {
                 System.Drawing.Font systemfont = new System.Drawing.Font("Arial", 12f, FontStyle.Regular);
                 text = new D3D.Font(device, systemfont);
             }
     
             private void DrawMesh(Mesh mesh, Material[] meshmaterials, Texture[] meshtextures)
             {
                 for (int i = 0; i < meshmaterials.Length; i++)
                 {
                     if (meshtextures.Length > 3) effect.SetValue("xColoredTexture", meshtextures[i]);                
                     effect.CommitChanges();
                     mesh.DrawSubset(i);
                 }
             }
     
             protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
             {
                 UpdateLightData();
                 GenerateShadowMap();
     
                 device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);
                 device.BeginScene();
     
                 RenderShadowedScene();
                 using (Sprite spriteobject = new Sprite(device))
                 {
                     spriteobject.Begin(SpriteFlags.DoNotSaveState);
                     spriteobject.Transform = Matrix.Scaling(0.25f, 0.25f, 0.25f);
                     spriteobject.Draw(RenderTexture, new Rectangle(0, 0, RenderSurfaceSize, RenderSurfaceSize), new Vector3(0, 0, 0), new Vector3(0, 0, 0), Color.White);
                     spriteobject.End();
                 }
                 UpdateFramerate();
     
                 device.EndScene();
                 device.Present();
                 this.Invalidate();    
             }
     
             private void GenerateShadowMap()
             {
                 RtsHelper.BeginScene(RenderSurface);            
                 device.Clear(ClearFlags.Target | ClearFlags.ZBuffer, Color.Black, 1.0f, 0);            
     
                 effect.Technique = "ShadowMap";
                 effect.SetValue("xMaxDepth", 60);            
                 int numpasses = effect.Begin(0);
                 for (int i = 0; i < numpasses; i++)
                 {
                     effect.BeginPass(i);
                     DrawScene();
                     effect.EndPass();
                 }        
                 effect.End();
     
                 RtsHelper.EndScene(Filter.None);
             }
     
             private void RenderShadowedScene()
             {
                 effect.Technique = "ShadowedScene";
                 effect.SetValue("xShadowMap", RenderTexture);
                 
                 int numpasses = effect.Begin(0);
                 for (int i = 0; i < numpasses; i++)
                 {
                     effect.BeginPass(i);
                     DrawScene();
                     effect.EndPass();
                 }        
                 effect.End();
             }
     
             private void UpdateLightData()
             {
                 Vector3[] LightPos = new Vector3[3];
                 LightPos[0] = new Vector3(18, 2, 5);
                 LightPos[1] = new Vector3(-5, 5, 11.5f);
                 LightPos[2] = new Vector3(-5, 35, 11.5f);
     
                 float[] LightPower = new float[3];        
                 LightPower[0] = 1.1f;
                 LightPower[1] = 0.6f;
                 LightPower[2] = 0.6f;
                 
                 Matrix[] LightViewProjection = new Matrix[3];
                 LightViewProjection[0] = Matrix.LookAtLH(LightPos[0], new Vector3(2, 10, -3), new Vector3(0, 0, 1)) * Matrix.PerspectiveFovLH((float)Math.PI / 2, this.Width / this.Height, 1f, 100f);
                 LightViewProjection[1] = Matrix.LookAtLH(LightPos[1], new Vector3(-5, 5, 0), new Vector3(0, 1, 0)) * Matrix.PerspectiveFovLH((float)Math.PI / 1.9f, this.Width / this.Height, 0.3f, 100f);
                 LightViewProjection[2] = Matrix.LookAtLH(LightPos[2], new Vector3(-5, 35, 0), new Vector3(0, 1, 0)) * Matrix.PerspectiveFovLH((float)Math.PI / 1.9f, this.Width / this.Height, 0.3f, 100f);
     
                 effect.SetValue("xAmbient", 0.4f);
                 effect.SetValue("xLightViewProjection", LightViewProjection);
                 effect.SetValue("xLightPos", V3ToV4(LightPos));
                 effect.SetValue("xLightPower", LightPower);
             }
     
             private Vector4[] V3ToV4(Vector3[] In)
             {
                 Vector4[] Out = new Vector4[3];
                 for (int i = 0; i < 3; i++)
                 {
                     Out[i] = new Vector4(In[i].X, In[i].Y, In[i].Z, 1);
                 }
                 return Out;
             }
     
             private void DrawScene()
             {            
                 effect.SetValue("xRotate", Matrix.Identity);
                 effect.SetValue("xTranslateAndScale", Matrix.Identity);            
                 effect.SetValue("xColoredTexture", StreetTexture);
                 effect.CommitChanges();
                 device.SetStreamSource(0, vb, 0);
                 device.VertexDeclaration = vd;
                 device.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 16);
     
                 effect.SetValue("xRotate", Matrix.RotationX((float)Math.PI / 2));
                 effect.SetValue("xTranslateAndScale", Matrix.Scaling(0.05f, 0.05f, 0.05f) * Matrix.Translation(-4.0f, 5, 1));
                 effect.CommitChanges();
                 DrawMesh(Lamppost, LamppostMaterials, LamppostTextures);
     
                 effect.SetValue("xTranslateAndScale", Matrix.Scaling(0.05f, 0.05f, 0.05f) * Matrix.Translation(-4.0f, 35, 1));
                 effect.CommitChanges();
                 DrawMesh(Lamppost, LamppostMaterials, LamppostTextures);
     
                 effect.SetValue("xRotate", Matrix.RotationYawPitchRoll((float)Math.PI / 2, (float)Math.PI / 2, (float)Math.PI / 2));
                 effect.SetValue("xTranslateAndScale", Matrix.Scaling(4f, 4f, 4f) * Matrix.Translation(3, 15, 0f));
                 DrawMesh(Car, CarMaterials, CarTextures);
     
                 effect.SetValue("xRotate", Matrix.RotationYawPitchRoll((float)Math.PI / 2, (float)Math.PI / 8, (float)Math.PI / 2));
                 effect.SetValue("xTranslateAndScale", Matrix.Scaling(4f, 4f, 4f) * Matrix.Translation(28, -1.9f, 0f));
                 DrawMesh(Car, CarMaterials, CarTextures);
             }
     
             private void UpdateFramerate()
             {
                 Frames++;
                 if (Math.Abs(Environment.TickCount - LastTickCount) > 1000)
                 {
                     LastFrameRate = (float)Frames * 1000 / Math.Abs(Environment.TickCount - LastTickCount);
                     LastTickCount = Environment.TickCount;
                     Frames = 0;
                 }
                 text.DrawText(null, string.Format("Framerate : {0:0.00} fps", LastFrameRate), new Point(10, 430), Color.Red);
             }
     
             private void SetUpCamera()
             {
                 CameraPos = new Vector3(25, -18, 13);
                 matProjection = Matrix.PerspectiveFovLH((float)Math.PI / 4, this.Width / this.Height, 0.3f, 200f);
                 matView = Matrix.LookAtLH(CameraPos, new Vector3(0, 12, 2), new Vector3(0, 0, 1));
                 effect.SetValue("xCameraViewProjection", matView * matProjection);
                 effect.SetValue("xCameraPos", new Vector4(CameraPos.X, CameraPos.Y, CameraPos.Z, 1));
             }
     
             private void LoadMesh(string filename, ref Mesh mesh, ref Material[] meshmaterials, ref Texture[] meshtextures)
             {
                 ExtendedMaterial[] materialarray;
                 GraphicsStream adj = null;
     
                 mesh = Mesh.FromFile(filename, MeshFlags.Managed, device, out adj, out materialarray);
     
                 if ((materialarray != null) && (materialarray.Length > 0))
                 {
                     meshmaterials = new Material[materialarray.Length];
                     meshtextures = new Texture[materialarray.Length];
     
                     for (int i = 0; i < materialarray.Length; i++)
                     {
                         meshmaterials[i] = materialarray[i].Material3D;
                         meshmaterials[i].Ambient = meshmaterials[i].Diffuse;
     
                         if ((materialarray[i].TextureFilename != null) && (materialarray[i].TextureFilename != string.Empty))
                         {
                             meshtextures[i] = TextureLoader.FromFile(device, materialarray[i].TextureFilename);
                         }
                     }                
                 }
     
                 mesh = mesh.Clone(mesh.Options.Value, CustomVertex.PositionNormalTextured.Format, device);
                 mesh.ComputeNormals();
             }
     
             protected override void Dispose(bool disposing)
             {
                 if (disposing)
                 {
                     if (components != null)
                     {
                         components.Dispose();
                     }
                 }
                 base.Dispose(disposing);
             }
     
             private void InitializeComponent()
             {
                 this.components = new System.ComponentModel.Container();
                 this.Size = new System.Drawing.Size(500, 500);
                 this.Text = "Riemer's DirectX & HLSL Tutorial using C# -- Season 3";
             }
     
             static void Main()
             {
                 using (WinForm our_directx_form = new WinForm())
                 {
                     our_directx_form.InitializeDevice();                
                     our_directx_form.AllocateResources();
                     our_directx_form.FillResources();
                     Application.Run(our_directx_form);
                 }
             }
         }
     }

    And the HLSL code:

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

    struct SMapPixelToFrame
    {
        float4 Color : COLOR0;
        float Depth     : DEPTH;
    };

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

    struct SScenePixelToFrame
    {
        float4 Color : COLOR0;
    };

     
     struct AmbientVertexToPixel
     {
         float4 Position             : POSITION;
         float2 TexCoords            : TEXCOORD0;
         float4 Position2D            : TEXCOORD1;
     };
     
     struct AmbientPixelToFrame
     {
         float4 Color : COLOR0;
     };


    //------- Constants --------
    float4x4 xCameraViewProjection;
    float4x4 xLightViewProjection[3];
    float4x4 xRotate;
    float4x4 xTranslateAndScale;

    float4 xLightPos[3];

     float4 xCameraPos;

    float xLightPower[3];
    float xMaxDepth;

     float xAmbient;


    //------- Texture Samplers --------

    Texture xColoredTexture;

    sampler ColoredTextureSampler = sampler_state { texture = <xColoredTexture> ; 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;};    
    Texture xSpotLightTexture;

    sampler SpotLightSampler = sampler_state { texture = <xSpotLightTexture> ; magfilter = LINEAR; minfilter=LINEAR; mipfilter = LINEAR; AddressU = clamp; AddressV = clamp;};    
    //------- Vertex Shaders --------

    SMapVertexToPixel ShadowMapVertexShader( float4 inPos : POSITION, uniform int CurrentLight)
    {
        SMapVertexToPixel Output = (SMapVertexToPixel)0;
        float4x4 preWorld = mul(xRotate, xTranslateAndScale);
        float4x4 preLightWorldViewProjection = mul (preWorld, xLightViewProjection[CurrentLight]);
        
        Output.Position = mul(inPos, preLightWorldViewProjection);
        Output.Position2D = Output.Position;
        
        return Output;    
    }

    SSceneVertexToPixel ShadowedSceneVertexShader( float4 inPos : POSITION, float2 inTexCoords : TEXCOORD0, float3 inNormal : NORMAL, uniform int CurrentLight)
    {
        SSceneVertexToPixel Output = (SSceneVertexToPixel)0;
        float4x4 preWorld = mul(xRotate, xTranslateAndScale);
        float4x4 preCameraWorldViewProjection = mul (preWorld, xCameraViewProjection);
        float4x4 preLightWorldViewProjection = mul (preWorld, xLightViewProjection[CurrentLight]);
        
        Output.Position = mul(inPos, preCameraWorldViewProjection);
        Output.ShadowMapSamplingPos = mul(inPos, preLightWorldViewProjection);
        Output.RealDistance = Output.ShadowMapSamplingPos.z/xMaxDepth;
        Output.TexCoords = inTexCoords;
        Output.Normal = mul(inNormal, xRotate);
        Output.Position3D = inPos;
        
        return Output;    
    }


     AmbientVertexToPixel AmbientVertexShader( float4 inPos : POSITION, float2 inTexCoords : TEXCOORD0)
     {
         AmbientVertexToPixel Output = (AmbientVertexToPixel)0;
         float4x4 preWorld = mul(xRotate, xTranslateAndScale);
         float4x4 preCameraWorldViewProjection = mul (preWorld, xCameraViewProjection);
     
         Output.Position = mul(inPos, preCameraWorldViewProjection);
         Output.Position2D = Output.Position;
         Output.TexCoords = inTexCoords;
     
         return Output;    
     }


    //------- Pixel Shaders --------

    float DotProduct(float4 LightPos, float3 Pos3D, float3 Normal)
    {
        float3 LightDir = normalize(LightPos - Pos3D);
        return dot(LightDir, Normal);
    }

    SMapPixelToFrame ShadowMapPixelShader(SMapVertexToPixel PSIn, uniform int CurrentLight)
    {
        SMapPixelToFrame Output = (SMapPixelToFrame)0;

        Output.Color[CurrentLight] = PSIn.Position2D.z/xMaxDepth;
        Output.Depth = Output.Color[CurrentLight]/3.0f + (2-CurrentLight)*0.33f;

        return Output;
    }

    SScenePixelToFrame ShadowedScenePixelShader(SSceneVertexToPixel PSIn, uniform int CurrentLight)
    {
        SScenePixelToFrame Output = (SScenePixelToFrame)0;

        float2 ProjectedTexCoords;
        ProjectedTexCoords[0] = PSIn.ShadowMapSamplingPos.x/PSIn.ShadowMapSamplingPos.w/2.0f +0.5f;
        ProjectedTexCoords[1] = -PSIn.ShadowMapSamplingPos.y/PSIn.ShadowMapSamplingPos.w/2.0f +0.5f;

        if ((saturate(ProjectedTexCoords.x) == ProjectedTexCoords.x) && (saturate(ProjectedTexCoords.y) == ProjectedTexCoords.y))
        {    
            float StoredDepthInShadowMap = tex2D(ShadowMapSampler, ProjectedTexCoords)[CurrentLight];    
            if ((PSIn.RealDistance.x - 1.0f/100.0f) <= StoredDepthInShadowMap)    
            {
                float LightTextureFactor;
                if (CurrentLight == 0)
                {
                    LightTextureFactor = tex2D(CarLightSampler, ProjectedTexCoords).r;
                }else{
                    LightTextureFactor = tex2D(SpotLightSampler, ProjectedTexCoords).r;
                }
        
                float DiffuseLightingFactor = DotProduct(xLightPos[CurrentLight], PSIn.Position3D, PSIn.Normal);
                float4 ColorComponent = tex2D(ColoredTextureSampler, PSIn.TexCoords);
                Output.Color = ColorComponent*LightTextureFactor*DiffuseLightingFactor*xLightPower[CurrentLight];
            }
        }    

        return Output;
    }


     AmbientPixelToFrame AmbientPixelShader(AmbientVertexToPixel PSIn)
     {
         AmbientPixelToFrame Output = (AmbientPixelToFrame)0;    
         
         Output.Color = tex2D(ColoredTextureSampler, PSIn.TexCoords)*xAmbient;
         
         float2 ScreenPos;
         ScreenPos[0] = PSIn.Position2D.x/PSIn.Position2D.w/2.0f +0.5f;
         ScreenPos[1] = -PSIn.Position2D.y/PSIn.Position2D.w/2.0f +0.5f;
         
         for (int CurrentLight=1; CurrentLight<3; CurrentLight++)    
         {            
             float4 Light3DPos = mul(xLightPos[CurrentLight],xCameraViewProjection);
             float2 LightScreenPos;
             LightScreenPos[0] = Light3DPos.x/Light3DPos.w/2.0f +0.5f;
             LightScreenPos[1] = -Light3DPos.y/Light3DPos.w/2.0f +0.5f;    
     
             float dist = distance(ScreenPos, LightScreenPos);
             float radius = 3.5f/distance(xCameraPos, xLightPos[CurrentLight]);
             if (dist < radius)
             {
                 Output.Color.rgb += (radius-dist)*8.0f;
             }
         }
         
         return Output;
     }
     

    //------- Techniques --------

    technique ShadowMap
    {
        pass Pass0
        {    
            cullmode = ccw;
            colorwriteenable = red;    
            VertexShader = compile vs_2_0 ShadowMapVertexShader(0);
            PixelShader = compile ps_2_0 ShadowMapPixelShader(0);
        }
        pass Pass1
        {    
            colorwriteenable = green;
            VertexShader = compile vs_2_0 ShadowMapVertexShader(1);
            PixelShader = compile ps_2_0 ShadowMapPixelShader(1);
        }    
        pass Pass2
        {    
            colorwriteenable = blue;
            VertexShader = compile vs_2_0 ShadowMapVertexShader(2);
            PixelShader = compile ps_2_0 ShadowMapPixelShader(2);
        }
    }

    technique ShadowedScene
    {
        pass Pass0
        {    
            VertexShader = compile vs_2_0 ShadowedSceneVertexShader(0);
            PixelShader = compile ps_2_0 ShadowedScenePixelShader(0);
        }
        pass Pass1
        {
             SRCBLEND = ONE;
            DESTBLEND = ONE;
            ALPHABLENDENABLE = true;
        
            VertexShader = compile vs_2_0 ShadowedSceneVertexShader(1);
            PixelShader = compile ps_2_0 ShadowedScenePixelShader(1);
        }
        pass Pass2
        {        
            VertexShader = compile vs_2_0 ShadowedSceneVertexShader(2);
            PixelShader = compile ps_2_0 ShadowedScenePixelShader(2);
        }

         pass Pass3
         {
              VertexShader = compile vs_2_0 AmbientVertexShader();
             PixelShader = compile ps_2_0 AmbientPixelShader();
         }

    }


    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)
    DirectX using C# (54)
    Series 1:Terrain (14)
    Series 2: Flightsim (19)
    Series 3: HLSL (19)
    Starting point
    HLSL Introduction
    Vertex Shader
    Shaded triangle
    Pixel Shader
    Textured Triangle
    Triangle Strip
    World transform
    Adding normals
    The first light
    Shadow mapping
    Render To Texture
    Projective texturing
    The first shadow
    Shaping the light
    Preshaders
    Multiple lights
    Adjusting Z values
    Finishing touch
    Short Tuts (2)
    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!