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

Cleaning up our interface using Preshaders

When you take a look at our DirectX code, thereís still one part if the code that is a bit disappointing: the DrawScene method. There is a lot of redundancy in the code that takes care of the interface to our HLSL file: the SetValue calls. First we set the WorldViewProjection matrix for our camera, then for our light, and we end by sending over a matrix containing only the rotation.

This way, every new transformation we would like to do in HLSL, would require a new SetValue call, with the data being passed probably already contained in one of the previous sets of data passed to the HLSL code (which is now the case with the rotation data, which is already present in the world matrix). All of this data has, in fact, nothing to do with the purpose of the method, which has to position and draw the objects in our scene. If we would have to pass a new matrix for each of our following lights, the method would definitely become a mess. Thatís why itís time we discuss preshaders.

In our DrawScene method, the only data we would ideally like to set are the scaling, rotation and translation matrices of the objects to draw. Also, we would like to pass in the view and projection matrices of our camera and light only once. The question that arises is this: in the end, these matrices have to be multiplied, so where and when would that be?

Up to this point, for each object, the multiplications were done once by our DirectX app, thus done by the CPU (your Intel or AMD). This is shown on the left side of the image below: every frame of a game, the game is updated (responding to user input if there is any), the matrices are multiplied and sent to HLSL. Next, the vertex shader is called for every vertex.



But we donít want to do the multiplication in our DirectX method, as this litters our code. If we would perform the multiplications in our vertex shader, these multiplications would have to be performed by our GPU (your GeForce or Radeon) in the graphics card for every vertex it has to draw! This is shown in the middle column of the image above.

This is where preshaders kick in: when the HLSL code is being compiled, the compiler checks for code that will be the same for every vertex. So if we put our matrix multiplications inside our vertex buffers, that part of HLSL code will get stripped away by the compiler, and put in a Ďpreshaderí. This preshader is executed on the CPU before the vertex shader is actually called, and the resulting constants are passed to the HLSL code. This way, we can code the multiplications in our vertex shader (where they belong, as youíll see), yet they will be processed only once on the CPU. This is represented on the right part of the image.

Enough for the theory, letís move on to the code. Letís start working towards the idea of setting HLSL constants only in the appropriate methods. Letís start by our camera: this delivers the view and projection matrices. Because weíll never need them separated, weíll pass the combined matrix, only this time we send it only once, from our SetUpCamera method:

 effect.SetValue("xCameraViewProjection", matView * matProjection);

The same hold for our light: add this line to your UpdateLightData method:

 effect.SetValue("xLightViewProjection", LightViewProjection);

This method now sets 3 HLSL constants, all of which are related only to this method, which is perfect.

Now the last part: our DrawScene method. As we said, we only should pass the scaling, rotation and translation matrices. Because we need our rotation data separately (to process our normals), we will send 2 matrices: the rotation-only matrix and the matrix that holds the combination of the scaling and the translation:

 private void DrawScene()
 {            
      effect.SetValue("xRotate", Matrix.Identity);
      effect.SetValue("xTranslateAndScale", Matrix.Identity);            
      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.RotationX((float)Math.PI / 2) * Matrix.RotationZ((float)Math.PI));
      effect.SetValue("xTranslateAndScale", Matrix.Translation(0, 12, 2.4f));
      effect.CommitChanges();
      DrawMesh(Car, CarMaterials, CarTextures);    
 }

Note that the second lamppost doesnít require the rotation matrix to be sent, as it is the same as that of the first lamppost.

Thatís it for the DirectX code! Note that every method sets only its appropriate HLSL constants, and no data is sent twice. Now itís time to have a look at the HLSL code, where we have to process the matrix multiplications. First remove all of the old matrix constants in the HLSL code, and replace them with these:

float4x4 xCameraViewProjection;
float4x4 xLightViewProjection;
float4x4 xRotate;
float4x4 xTranslateAndScale;

Next in line is our vertex shader. The ShadowMapVertexShader holds only 2 lines of code, but they use and old constant: LightWorldViewProjection. Now we have to create this constant, starting from the 4 matrices we just defined. Have a look at this code:

float4x4 preWorld = mul(xRotate, xTranslateAndScale);
float4x4 preLightWorldViewProjection = mul (preWorld, xLightViewProjection);

From the rotation, translation and scaling data, we can create the world matrix. This world matrix will be identified as being the same for every vertex of the current object, so it will be extracted by the HLSL compiler to be run on the CPU. Because of this, Iíve called the result preWorld.

When we multiply the world matrix by the viewprojection matrix, we get the required preLightWorldViewProjection. This will also be calculated as preshader on the CPU. With this preLightWorldViewProjection, each vertex will be multiplied in the vertex shader. The total vertex shader becomes:

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

Since our pixel shaders donít use any matrix constants, we can move on to the second vertex shader, ShadowedSceneVertexShader. This one needs the WorldViewProjection matrices of both our camera and our lamp, which we need to calculate. This is done exactly the same as before:

float4x4 preWorld = mul(xRotate, xTranslateAndScale);
float4x4 preCameraWorldViewProjection = mul (preWorld, xCameraViewProjection);
float4x4 preLightWorldViewProjection = mul (preWorld, xLightViewProjection);

First we calculate the World matrix for the object, from which we create the required matrices. The complete vertex shader becomes:

SSceneVertexToPixel ShadowedSceneVertexShader( float4 inPos : POSITION, float2 inTexCoords : TEXCOORD0, float3 inNormal : NORMAL)
{
    SSceneVertexToPixel Output = (SSceneVertexToPixel)0;
    float4x4 preWorld = mul(xRotate, xTranslateAndScale);
    float4x4 preCameraWorldViewProjection = mul (preWorld, xCameraViewProjection);
    float4x4 preLightWorldViewProjection = mul (preWorld, xLightViewProjection);
    
    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;    
}

When you hit CTRL+S, FX Composer shouldnít give any error messages. Before ending this chapter, let me give you some proof of my whole story. Using the command prompt, you can let the compiler show you what assembler code your HLSL file would be transformed into. Go to the directory that holds you .fx file, and type:

 fxc /Tfx_2_0 OurHLSLfile.fx /Fc:output.fxc

In case you .fx file is named OurHLSLfile.fx, this will compile you HLSL code and put the assembler code in the file output.fxc. By default, youíre the fxc compiler will enable. If you want to see the difference, you can let the compiler know to disable preshaders by using the /Od parameter:

 fxc /Od /Tfx_2_0 OurHLSLfile.fx /Fc:output.fxc

Below you can file the assembly code of our first vertex shader. Because the total listing would be too large, I snipped out a part of it, but you should get the idea anyway:



In the left part, you will see all matrix multiplications are done in the vertex shader itself, which corresponds to the ĎNo wayí column of my first image on this page. This way, up to 67 vertex instructions have to be performed for each vertex, which is quite a lot.

In the right part, youíll see these multiplications have been identified by the compiler and extracted into the preshader. In this case, only 6 shader instructions have to be performed for each vertex!




DirectX Tutorial 16 - Preshaders

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:
  • About this tutorial
          HI riemer, Standing in your site far from 7 weeks....


    This chapter we havenít introduced a new DirectX technique, but we have discussed an elegant way to clean up the interface between our DirectX code and our HLSL code. The DirectX methods set their appropriate HLSL constants, and the HLSL code creates the matrices it needs. This approach is much cleaner and more scalable.

    Our HLSL code:

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

    struct SMapPixelToFrame
    {
        float4 Color : COLOR0;
    };

    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;
    };

    //------- Constants --------

     float4x4 xCameraViewProjection;
     float4x4 xLightViewProjection;
     float4x4 xRotate;
     float4x4 xTranslateAndScale;


    float4 xLightPos;
    float xLightPower;
    float xMaxDepth;

    //------- 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;};    
    //------- Vertex Shaders --------

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

         float4x4 preWorld = mul(xRotate, xTranslateAndScale);
         float4x4 preLightWorldViewProjection = mul (preWorld, xLightViewProjection);
         
         Output.Position = mul(inPos, preLightWorldViewProjection);

        Output.Position2D = Output.Position;
        
        return Output;    
    }

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

         float4x4 preWorld = mul(xRotate, xTranslateAndScale);
         float4x4 preCameraWorldViewProjection = mul (preWorld, xCameraViewProjection);
         float4x4 preLightWorldViewProjection = mul (preWorld, xLightViewProjection);
         
         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;    
    }

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

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

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

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

        return Output;
    }

    SScenePixelToFrame ShadowedScenePixelShader(SSceneVertexToPixel PSIn)
    {
        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).x;    
            if ((PSIn.RealDistance.x - 1.0f/100.0f) <= StoredDepthInShadowMap)    
            {
                float LightTextureFactor = tex2D(CarLightSampler, ProjectedTexCoords).r;
                float DiffuseLightingFactor = DotProduct(xLightPos, PSIn.Position3D, PSIn.Normal);
                float4 ColorComponent = tex2D(ColoredTextureSampler, PSIn.TexCoords);
                Output.Color = ColorComponent*LightTextureFactor*DiffuseLightingFactor*xLightPower;
            }
        }    

        return Output;
    }

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

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

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

    And our cleaned 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 Matrix LightViewProjection;
     
             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);
     
                 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);
                 effect.SetValue("xCarLightTexture", CarLight);
                 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(18, 2, 5);
                 float LightPower = 2f;
     
                 LightViewProjection = Matrix.LookAtLH(LightPos, new Vector3(2, 10, -3), new Vector3(0, 0, 1)) * Matrix.PerspectiveFovLH((float)Math.PI / 2, this.Width / this.Height, 1f, 100f);
                 effect.SetValue("xLightViewProjection", LightViewProjection);
                 effect.SetValue("xLightPos", new Vector4(LightPos.X, LightPos.Y, LightPos.Z, 1));
                 effect.SetValue("xLightPower", LightPower);
             }
     
             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));
                 DrawMesh(Lamppost, LamppostMaterials, LamppostTextures);
     
                 effect.SetValue("xTranslateAndScale", Matrix.Scaling(0.05f, 0.05f, 0.05f) * Matrix.Translation(-4.0f, 35, 1));
                 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);
             }
     
             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);
                 }
             }
         }
     }


    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!