Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Problems with Blending Images XNA 3.1


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
12 replies to this topic

#1 Nokame   Members   -  Reputation: 153

Like
0Likes
Like

Posted 02 April 2012 - 05:26 PM

Hi there,
I've been working on a 2D tile-based game. The whole thing is created in C#, XNA 3.1 and uses spritebatch to draw everything. Lately I've been trying to add a bit of depth to the game with some basic lighting technique that blends images over the current map. This seemed to work nicely at first, but then I realized that after the game has been running for a few minutes the FPS drops by half or more, and begins to run sluggishly. Also note, the only time the FPS drops is when the lighting is on, and when i turn the lighting off... the FPS jumps right back up to 60.

I've attatched a screenshot that shows what the lighting looks like, and what it looks like without. I'm at a loss. I can't figure out why it begins to run sluggishly... Any help/suggestions would be appreciated.

			DrawToRenderTarget...()
		    {
				 this.GraphicsDevice.SetRenderTarget(0, this.region.lightMap);
		   
				 //clear to some small ambient light
				 this.GraphicsDevice.Clear(this.region.ambience);
		   
				 //where Alpha is 0, nothing will be written
				 this.spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
		   
				 this.spriteBatch.GraphicsDevice.RenderState.DestinationBlend = Blend.One;
				 this.spriteBatch.GraphicsDevice.RenderState.SourceBlend = Blend.DestinationAlpha;
				 this.spriteBatch.GraphicsDevice.RenderState.BlendFunction = BlendFunction.Add;
				 this.spriteBatch.GraphicsDevice.RenderState.SeparateAlphaBlendEnabled = true;

				 foreach (LightSource light in this.region.regionLightSourceInstances)
				 {
						light.Draw(this.spriteBatch);	   
				 }
				 this.spriteBatch.End();
				 this.GraphicsDevice.SetRenderTarget(0, null);
	    }

Thank you.

Attached Files

  • Attached File  SC-1.bmp   659.23KB   30 downloads


Sponsor:

#2 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 03 April 2012 - 01:43 PM

I don’t fully understand what you are doing. Particularly the line: light.Draw(this.spriteBatch);

However, the SpriteSortMode.Immediate could be changed to reduce draw calls, and the saveStateMode.SaveState could be avoided at the expense of some extra lines of code (http://blogs.msdn.com/b/shawnhar/archive/2006/11/13/spritebatch-and-renderstates.aspx).

Good luck!!!

Project page: < XNA FINAL Engine >


#3 Nokame   Members   -  Reputation: 153

Like
0Likes
Like

Posted 03 April 2012 - 02:05 PM

First of all, thank you for the response. I'll look into those suggestions. Sorry if the post was a bit vague. The "DrawToRenderTarget()" method shown above renders a 'lightmap' to a RenderTarget2D object. It clears the surface to the "ambience" color, then all the lights, which are just images, are drawn onto the RenderTarget.

So the line: light.Draw(this.spriteBatch);

just means...

spriteBatch.Draw(lightTexture, position, null, color, 0, center, scale, SpriteEffects.None, 1);

Once the RenderTarget2D object is "filled" i use the following code to Draw it to the screen, after everything else has been drawn (that I want "light" to fall on):

					   // Draw lightmap over everything
					    this.spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);

					    this.spriteBatch.GraphicsDevice.RenderState.SourceBlend = this.region.sourceBlendType;
					    this.spriteBatch.GraphicsDevice.RenderState.DestinationBlend = this.region.destBlendType;
					    this.spriteBatch.GraphicsDevice.RenderState.BlendFunction = this.region.blendFunction;

					    this.spriteBatch.Draw(this.region.lightMap.GetTexture(), Vector2.Zero, Color.White);

					    this.spriteBatch.End();

Note: this.region.lightMap is the RenderTarget2D object. I suppose it's also worth mentioning that I've messed around with the RenderStates, BlendModes, SaveStateModes and the lighting effect is either skewed too much to be useful, or still causes the game to run sluggishly.

I hope this made the question more clear.

#4 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 03 April 2012 - 02:41 PM

I don’t see anything that could provoke your problem. Are you sure that the problem is there?

You said: “the only time the FPS drops is when the lighting is on”. Do you call/do anything else?

The GPU memory is not managed, that means you can potentially have a leak. But I don’t see it in your code. Do you create some asset (shader, texture, render target, etc.) every frame?

Project page: < XNA FINAL Engine >


#5 Nokame   Members   -  Reputation: 153

Like
0Likes
Like

Posted 03 April 2012 - 03:38 PM

I create that lightmap (RenderTarget2D) every frame because the background scrolls and it moves the lights onto the screen. Should I find a way to create a large lightmap once and then pull portions from it every frame?

#6 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 03 April 2012 - 04:11 PM

That's the problem!!


The render targets are stored in the GPU memory in an unmanaged way. If the dispose method is not called then a memory portion will be reserved for this render target. Moreover creating a render target each frame even if you destroy the old one is a bad practice. You have to reuse it.

Project page: < XNA FINAL Engine >


#7 Nokame   Members   -  Reputation: 153

Like
0Likes
Like

Posted 03 April 2012 - 04:49 PM

Well, I messed up. I actually do just reuse the RenderTarget2Ds by drawing on them every frame, i dont reinitialize them every frame, just redraw. Sorry about that.

#8 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 03 April 2012 - 04:56 PM

Can you paste the creation method? I want to see how you create the assets (sprite batch, render targets, etc.).

Project page: < XNA FINAL Engine >


#9 Nokame   Members   -  Reputation: 153

Like
0Likes
Like

Posted 03 April 2012 - 07:10 PM

:) you're being very helpful, let me say that i appreciate this.

At initialization spritebatch is loaded.

this.spriteBatch = new SpriteBatch(this.GraphicsDevice);

and during initialization the following is called when a map is loaded.

		    PresentationParameters pp = device.PresentationParameters;

			// This RenderTarget2D object holds the map (or region) and all sprites.
		    region.regionSurface = new RenderTarget2D(device, pp.BackBufferWidth, pp.BackBufferHeight, 1, SurfaceFormat.Color, pp.MultiSampleType, pp.MultiSampleQuality);
		   
		    // This RenderTarget2D object holdes the "lightmap".
		    region.lightMap = new RenderTarget2D(device, pp.BackBufferWidth, pp.BackBufferHeight, 1, SurfaceFormat.Color, pp.MultiSampleType, pp.MultiSampleQuality);

then for the textures of all the lighting is loaded (also at initialization) is as follows:

					// Get the light texture images
				    int numberOfTextureObjects = Convert.ToInt32(temp[count]); count++;
				    for (int i = 0; i < numberOfTextureObjects; i++)
				    {
					    // Create a list of textures and filenames
					    region.regionLightSourceTextures.Add(Content.Load<Texture2D>("Lighting\\" + temp[count].Trim()));
					    region.regionLightSourceTextureFileName.Add(temp[count].Trim()); count++;
				    }

				    // Get the number of LightSource instances on the map
				    int numberOfLightInstances = Convert.ToInt32(temp[count]); count++;
				    for (int i = 0; i < numberOfLightInstances; i++)
				    {
					    // Create a list of LightSources.
					    //

					    // Get the index of our texture list for the image to be used
					    int imageIndex = Convert.ToInt32(temp[count]); count++;
					    region.regionLightSourceInstanceTextureIndex.Add(imageIndex);

					    // Get the color of the light
					    Color color = Region.GetColor(temp[count]); count++;

					    // Get the size of the light
					    float range = (float)Convert.ToDouble(temp[count]); count++;

					    // Get the location of the light on the map.
					    int x = Convert.ToInt32(temp[count]); count++;
					    int y = Convert.ToInt32(temp[count]); count++;
					    Vector2 location = new Vector2(x, y);

					    // Distance
					    if (temp[count].ToUpper().Trim().Equals("DISTANCE"))
					    {
						    count++;

						    // Get the distance
						    float distance = (float)Convert.ToDouble(temp[count]); count++;

						    // Add the light source
						    region.regionLightSourceInstances.Add(new LightSource(region.regionLightSourceTextures[imageIndex], color, range, location, distance));
					    }
					    else
					    {
						    region.regionLightSourceInstances.Add(new LightSource(region.regionLightSourceTextures[imageIndex], color, range, location));
					    }
				    }

the code above is part of a method that loads a map from a text file. As far as the lighting goes, it copies a Texture2D object from a list of possible textures to a new lighting instance, which is then added to a map's (or region's) list of light sources. The lighting textures aren't instanced, rather they are copied. Each lightsource has it's own texture2d object. I would think the non-instancing part as troubling, but some of the maps only have a few lights going, and still have the eventual reduction in FPS. These are all the assets i can think of. There are primitives on the map, but those work fine while the lighting is turned off.

again, thanks for the back and forth.

#10 Nokame   Members   -  Reputation: 153

Like
0Likes
Like

Posted 03 April 2012 - 07:50 PM

I figured i'd give you the whole draw method as well... The following code is called during the draw function. The lightmap rendertarget is created (as discussed) and the map is all drawn onto a rendertarget then drawn to the screen... THEN the lightmap is drawn over the map.

					    this.DrawLightMapToRenderTarget();	 // This is the function i first posted.

					    this.GraphicsDevice.SetRenderTarget(0, this.region.regionSurface);
					    this.GraphicsDevice.Clear(Color.Black);

					    this.spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.FrontToBack, SaveStateMode.None);
					   
						 #region Draw Player, Character, and Map (The Map's Colored image)
					    //////////////////////////////////////////////////////////
											  
						// Draw MAP
					    this.DrawRegionTEST(this.region, this.player, this.region.characterList, gameTime);
					   
						// Draw Region's Characters
					    this.DrawCharacters(this.player, this.region.characterList, gameTime);
					   
						// Draw Player
					    this.DrawPlayer(this.player, gameTime);

					    //////////////////////////////////////////////////////////
					    #endregion

					    this.spriteBatch.End();

					    this.GraphicsDevice.SetRenderTarget(0, null);
					    this.GraphicsDevice.Clear(Color.Black);

						// Draw the region and characters.
					    this.spriteBatch.Begin();
					    this.spriteBatch.Draw(this.region.regionSurface.GetTexture(), new Vector2(), Color.White);
					    this.spriteBatch.End();

					    // Draw lightmap over all the textures
					    this.spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Immediate, SaveStateMode.SaveState);
						
					    this.spriteBatch.GraphicsDevice.RenderState.SourceBlend = this.region.sourceBlendType;
					    this.spriteBatch.GraphicsDevice.RenderState.DestinationBlend = this.region.destBlendType;
					    this.spriteBatch.GraphicsDevice.RenderState.BlendFunction = this.region.blendFunction;

					    this.spriteBatch.Draw(this.region.lightMap.GetTexture(), Vector2.Zero, Color.White);

					    this.spriteBatch.End();


#11 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 03 April 2012 - 07:59 PM

You are welcome!

Be careful, the last parameter in the RenderTarget2D constructor is the usage, not multisampling. If the application runs in the XBOX or in some PC GPUs then preserve contents could be a problem.

Edit: Sorry, my mistake. Your value is ok.

Project page: < XNA FINAL Engine >


#12 jischneider   Members   -  Reputation: 252

Like
0Likes
Like

Posted 03 April 2012 - 08:23 PM

Ok. I’m dry. Sorry :(

At this point I can only recommend that you calculate the illumination but don’t do the drawing. Then comment another part of the code and so on until you find the answer.

Good luck!!

Project page: < XNA FINAL Engine >


#13 Nokame   Members   -  Reputation: 153

Like
0Likes
Like

Posted 03 April 2012 - 10:37 PM

I agree. It's time to go through it thoroughly. I've been thinking that since this code seems to be done correctly, it's increase in processing power is shedding light on another problem... which i'm excited about.... *sigh*. Anyways, thank you very much for helping me up to this point. Having another voice on the matter has put things into perspective. *closes post*




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS