6 Replies - 4047 Views - Last Post: 03 May 2013 - 09:21 AM

#1 rex64  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 164
  • Joined: 31-January 12

Custom XNA HLSL Shader Effects

Posted 05 February 2013 - 10:03 AM

I am attempting to understand how to perform custom HLSL Shader effects and mix them into our existing code.

We are using the content library with FBX models, and so I think the models may already have the textures inside that we need for specular lighting, and hopefully vertex modifiers. Here is the basic effect, I though that I should keep doing this loop like this and work with this effect?
foreach (BasicEffect effect in mesh.Effects)
{

}



List of objects:
3D Model - contains meshes with basic effects?
Basic Effect - should we use this anymore?
HLSL Shader Effect - this is what we want to use. Can we also stack other effects on top of this?

Is This A Good Question/Topic? 0
  • +

Replies To: Custom XNA HLSL Shader Effects

#2 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 533
  • View blog
  • Posts: 1,188
  • Joined: 24-April 12

Re: Custom XNA HLSL Shader Effects

Posted 06 February 2013 - 07:00 AM

I've been pretty much out of game programming for the past couple months and have not even looked at this code in months. So I don't even remember how it works off the top of my head. But I thought you might get some ideas out of it since it is working code.

I was trying to learn how to do lighting in HLSL. What I wanted to do was split the screen into 4 displays with each displaying the scene at a different rendering step in the process. The 3rd window pannel displays the actual scene, which for me was a car model from another tutorial (Riemer's I think). And a checkered floor tile. Simple scene, but I just wanted point lighting from an unlimited number of sources. This code was a success but I realized I still did not know how to do shadows.

I might mention that there were 3 .x models used. One for the car. One for the floor plane. And another is a sphere that represents where the light is to shine in the scene that is needed in the lighting calculations.

Anyway, here is some of my HLSL code:

using System;
using System.Collections.Generic;
using System.Linq;
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.Media;
using CameraNamespace;


namespace MultiPointLightSimplified
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        QuaternionCamera Camera;
        //HumanCamera Camera;
        Model FloorModel;
        Model CarModel;
        Matrix CarWorldMatrix;
        Model LightingMesh;
        KeyboardState PreviousKBState;
        Effect Shader;
        Effect SpriteEffect;
        Effect LightingEffect;
        Effect FinalRenderEffect;
        BasicEffect StandardShader;
        RenderTarget2D DepthMap;
        RenderTarget2D NormalMap;
        RenderTarget2D SpriteRenderTarget;
        RenderTarget2D LightingRenderTarget;
        Vector3 DiffuseColor = new Vector3(1f, 1f, 1f);
        private class MeshTag
        {
            public Vector3 Color {get; set;}
            public Texture2D Texture {get; set;}
            public float SpecularPower {get; set;}
            public Effect DepthNormalEffect { get; set; }
            public Effect StandardEffect { get; set; }
            
            public MeshTag()
            {
                
            }
        }
        private class PointLight
        {
            public Vector3 Position { get; set; }
            public Vector3 Color { get; set; }
            public float Attenuation { get; set; }

            public PointLight(Vector3 Position, Vector3 Color, float Attenuation)
            {
                this.Position = Position;
                this.Color = Color;
                this.Attenuation = Attenuation;
            }
        }
        List<PointLight> PointLights;


        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 720;

            graphics.IsFullScreen = false;
            Content.RootDirectory = "Content";
        }


        protected override void Initialize()
        {
            window.Title = "Multiple Point Lights"; //Your window's title displays in the top left corner in windowed mode.
            PresentationParameters pp = GraphicsDevice.PresentationParameters;

            Camera = new QuaternionCamera(this);
            //Camera = new HumanCamera(this);
            Components.Add(Camera);

            //Render Targets for calculations as well as the 4 viewports on the screen
            DepthMap = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, SurfaceFormat.Single, DepthFormat.Depth24);
            NormalMap = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);
            LightingRenderTarget = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);
            SpriteRenderTarget = new RenderTarget2D(GraphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);

            PointLights = new List<PointLight>() 
            {
                new PointLight(new Vector3(2f, 2.5f, 9f), Color.Red.ToVector3(), 20f),
                new PointLight(new Vector3(-4f, 2.5f, 11f), Color.Blue.ToVector3(), 20f),
                new PointLight(new Vector3(0f, 6f, 2f), Color.White.ToVector3(), 13f)
            };


            base.Initialize();
        }


        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            StandardShader = new BasicEffect(GraphicsDevice);
            Shader = Content.Load<Effect>("PPDepthNormal");
            SpriteEffect = Content.Load<Effect>("SpriteEffect");
            LightingEffect = Content.Load<Effect>("PPLight");
            FinalRenderEffect = Content.Load<Effect>("PPModel");
            FloorModel = LoadModel("Ground");
            CarModel = LoadModel("car");
            CarWorldMatrix = Matrix.CreateRotationY(MathHelper.PiOver2) * Matrix.CreateTranslation(0f, 0f, 10f);

            LightingMesh = Content.Load<Model>("PPLightMesh");
            LightingMesh.Meshes[0].MeshParts[0].Effect = LightingEffect;
        }


        private Model LoadModel(string assetName)
        {

            Model NewModel = Content.Load<Model>(assetName);
            

            foreach (ModelMesh Mesh in NewModel.Meshes)
                foreach (ModelMeshPart MeshPart in Mesh.MeshParts)
                {
                    BasicEffect OriginalShader = (BasicEffect)MeshPart.Effect;
                    MeshTag NewTag = new MeshTag(); 

                    NewTag.Color = OriginalShader.DiffuseColor;
                    NewTag.Texture = OriginalShader.Texture;
                    NewTag.SpecularPower = OriginalShader.SpecularPower;
                    NewTag.DepthNormalEffect = Shader.Clone();
                    NewTag.StandardEffect = FinalRenderEffect.Clone();

                    MeshPart.Effect = NewTag.StandardEffect;    //Initialize effect from BasicEffect to our custom effect
                    MeshPart.Tag = NewTag;
                }

            return NewModel;
        }


        protected override void UnloadContent()
        {

        }


        protected override void Update(GameTime gameTime)
        {
            KeyboardState KBState;
            Camera.VelocityPerFrame = 0f;
            Camera.YawPerFrame = 0f;

            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            KBState = Keyboard.GetState();
            if (KBState.IsKeyDown(Keys.Escape)) this.Exit();

            if (KBState.IsKeyDown(Keys.W) || KBState.IsKeyDown(Keys.Up)) Camera.VelocityPerFrame = Camera.VelocityPerFrame = 0.05f;
            if (KBState.IsKeyDown(Keys.S) || KBState.IsKeyDown(Keys.Down)) Camera.VelocityPerFrame = Camera.VelocityPerFrame = -0.05f;
            if (KBState.IsKeyDown(Keys.A) || KBState.IsKeyDown(Keys.Left) && !(KBState.IsKeyDown(Keys.LeftShift) || KBState.IsKeyDown(Keys.RightShift))) Camera.YawPerFrame = 0.03f;
            if (KBState.IsKeyDown(Keys.D) || KBState.IsKeyDown(Keys.Right) && !(KBState.IsKeyDown(Keys.LeftShift) || KBState.IsKeyDown(Keys.RightShift))) Camera.YawPerFrame = -0.03f;
            if (KBState.IsKeyDown(Keys.Q)) Camera.RollToPort();
            if (KBState.IsKeyDown(Keys.E)) Camera.RollToStarboard();
            if ((KBState.IsKeyDown(Keys.A) || KBState.IsKeyDown(Keys.Left)) && (KBState.IsKeyDown(Keys.LeftShift) || KBState.IsKeyDown(Keys.RightShift)))
            {
                Camera.StrafeLeft();
            }
            if ((KBState.IsKeyDown(Keys.D) || KBState.IsKeyDown(Keys.Right)) && (KBState.IsKeyDown(Keys.LeftShift) || KBState.IsKeyDown(Keys.RightShift)))
            {
                Camera.StrafeRight();
            }
            if (KBState.IsKeyDown(Keys.PageUp)) Camera.LookUp();
            if (KBState.IsKeyDown(Keys.PageDown)) Camera.LookDown();


            PreviousKBState = KBState;

            base.Update(gameTime);
        }


        private void DrawDepthNormal(GameTime gameTime)
        {
            //Assign the exact same instance of Shader to all parts because
            //for the Depth & Normals all parts will be drawn the same without textures.
            foreach (ModelMesh mesh in FloorModel.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    //Setup the effect for Depth and Normal mapping
                    meshPart.Effect = ((MeshTag)meshPart.Tag).DepthNormalEffect;

                    meshPart.Effect.CurrentTechnique = meshPart.Effect.Techniques["Technique1"];
                    meshPart.Effect.Parameters["World"].SetValue(Matrix.Identity);
                    meshPart.Effect.Parameters["View"].SetValue(Camera.ViewMatrix);
                    meshPart.Effect.Parameters["Projection"].SetValue(Camera.ProjectionMatrix);
                }
                mesh.Draw();
            }
            
            Matrix[] ModelTransforms = new Matrix[CarModel.Bones.Count];    //Tires are bones.
            CarModel.CopyAbsoluteBoneTransformsTo(ModelTransforms);
            foreach (ModelMesh Mesh in CarModel.Meshes)
            {
                foreach (ModelMeshPart Part in Mesh.MeshParts)
                {
                    //Setup the effect for Depth and Normal mapping
                    Part.Effect = ((MeshTag)Part.Tag).DepthNormalEffect;

                    Part.Effect.CurrentTechnique = Part.Effect.Techniques["Technique1"];
                    Part.Effect.Parameters["World"].SetValue(ModelTransforms[Mesh.ParentBone.Index] * CarWorldMatrix);
                    Part.Effect.Parameters["View"].SetValue(Camera.ViewMatrix);
                    Part.Effect.Parameters["Projection"].SetValue(Camera.ProjectionMatrix);
                }
                Mesh.Draw();  //Draw the mesh
            }

            //Revert back to the effect to be drawn on the screen
            foreach (ModelMesh mesh in FloorModel.Meshes)
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    meshPart.Effect = ((MeshTag)meshPart.Tag).StandardEffect;

            foreach (ModelMesh mesh in CarModel.Meshes)
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    meshPart.Effect = ((MeshTag)meshPart.Tag).StandardEffect;
        }


        private void DrawLightingEffect(GameTime gameTime)
        {
            Matrix WorldViewProjection;

            GraphicsDevice.SetRenderTarget(LightingRenderTarget);
            GraphicsDevice.Clear(Color.Black);
            GraphicsDevice.BlendState = BlendState.Additive;
            GraphicsDevice.DepthStencilState = DepthStencilState.None;

            foreach (PointLight Light in PointLights)
            {
                float dist = Vector3.Distance(Camera.PushHandle, Light.Position);    // Determine the distance between the light and camera

                // If the camera is inside the light-sphere, invert the cull mode
                // to draw the inside of the sphere instead of the outside
                if (dist < Light.Attenuation)
                {
                    GraphicsDevice.RasterizerState = RasterizerState.CullClockwise;
                }

                WorldViewProjection = (Matrix.CreateScale(Light.Attenuation) * Matrix.CreateTranslation(Light.Position)) * Camera.ViewMatrix * Camera.ProjectionMatrix;

                foreach (ModelMesh Mesh in LightingMesh.Meshes)
                {
                    foreach (ModelMeshPart Part in Mesh.MeshParts)
                    {
                        Effect MeshShader = Part.Effect;

                        MeshShader.CurrentTechnique = MeshShader.Techniques["Technique1"];
                        MeshShader.Parameters["WorldViewProjection"].SetValue(WorldViewProjection);
                        MeshShader.Parameters["InvViewProjection"].SetValue(Matrix.Invert(Camera.ViewMatrix * Camera.ProjectionMatrix));
                        MeshShader.Parameters["viewportWidth"].SetValue(GraphicsDevice.Viewport.Width);
                        MeshShader.Parameters["viewportHeight"].SetValue(GraphicsDevice.Viewport.Height);
                        MeshShader.Parameters["DepthTexture"].SetValue(DepthMap);
                        MeshShader.Parameters["NormalTexture"].SetValue(NormalMap);
                        MeshShader.Parameters["LightColor"].SetValue(Light.Color);
                        MeshShader.Parameters["LightPosition"].SetValue(Light.Position);
                        MeshShader.Parameters["LightAttenuation"].SetValue(Light.Attenuation);
                    }
                    Mesh.Draw();  //Draw the mesh
                }
            }
            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
            GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
            GraphicsDevice.SetRenderTarget(null);
        }

        private void DrawFinal(GameTime gameTime)
        {
            foreach (ModelMesh Mesh in FloorModel.Meshes)
            {
                foreach (ModelMeshPart Part in Mesh.MeshParts)
                {
                    Effect MeshShader = Part.Effect;

                    MeshShader.CurrentTechnique = MeshShader.Techniques["Technique1"];
                    MeshShader.Parameters["World"].SetValue(Matrix.Identity);
                    MeshShader.Parameters["View"].SetValue(Camera.ViewMatrix);
                    MeshShader.Parameters["Projection"].SetValue(Camera.ProjectionMatrix);
                    MeshShader.Parameters["viewportWidth"].SetValue(GraphicsDevice.Viewport.Width);
                    MeshShader.Parameters["viewportHeight"].SetValue(GraphicsDevice.Viewport.Height);
                    MeshShader.Parameters["TextureEnabled"].SetValue(true);
                    MeshShader.Parameters["BasicTexture"].SetValue(((MeshTag)Part.Tag).Texture);
                    MeshShader.Parameters["LightTexture"].SetValue(LightingRenderTarget);
                    MeshShader.Parameters["DiffuseColor"].SetValue(DiffuseColor);

                }
                Mesh.Draw();  //Draw the mesh
            }

            Matrix[] ModelTransforms = new Matrix[CarModel.Bones.Count];    //Tires are bones.
            CarModel.CopyAbsoluteBoneTransformsTo(ModelTransforms);
            foreach (ModelMesh Mesh in CarModel.Meshes)
            {
                foreach (ModelMeshPart Part in Mesh.MeshParts)
                {
                    Effect MeshShader = Part.Effect;

                    MeshShader.CurrentTechnique = MeshShader.Techniques["Technique1"];
                    MeshShader.Parameters["World"].SetValue(ModelTransforms[Mesh.ParentBone.Index] * CarWorldMatrix);
                    MeshShader.Parameters["View"].SetValue(Camera.ViewMatrix);
                    MeshShader.Parameters["Projection"].SetValue(Camera.ProjectionMatrix);
                    MeshShader.Parameters["viewportWidth"].SetValue(GraphicsDevice.Viewport.Width);
                    MeshShader.Parameters["viewportHeight"].SetValue(GraphicsDevice.Viewport.Height);
                    MeshShader.Parameters["TextureEnabled"].SetValue(true);
                    MeshShader.Parameters["BasicTexture"].SetValue(((MeshTag)Part.Tag).Texture);
                    MeshShader.Parameters["LightTexture"].SetValue(LightingRenderTarget);
                    MeshShader.Parameters["DiffuseColor"].SetValue(DiffuseColor);
                }
                Mesh.Draw();  //Draw the mesh
            }
        }


        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.SetRenderTargets(NormalMap, DepthMap);
            GraphicsDevice.Clear(Color.White);
            DrawDepthNormal(gameTime);
            GraphicsDevice.SetRenderTarget(null);

            DrawLightingEffect(gameTime);

            //base.Draw(gameTime);

            GraphicsDevice.SetRenderTarget(SpriteRenderTarget);
            GraphicsDevice.Clear(Color.Black);
            DrawFinal(gameTime);
            GraphicsDevice.SetRenderTarget(null);

            //DRAW ON SCREEN
            GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1.0f, 0);
            spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.Opaque, SamplerState.LinearClamp, DepthStencilState.Default,
                RasterizerState.CullCounterClockwise, SpriteEffect);

            GraphicsDevice.SamplerStates[0] = SamplerState.PointWrap;   //Absolutely required.

            spriteBatch.Draw(DepthMap, new Rectangle(0, 0, GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2), Color.White);
            spriteBatch.Draw(NormalMap, new Rectangle(GraphicsDevice.Viewport.Width / 2, 0, GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2), Color.White);
            spriteBatch.Draw(LightingRenderTarget, new Rectangle(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2, GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2), Color.White);
            spriteBatch.Draw(SpriteRenderTarget, new Rectangle(0, GraphicsDevice.Viewport.Height / 2, GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2), Color.White);

            spriteBatch.End();
            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;
        }


    }
}



This post has been edited by BBeck: 06 February 2013 - 07:09 AM

Was This Post Helpful? 0
  • +
  • -

#3 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 533
  • View blog
  • Posts: 1,188
  • Joined: 24-April 12

Re: Custom XNA HLSL Shader Effects

Posted 06 February 2013 - 07:10 AM

I might mention that this code and to a much greater degree the shaders were pieced together out of other peoples' code tutorials.

PPDepthNormal.fx
float4x4 World;
float4x4 View;
float4x4 Projection;

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float3 Normal : NORMAL0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 Depth : TEXCOORD0;
    float3 Normal : TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    float4x4 viewProjection = mul(View, Projection);
    float4x4 worldViewProjection = mul(World, viewProjection);
	    
    output.Position = mul(input.Position, worldViewProjection);
    output.Normal = mul(input.Normal, World);
    
    // Position's z and w components correspond to the distance
    // from camera and distance of the far plane respectively
    output.Depth.xy = output.Position.zw;

    return output;
}

// We render to two targets simultaneously, so we can't
// simply return a float4 from the pixel shader
struct PixelShaderOutput
{
	float4 Normal : COLOR0;
	float4 Depth : COLOR1;
};

PixelShaderOutput PixelShaderFunction(VertexShaderOutput input)
{
	PixelShaderOutput output;
	
	// Depth is stored as distance from camera / far plane distance
	// to get value between 0 and 1
	output.Depth = input.Depth.x / input.Depth.y;
	
	// Normal map simply stores X, Y and Z components of normal
	// shifted from (-1 to 1) range to (0 to 1) range
	output.Normal.xyz = (normalize(input.Normal).xyz / 2) + .5;
	
	// Other components must be initialized to compile
	output.Depth.a = 1;
	output.Normal.a = 1;
	
    return output;
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_1_1 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}




PPLight.fx
float4x4 WorldViewProjection;
float4x4 InvViewProjection;

texture2D DepthTexture;
texture2D NormalTexture;
sampler2D depthSampler = sampler_state { 
	texture = <DepthTexture>; 
	minfilter = point;
	magfilter = point;
	mipfilter = point;
};
sampler2D normalSampler = sampler_state { 
	texture = <NormalTexture>; 
	minfilter = point;
	magfilter = point;
	mipfilter = point;
};

float3 LightColor;
float3 LightPosition;
float LightAttenuation;
float LightFallOff = 2;

// Include shared functions
#include "PPShared.vsi"

struct VertexShaderInput
{
    float4 Position : POSITION0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float4 LightPosition : TEXCOORD0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    output.Position = mul(input.Position, WorldViewProjection);
    output.LightPosition = output.Position;
    
    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	// WRONG: Find the pixel coordinates of the input position in the depth
	// and normal textures
	// Find the 2D screen coordinates of any objects possibly affected
	// by the light sphere.
	float2 texCoord = postProjToScreen(input.LightPosition) + halfPixel();
	
	// Extract the depth for this pixel from the depth map
	// Get the depth of a surface possibly lit by the light sphere
	float4 depth = tex2D(depthSampler, texCoord);
	
	// Recreate the position with the UV coordinates and depth value
	float4 position;
	position.x = texCoord.x * 2 - 1;
	position.y = (1 - texCoord.y) * 2 - 1;
	position.z = depth.r;
	position.w = 1.0f;

	// Transform position from screen space to world space
	position = mul(position, InvViewProjection);
	position.xyz /= position.w;
	
	// Extract the normal from the normal map and move from
	// 0 to 1 range to -1 to 1 range
	float4 normal = (tex2D(normalSampler, texCoord) - .5) * 2;
		
	// Perform the lighting calculations for a point light
	float3 lightDirection = normalize(LightPosition - position);
	float lighting = clamp(dot(normal, lightDirection), 0, 1);
	
	// Attenuate the light to simulate a point light
	float d = distance(LightPosition, position);
	float att = 1 - pow(d / LightAttenuation, LightFallOff);
	
    return float4(LightColor * lighting * att, 1);
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_1_1 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}





PPModel.fx
float4x4 World;
float4x4 View;
float4x4 Projection;

texture2D BasicTexture;
sampler2D basicTextureSampler = sampler_state { 
	texture = <BasicTexture>; 
	addressU = wrap; 
	addressV = wrap; 
	minfilter = anisotropic;
	magfilter = anisotropic;
	mipfilter = linear;
};
bool TextureEnabled = true;

texture2D LightTexture;
sampler2D lightSampler = sampler_state { 
	texture = <LightTexture>;
	minfilter = point;
	magfilter = point;
	mipfilter = point;
};

float3 AmbientColor = float3(0.15, 0.15, 0.15);
float3 DiffuseColor;

#include "PPShared.vsi"

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float2 UV : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 UV : TEXCOORD0;
    float4 Positioncopy : TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
	VertexShaderOutput output;

	float4x4 worldViewProjection = mul(World, mul(View, Projection));
	
	output.Position = mul(input.Position, worldViewProjection);
	output.Positioncopy = output.Position;
    
	output.UV = input.UV;

	return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	// Sample model's texture
	float3 basicTexture = tex2D(basicTextureSampler, input.UV);
	
	if (!TextureEnabled)
		basicTexture = float4(1, 1, 1, 1);
		
	// Extract lighting value from light map
	float2 texCoord = postProjToScreen(input.Positioncopy) + halfPixel();
	float3 light = tex2D(lightSampler, texCoord);
	
	//Multiplied to tone down the ambient light
	light += (AmbientColor * 0.03);

	return float4(basicTexture * DiffuseColor * light, 1);
	//return float4(basicTexture * light, 1);
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_1_1 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}




SimpleEffect.fx
float4x4 World;
float4x4 View;
float4x4 Projection;


struct VertexShaderInput
{
    float4 Position : POSITION0;

};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output =(VertexShaderOutput)0;

    float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	float4 Output;

	Output = float4(1, 0, 0, 1);
    return Output;
}

technique SimpleTechnique
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}



SpriteEffect.fx
//------------------------------ TEXTURE PROPERTIES ----------------------------
// This is the texture that SpriteBatch will try to set before drawing
texture2D ScreenTexture;
 
// Our sampler for the texture, which is just going to be pretty simple
sampler TextureSampler = sampler_state
{
    Texture = <ScreenTexture>;

};
 
//------------------------ PIXEL SHADER ----------------------------------------
// This pixel shader will simply look up the color of the texture at the
// requested point
float4 PixelShaderFunction(float2 TextureCoordinate : TEXCOORD0) : COLOR0
{
  float4 color = tex2D(TextureSampler, TextureCoordinate);
 
    float4 outputColor = color;
    //outputColor.r = (color.r * 0.393) + (color.g * 0.769) + (color.b * 0.189);
    //outputColor.g = (color.r * 0.349) + (color.g * 0.686) + (color.b * 0.168);    
    //outputColor.b = (color.r * 0.272) + (color.g * 0.534) + (color.b * 0.131);
 
	
    //return outputColor;
	return color;


}
 
//-------------------------- TECHNIQUES ----------------------------------------
// This technique is pretty simple - only one pass, and only a pixel shader
technique Plain
{
    pass Pass1
    {
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}




I think with this Camera.cs file that's all the code for the whole thing:

using System;
using System.Collections.Generic;
using System.Linq;
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.Media;


namespace CameraNamespace
{
    /// This is a game component that implements IUpdateable.
    public abstract class Camera : Microsoft.Xna.Framework.GameComponent
    {
        protected Matrix View;            //ViewMatrix
        protected Matrix Projection;      //Projection Matrix
        protected Vector3 Handle;         //Used to control the camera's "position".
        protected Vector3 HandleFacing;   //Direction Handle of camera faces.
        protected float Velocity;       //Speed that the camera is moving at.
        protected float Yaw;                //Rotational velocity of the camera.
        protected float EyeLevel = 1.75f;

        public Matrix ViewMatrix
        {
            get { return View; }
        }


        public Matrix ProjectionMatrix
        {
            get {return Projection;}

        }


        public Vector3 PushHandle
        {
            get { return Handle; }
        }


        public virtual float VelocityPerFrame
        {
            get { return Velocity; }
            set { Velocity = value; }
        }


        public float YawPerFrame
        {
            get { return Yaw; }
            set { Yaw = value; }
        }


        public Camera(Game game)
            : base(game)
        {
            Handle = new Vector3(0f, 0f, 0f);
            HandleFacing = new Vector3(0f, 0f, 1f);
            Velocity = 0f;
            Yaw = 0f;
        }


        public abstract void StrafeLeft();


        public abstract void StrafeRight();


        public abstract void RollToPort();


        public abstract void RollToStarboard();


        public abstract void LookUp();


        public abstract void LookDown();


        public override void Initialize()
        {
            base.Initialize();
        }


        public override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }
    }



    public class HumanCamera : Camera
    {
        //private float EyeLevel = 1.75f;
        private float Pitch = 0f;   //Used to pitch the view up and down.


        public HumanCamera(Game game) : base(game)
        {
        }


        public override void Initialize()
        {
            Handle = new Vector3(0f, EyeLevel, 0f);
            HandleFacing = new Vector3(0f, 0f, 1f);
            View = Matrix.CreateLookAt(Handle, Handle+HandleFacing, Vector3.Up);
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Game.GraphicsDevice.Viewport.AspectRatio, 0.1f, 2000f);

            base.Initialize();
        }


        public override void StrafeLeft()
        {
            Matrix YRotation = Matrix.Identity;
            Vector3 LeftFacing;


            YRotation = Matrix.CreateRotationY(MathHelper.PiOver2);     //90 Degree rotation
            LeftFacing = Vector3.Transform(HandleFacing, YRotation);
            Handle += LeftFacing * 0.03f;    //0.3 meters per frame.
        }



        public override void StrafeRight()
        {
            Matrix YRotation = Matrix.Identity;
            Vector3 RightFacing;


            YRotation = Matrix.CreateRotationY(-MathHelper.PiOver2);     //90 Degree rotation
            RightFacing = Vector3.Transform(HandleFacing, YRotation);
            Handle += RightFacing * 0.03f;    //0.3 meters per frame.
        }


        public override void RollToPort()
        {

        }


        public override void RollToStarboard()
        {

        }


        public override void LookUp()
        //===================================================================================
        // LookUp()
        //
        // Purpose: Turns the character's head upwards.
        // Parameters:
        // DependsOn: 
        // Returns: void
        //
        // Notes: 
        //===================================================================================
        {
            Pitch += 0.01f;
            if (Pitch > MathHelper.PiOver4)
            {
                Pitch = MathHelper.PiOver4;
            }
        }
        //===================================================================================


        public override void LookDown()
        //===================================================================================
        // LookDown()
        //
        // Purpose: Turns the character's head downwards.
        // Parameters:  
        // DependsOn: 
        // Returns: void
        //
        // Notes: 
        //===================================================================================
        {
            Pitch -= 0.01f;
            if (Pitch < -MathHelper.PiOver4)
            {
                Pitch = -MathHelper.PiOver4;
            }
        }
        //===================================================================================


        public override void Update(GameTime gameTime)
        {
            Matrix YRotation = Matrix.Identity;
            Matrix PitchRotation = Matrix.Identity;
            Vector3 RightFacing;
            Vector3 LookAt;


            YRotation = Matrix.CreateRotationY(Yaw);
            Handle += HandleFacing * Velocity;
            HandleFacing = Vector3.Transform(HandleFacing, YRotation);
            RightFacing = Vector3.Cross(HandleFacing, Vector3.Up);
            PitchRotation = Matrix.CreateFromAxisAngle(RightFacing, Pitch);    //Now we can pitch with the right vector.
            LookAt = HandleFacing;
            LookAt = Vector3.Transform(LookAt, PitchRotation);  //Apply Pitch rotation.
            View = Matrix.CreateLookAt(Handle, Handle + LookAt, Vector3.Up);
                        
            base.Update(gameTime);
        }
    }



    public class QuaternionCamera : Camera
    {
        Quaternion Orientation;


        public QuaternionCamera(Game game) : base(game)
        {
        }


        public new float YawPerFrame
        {
            //get { return Yaw; }
            set { Orientation *= Quaternion.CreateFromYawPitchRoll(value, 0f, 0f); }
        }


        public override void StrafeLeft()
        {
            Handle += Vector3.Transform(HandleFacing, Matrix.CreateFromQuaternion(Orientation * Quaternion.CreateFromYawPitchRoll(MathHelper.ToRadians(90), 0f, 0f))) * 0.05f;
        }


        public override void StrafeRight()
        {
            Handle += Vector3.Transform(HandleFacing, Matrix.CreateFromQuaternion(Orientation * Quaternion.CreateFromYawPitchRoll(-MathHelper.PiOver2, 0f, 0f))) * 0.05f;
        }


        public override void RollToPort()
        {
            Orientation *= Quaternion.CreateFromYawPitchRoll(0f, 0f, (float)(Math.PI / 180f));
        }


        public override void RollToStarboard()
        {
            Orientation *= Quaternion.CreateFromYawPitchRoll(0f, 0f, (float)-(Math.PI / 180f));
        }
        

        public override void LookUp()
        {
            Quaternion PitchUpQuaternion;


            PitchUpQuaternion = Quaternion.CreateFromYawPitchRoll(0f,(float) (Math.PI / 180f), 0f);  //One degree of pitch.
            Orientation *= PitchUpQuaternion;
        }


        public override void LookDown()
        {
            Quaternion PitchDownQuaternion;

            PitchDownQuaternion = Quaternion.CreateFromYawPitchRoll(0f, (float)-(Math.PI / 180f), 0f);  //One degree of pitch.
            Orientation *= PitchDownQuaternion;
        }


        public override void Initialize()
        {
            Orientation = Quaternion.Identity;  //Empty Unit Quaternion.
            //Handle = new Vector3(0f, 0.5f, 0f);
            Handle = new Vector3(0f, EyeLevel, 0f);
            HandleFacing = new Vector3(0f, 0f, -1f); 
            Orientation *= Quaternion.CreateFromYawPitchRoll(MathHelper.Pi, 0f, 0f);
            View = Matrix.Invert(Matrix.CreateFromQuaternion(Orientation) * Matrix.CreateTranslation(Handle));
            Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, Game.GraphicsDevice.Viewport.AspectRatio, 0.1f, 2000f);

            base.Initialize();
        }


        public override void Update(GameTime gameTime)
        {
            Handle += (Vector3.Transform(HandleFacing, Matrix.CreateFromQuaternion(Orientation)) * Velocity);
            View = Matrix.Invert(Matrix.CreateFromQuaternion(Orientation) * Matrix.CreateTranslation(Handle));

            base.Update(gameTime);
        }
    }
}


Was This Post Helpful? 0
  • +
  • -

#4 rex64  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 164
  • Joined: 31-January 12

Re: Custom XNA HLSL Shader Effects

Posted 08 February 2013 - 03:03 PM

That sounds like a cool way to learn this (with multiple displays). Anyways, can you post the solution? I have been working on understanding this and adapting code to work better with this setup. Thanks!
Was This Post Helpful? 0
  • +
  • -

#5 rex64  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 164
  • Joined: 31-January 12

Re: Custom XNA HLSL Shader Effects

Posted 20 February 2013 - 06:45 PM

I am getting an error about a missing file. Also, I have created a solution and tried to attach it, but ZIP files do not seem to work even when they do not contain EXEs.

Also, what is this for?
NewTag.StandardEffect = FinalRenderEffect.Clone(); //TODO: We need this?

My Error:
Error	1	Errors compiling C:\Users\Jeff\Documents\Visual Studio 2010\Projects\HLSL Shader Multi Effects\HLSL Shader Multi Effects\HLSL Shader Multi EffectsContent\PPLight.fx:
C:\Users\Jeff\Documents\Visual Studio 2010\Projects\HLSL Shader Multi Effects\HLSL Shader Multi Effects\HLSL Shader Multi EffectsContent\PPLight.fx(25,10): error X1507: failed to open source file: 'PPShared.vsi'	C:\Users\Jeff\Documents\Visual Studio 2010\Projects\HLSL Shader Multi Effects\HLSL Shader Multi Effects\HLSL Shader Multi EffectsContent\PPLight.fx	25	10	HLSL Shader Multi Effects


This post has been edited by rex64: 20 February 2013 - 06:48 PM

Was This Post Helpful? 0
  • +
  • -

#6 rex64  Icon User is offline

  • D.I.C Head

Reputation: 6
  • View blog
  • Posts: 164
  • Joined: 31-January 12

Re: Custom XNA HLSL Shader Effects

Posted 02 May 2013 - 03:21 PM

Can you post the full solution somewhere? Also, please see the last post.
Was This Post Helpful? 0
  • +
  • -

#7 BBeck  Icon User is offline

  • Here to help.
  • member icon


Reputation: 533
  • View blog
  • Posts: 1,188
  • Joined: 24-April 12

Re: Custom XNA HLSL Shader Effects

Posted 03 May 2013 - 09:21 AM

I posted the full code as my "Multiple Point Lights" example about a week ago.

http://virtuallyprog...ndTutorial.html

If it's in that code, it's almost certainly a requirement. On that example, I specifically tried to cut it down to the minimum code necessary, because the code examples I was working from were extremely convoluted.

It's been a long time since I've looked at that code, but as I remember that section is storing the Shader/Effect information inside of each model part. XNA does not allow you to do this even though it's almost a requirement to make this stuff work. So, you have to use the "tag" in the model and expand it with your own variables to store the shader information. If I remember correctly, this is because one part of the model may have multiple shaders drawing it and you have to be able to go back to the original shader/effect when you're done for the next frame.

I'm pretty sure cloning was an absolute requirement. I'm thinking it had something to do with "pointers" and the need to make a completely seperate copy of the object as opposed to simply using the existing object.

But the full working code is on my website now. It's the entire project with all of the files in the project. You should be able to just unzip it, open the solution, and run it. And of course there's full source code.

There are other pieces of example code on my website now too.

And you may want to check it again here this weekend and next weekend; I'm currently working on "water". It's basically the same thing as Riemer's terrain example with water (in fact I'm using that to learn how to do it). But I don't think Riemer's example has been converted to XNA 4.0 and my code is 4.0 code. I think my code is also easier and more straight forward. My terrain example on my website is likewise 4.0, more straight forward, and includes terrain collision.

Right now my "water" code draws a skybox, a basic textured terrain, and has an "ocean" of liquid reflection (like mercury). It's just a quad (square) with a "liquid reflection" shader applied. Also, unlike Riemers, I used Basic Effect for the terrain and skybox and only used the custom shader for the "water".

To turn it into water, instead of mercury, I need to add transparency, refraction, and maybe some tint. I hope to do that this weekend and plan on posting the code for all that on the same webpage as the multi-point light example soon.

I decided not to continue doing tutorials in XNA, but figured I would post my code anyway. And I also decided recently to finish learning how to do some of the stuff that I did not already know how to do like water and I hope to figure out annimation in the not too distant future (although I'm also thinking of playing some Skyrim, which tends to make me forget about working on my own projects). :-)

Incidentally, I figured out how to do multiple point lights from several different sources, including my XNA books. But I got a lot of ideas and techniques from RB Whitiker's site. Specifically, I know I got the split screen technique from him that allowed me to split the screen into 4 displays. So, it's definitely worth the time to go through his stuff.

This post has been edited by BBeck: 03 May 2013 - 09:35 AM

Was This Post Helpful? 0
  • +
  • -

Page 1 of 1