Sign in to follow this  
ddamicoAVI

XNA Framerate issue when using Spotlights

Recommended Posts

ddamicoAVI    140
I have a XNA application that’s fairly simple. Basically I draw a room with a few models inside. There are 4 spot lights in the room casting basic shadows. I have normal first person shooter controls that allow the camera to move around the room. Once I added multiple passes to the spot light technique the frame rate really dropped off. the additional passes are to replicate the spot light four times. I have alpha blending enabled for all the passes after the first one. I can't tell what the exact FPS is because when I draw the spritebatch objects disappear. I have a feeling it is due to the alpha blending... but that’s not my main concern now. What is the best way to analyze where the bottle neck is? I'm very new to all of this 3d rendering. What are some ways to improve frame rate? Is there anything that I'm doing that jumps out as being a big "No No" in game programming? EDIT: I used PIX for Windows and it appears my FPS is around 8. Here is the code I'm using to render room and lights:
        protected override void Draw(GameTime gameTime)
        {

            frameCounter++;

            Matrix rotationMatrix = Matrix.CreateRotationY(cameraYaw);

            Vector3 headOffset = Vector3.Transform(avatarHeadOffset, rotationMatrix);

            Vector3 cameraPosition = avatarPosition + headOffset;

            Vector3 transformedReference = Vector3.Transform(cameraReference, rotationMatrix);

            Vector3 cameraLookat = transformedReference + cameraPosition;

            Matrix slookAt = Matrix.CreateLookAt(cameraPosition, cameraLookat, Vector3.Up);
   
            graphics.GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Blue, 1.0f, 0);

            DrawObejcts("ShadowedScene", slookAt, buildingModel, Matrix.Identity, llookAt, lProjection);

            //DrawText();

            base.Draw(gameTime);

        }

        void DrawObejcts(string techniqueName, Matrix lookAt, Model model, Matrix world, Matrix[] lView, Matrix lProjection)
        {
            Matrix[] transforms = new Matrix[model.Bones.Count];
            model.CopyAbsoluteBoneTransformsTo(transforms);

            roomLighting.CurrentTechnique = roomLighting.Techniques[techniqueName];
            roomLighting.Parameters["View"].SetValue(lookAt);
            roomLighting.Parameters["LightView"].SetValue(lView);
            roomLighting.Parameters["LightProjection"].SetValue(lProjection);
            roomLighting.Parameters["Projection"].SetValue(Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), graphics.GraphicsDevice.Viewport.AspectRatio, 0.1f, 5000f));
            roomLighting.Parameters["lightPosition"].SetValue(lightPosition);
            roomLighting.Parameters["lightDirection"].SetValue(Vector3.Down);
            roomLighting.Parameters["phi"].SetValue(MathHelper.ToRadians(phi));
            roomLighting.Parameters["theta"].SetValue(MathHelper.ToRadians(theta));
            roomLighting.Parameters["cphi"].SetValue(Convert.ToSingle(Math.Cos(MathHelper.ToRadians(phi))));
            roomLighting.Parameters["ctheta"].SetValue(Convert.ToSingle(Math.Cos(MathHelper.ToRadians(theta))));
            roomLighting.Parameters["dimFactor"].SetValue(dimFactor);
            roomLighting.Parameters["lightsOn"].SetValue(lightsOn);
            roomLighting.Parameters["maxDepth"].SetValue(250.0f);
            roomLighting.Parameters["shadowMap0"].SetValue(shadowMaps[0]);
            roomLighting.Parameters["shadowMap1"].SetValue(shadowMaps[1]);
            roomLighting.Parameters["shadowMap2"].SetValue(shadowMaps[2]);
            roomLighting.Parameters["shadowMap3"].SetValue(shadowMaps[3]);



            int i = 0;
            roomLighting.Begin();
            foreach (ModelMesh mesh in model.Meshes)
            {
                roomLighting.Parameters["World"].SetValue(transforms[mesh.ParentBone.Index] * world);
                graphics.GraphicsDevice.Indices = mesh.IndexBuffer;

                if (techniqueName.Equals("SpotLight") || techniqueName.Equals("ShadowedScene"))
                {

                    foreach (Effect b in mesh.Effects)
                    {
                        roomLighting.Parameters["modelTexture"].SetValue((Texture2D)textures[i]);
                        i++;
                    }
                }


                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                {
                    graphics.GraphicsDevice.Vertices[0].SetSource(mesh.VertexBuffer, meshPart.StreamOffset, meshPart.VertexStride);
                    graphics.GraphicsDevice.VertexDeclaration = meshPart.VertexDeclaration;

                    foreach (EffectPass pass in roomLighting.CurrentTechnique.Passes)
                    {
                        pass.Begin();
                        graphics.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, meshPart.BaseVertex, 0, meshPart.NumVertices, meshPart.StartIndex, meshPart.PrimitiveCount);
                        pass.End();
                    }

                }
                mesh.Draw();
            }
            roomLighting.End();
        }


float4x4 World;
float4x4 View;
float4x4 Projection;
float4x4 LightView[4];
float4x4 LightProjection;

float3 lightPosition[4];
float3 lightDirection;
float phi;
float theta;
float dimFactor;
bool lightsOn; 

float cphi;
float ctheta;


// for shadows
float maxDepth;
texture modelTexture;
texture shadowMap0;
texture shadowMap1;
texture shadowMap2;
texture shadowMap3;

sampler ColoredTextureSampler = 
	sampler_state { texture = <modelTexture> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR;AddressU = wrap; AddressV = wrap;};
sampler ShadowMapSamplers[4] = {
	sampler_state { texture = <shadowMap0> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR;AddressU = clamp; AddressV = clamp;},
	sampler_state { texture = <shadowMap1> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR;AddressU = clamp; AddressV = clamp;},	
	sampler_state { texture = <shadowMap2> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR;AddressU = clamp; AddressV = clamp;},
	sampler_state { texture = <shadowMap3> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR;AddressU = clamp; AddressV = clamp;},
};


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

struct SScenePixelToFrame
{
    float4 Color				: COLOR0;
};

struct SSceneVertexInput
{
	float4 inPos				: POSITION;
	float2 inTexCoords			: TEXCOORD0;
	float3 inNormal				: NORMAL;
};
SSceneVertexToPixel ShadowedSceneVertexShader(SSceneVertexInput input, uniform int currentLight)
{
    SSceneVertexToPixel Output = (SSceneVertexToPixel)0;
    float4x4 wvp =  mul(mul(World, View), Projection);
    Output.Position = mul(input.inPos, wvp);


	float4x4 lwvp =  mul(mul(World, LightView[currentLight]), LightProjection);
	Output.ShadowMapSamplingPos = mul(input.inPos,lwvp );
	Output.RealDistance = Output.ShadowMapSamplingPos.z/maxDepth; 
    Output.Normal = normalize(mul(input.inNormal, (float3x3)World));
    Output.Position3D = mul(input.inPos, World);

    Output.TexCoords = input.inTexCoords;

    return Output;    
}

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

	float3 lightDir= normalize(lightDirection);
	float4 FinalColor = {0.0f,0.0f,0.0f,1.0f};
		Output.Color = FinalColor;

		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(ShadowMapSamplers[currentLight], ProjectedTexCoords).x;    
			if ((PSIn.RealDistance.x - 1.0f/100.0f) <= StoredDepthInShadowMap)    
			{						
				
				float4 ColorComponent = tex2D(ColoredTextureSampler, PSIn.TexCoords);	

				float3 lightVec = lightPosition[currentLight] - PSIn.Position3D.xyz;
				lightVec= normalize(lightVec);	
				float diffuse = dot(PSIn.Normal, lightVec);
				float cAlpha = dot(-lightDirection,lightVec);	
				if (cAlpha >= cphi && cAlpha <= ctheta)
				{
					FinalColor = CalculateFallOff(cAlpha) * ColorComponent;
				}
				else if (cAlpha >= ctheta)
				{
					FinalColor =  ColorComponent;
				}
				
				Output.Color = FinalColor * diffuse;     
			}       
		}    

	Output.Color.a = 1.0f;  
    return Output;
}

technique ShadowedScene
{
    pass Pass0
    {
		ALPHABLENDENABLE = false;
        VertexShader = compile vs_2_0 ShadowedSceneVertexShader(0);
        PixelShader = compile ps_2_0 ShadowedScenePixelShader(0);
    }
    pass Pass1
    {
		ALPHABLENDENABLE = true;
		SRCBLEND = one;
		DESTBLEND = one;
        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 ShadowedSceneVertexShader(3);
        PixelShader = compile ps_2_0 ShadowedScenePixelShader(3);
    }
}



[Edited by - ddamicoAVI on February 22, 2008 10:57:49 AM]

Share this post


Link to post
Share on other sites
jollyjeffers    1570
Depending on your hardware, you can probably look into using NVPerfHUD to dig into the performance characteristics. PIX isn't bad at this, but I've found it to be a better debugger than performance profiler in the past...

Having said that, you can use PIX to determine how much state-changing occurs per frame. Re-ordering the render sequence may well improve this and give you a more efficient API usage. For example, try ordering it by effect/pass rather than by model/modelpart.

hth
Jack

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this