Using XNA RenderTargets

Started by
5 comments, last by Subliminalman 12 years, 6 months ago
Hi everyone! I'm working on what I call a ViewFinder for my game which acts much like the little "viewers" in Super Smash Bros. when your character goes off screen so you can still see them.




I am having a few problems though

  1. My background stops being drawn.
  2. My Character does not animate within the ViewFinder.
  3. Only one ViewFinder will be drawn at a time.
I think it's with how I use RenderTargets within the ViewFinder class and not anywhere else in the Drawing Code. Since I'm still fairly new to RenderTargets and not drawing to the BackBuffer I'm a little at a loss.

Any help would be appreciated thanks :D

Advertisement
Rendertarget usage can get a bit tricky, if you haven't already you should probably read this and this. If you were more specific (e.g. show some code) you may get some more specific help.
Here's my ViewFinder Class, I tried to make it as self contained as possible but that may be the problem. I will also post up my draw code in the main game loop.

ViewFinder



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace ImFalling
{
class ViewFinder
{
#region Variables
public bool isAlive = true;
private float yPosition;
private float seeRadius;
private Point frameSize;
private SpriteEffects spriteEffect = SpriteEffects.None;
private Vector2 position;
private Color viewFinderColor;
private Matrix camera;
private Camera2d cam;
private Effect mask;
private Texture2D pointer;
private Texture2D lens;
private Texture2D pointRender;
private Texture2D maskTexture;
private Texture2D texture;
private RenderTarget2D renderTarget;
private GraphicsDevice graphicsDevice;
public PlayerIndex playerIndex;
private FallingMan cat;
static public bool[] playerView = new bool[4];

#endregion

#region Constructors
public ViewFinder(Game game,Vector2 position, Texture2D texture, Point frameSize, Color viewFinderColor, GraphicsDevice graphicsDevice, PlayerIndex playerIndex)
{
mask = game.Content.Load<Effect>(@"Shaders\viewMask");
pointer = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\pointer");
lens = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\lens");
maskTexture = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\mask");
cam = new Camera2d();
cam.Zoom = 3;
this.position = position;
this.viewFinderColor = viewFinderColor;
this.texture = texture;
this.frameSize = frameSize;
seeRadius = this.frameSize.X;
this.graphicsDevice = graphicsDevice;
PresentationParameters pp = graphicsDevice.PresentationParameters;
renderTarget = new RenderTarget2D(graphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, graphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
this.playerIndex = playerIndex;

}


public ViewFinder(Game game, FallingMan cat, GraphicsDevice graphicsDevice)
{
mask = game.Content.Load<Effect>(@"Shaders\viewMask");
pointer = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\pointer");
lens = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\lens");
maskTexture = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\mask");
cam = new Camera2d();
cam.Zoom = 3;
position = cat.position;
viewFinderColor = cat.color;
texture = cat.texture;
seeRadius = cat.frameSize.X;
this.graphicsDevice = graphicsDevice;
playerIndex = cat.p;
this.cat = cat;
PresentationParameters pp = graphicsDevice.PresentationParameters;
renderTarget = new RenderTarget2D(graphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, graphicsDevice.DisplayMode.Format, DepthFormat.Depth24);

Console.WriteLine();
for(int i = 0; i < 4; i++)
Console.Write(playerView);

}

#endregion

#region Update
public void Update(GameTime gameTime, Vector2 position, Matrix camera)
{
this.position = position;

cam.position.X = position.X - (frameSize.X / 2);
cam.position.Y = position.Y - (frameSize.Y / 2);


this.camera = camera;

}
#endregion

#region Draw
public void Draw(GameTime gameTime, SpriteBatch spriteBatch, params Object[] objects)
{

//Draw either on top or on bottom of the screen


if (position.Y < camera.Translation.Y)
{
yPosition = 10;
spriteEffect = SpriteEffects.FlipVertically;
}
else if (position.Y > camera.Translation.Y + graphicsDevice.Viewport.Height)
{
yPosition = graphicsDevice.Viewport.Height - pointer.Height;
}
//Draw the off screen action


mask.CurrentTechnique = mask.Techniques["Technique1"];
graphicsDevice.SetRenderTarget(renderTarget);

graphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };

// Draw the scene
graphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, cam.get_transformation(graphicsDevice));

if (cat == null)
{
spriteBatch.Draw(texture, new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height), Color.White);
}
else
{
spriteBatch.Draw(texture, cat.position, new Rectangle(cat.currentFrame.X * frameSize.X, cat.currentFrame.Y * frameSize.Y, cat.frameSize.X, cat.frameSize.Y),
Color.White, cat.rotation, Vector2.Zero, cat.scale, cat.flip, 0);
//Console.WriteLine(cat.currentFrame);
}

foreach (Object obj in objects)
{

if (obj is List<Platform>)
{
foreach (Platform platform in ((List<Platform>)obj))
{
if (Math.Abs(platform.position.X - position.X) < seeRadius && Math.Abs(platform.position.Y - position.Y) < seeRadius)
{
platform.Draw(gameTime, spriteBatch);
}
}
}

else if (obj is List<PowerUp>)
{
foreach (PowerUp powerUp in ((List<PowerUp>)obj))
{
if (Math.Abs(powerUp.position.X - position.X) < seeRadius && Math.Abs(powerUp.position.Y - position.Y) < seeRadius)
{
powerUp.Draw(gameTime, spriteBatch);
}
}
}
else if (obj is List<Airplane>)
{
foreach (Airplane airPlane in ((List<Airplane>)obj))
{
if (Math.Abs(airPlane.position.X - position.X) < seeRadius && Math.Abs(airPlane.position.Y - position.Y) < seeRadius)
{
airPlane.Draw(gameTime, spriteBatch);
}
}
}
else if (obj is List<Bird>)
{
foreach (Bird bird in ((List<Bird>)obj))
{
if (Math.Abs(bird.position.X - position.X) < seeRadius && Math.Abs(bird.position.Y - position.Y) < seeRadius)
{
bird.Draw(gameTime, spriteBatch);
}
}
}
else if (obj is List<Fan>)
{
foreach (Fan fan in ((List<Fan>)obj))
{
if (Math.Abs(fan.position.X - position.X) < seeRadius && Math.Abs(fan.position.Y - position.Y) < seeRadius)
{
fan.Draw(gameTime, spriteBatch);
}
}
}
else if (obj is List<Cloud>)
{
foreach (Cloud cloud in ((List<Cloud>)obj))
{
if (Math.Abs(cloud.position.X - position.X) < seeRadius && Math.Abs(cloud.position.Y - position.Y) < seeRadius)
{
cloud.Draw(gameTime, spriteBatch);
}
}
}

else if (obj is List<FallingMan>)
{
foreach (FallingMan kitty in ((List<FallingMan>)obj))
{
if (Math.Abs(kitty.position.X - position.X) < seeRadius && Math.Abs(kitty.position.Y - position.Y) < seeRadius && kitty.p != playerIndex)
{
kitty.Draw(gameTime, spriteBatch);
}
}
}
}


spriteBatch.End();

graphicsDevice.SetRenderTarget(null);
pointRender = (Texture2D)renderTarget;
graphicsDevice.Clear(Color.CornflowerBlue);

//Draw the scene to the screen and apply the mask to make it circular




spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, mask, camera);
mask.Parameters["spherePort"].SetValue(pointRender);
mask.Parameters["mask"].SetValue(maskTexture);
spriteBatch.Draw(pointRender, new Rectangle((int)position.X, (int)yPosition - (int)camera.Translation.Y, 100, 100), Color.White);
spriteBatch.End();


//Draw the actual ViewFinder

spriteBatch.Begin();
spriteBatch.Draw(pointer, new Vector2(position.X, yPosition), null, viewFinderColor, 0.0f, Vector2.Zero, 1.0f, spriteEffect, 0.1f);
//spriteBatch.Draw(lens, new Vector2(position.X, yPosition), null, Color.White, 0.0f, Vector2.Zero, 1.0f, SpriteEffects.None, 0.0f);
spriteBatch.Draw(lens, new Rectangle((int)position.X, (int)yPosition, lens.Width, lens.Height), Color.White);
spriteBatch.End();
}
#endregion
}
}





Main Game Draw Method


//Draw the Background

protected override void Draw(GameTime gameTime)
{

spriteBatch.Begin();
myBackground.Draw(spriteBatch, Color.White); //color.blendedColor);
spriteBatch.End();

cameraPosition += cameraSpeed;

cameraMatrix = Matrix.CreateTranslation(0.0f, -cameraPosition + GraphicsDevice.Viewport.Height / 3 - 50, 0.0f);



cloudExplosion.Draw(gameTime, spriteBatch, cameraMatrix);
foreach (FallingMan cat in cats)
{

if (cat.velocity.Y >= 10)
{
UpdateCatFur(elapsed, cat);
catFur.Draw(gameTime, spriteBatch);

}
}

spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, cameraMatrix);


//Draw the cats

foreach (FallingMan cat in cats)
{
if (cat.backGlow)
{
invulnExplosion.AddParticles(new Vector2(cat.collision.Center.X, cat.collision.Y));
if (cat.pulse <= 0)
cat.count = true;
if (cat.pulse >= 40)
cat.count = false;

if (cat.count)
{
if (cat.elapsedTimePulse >= timePulse)
{
cat.pulse++;
elapsedTimePulse = 0;
}
}
else
{
if (cat.elapsedTimePulse >= timePulse)
{
cat.pulse--;
cat.elapsedTimePulse = 0;
}
}

if (cat.flip == SpriteEffects.None)
{

cat.backPos.X = cat.collision.Center.X - ((pulse + cat.backGlowTexture.Width) / 2);
cat.backPos.Y = cat.collision.Center.Y - (cat.backGlowTexture.Height / 2);
}
else
{
cat.backPos.X = (int)cat.position.X;
}

spriteBatch.Draw(cat.backGlowTexture, new Rectangle(cat.backPos.X, cat.backPos.Y, cat.frameSize.X + pulse, cat.frameSize.Y + pulse), Color.LightYellow);
}
}
foreach (FallingMan cat in cats)
{


cat.Draw(gameTime, spriteBatch);

}








//Draw all the objects other then the player to the screen

GraphicsDevice.BlendState = BlendState.AlphaBlend;


foreach (Platform p in platforms)
{
p.Draw(gameTime, spriteBatch);
}

foreach (PowerUp pow in powerUps)
{
pow.Draw(gameTime, spriteBatch);
}

foreach (Airplane air in airPlanes)
{
air.Draw(gameTime, spriteBatch);
}
foreach (Bird bird in birds)
{
bird.Draw(gameTime, spriteBatch);
}
foreach (Fan fan in fans)
{
fan.Draw(gameTime, spriteBatch);
}

spriteBatch.End();



//Draw the ViewFinders


foreach (ViewFinder view in viewFinders)
{

view.Draw(gameTime, spriteBatch, platforms, clouds, powerUps, birds, airPlanes);


}






}






I'm experimenting with RenderTargets throughout the draw code also but I keep getting a purple screen when I do. Could that be because I might be doing a RenderTarget within a RenderTarget because of how the code is structured?

Like



Graphics.SetRenderTarget2D(example1);

Graphics.SetRenderTarget2D(example2);

//Drawing stuff here

Graphics.SetRenderTarget2D(null);

I'm not really an expert on this stuff, but have you tried setting RenderTargetUsage to PreserveContents (or whatever it's called)? The framework may be discarding the rendertarget buffer before it gets drawn, and would explain the purple screen.
No I haven't but doesnt that cause issues with the Xbox 360?

No I haven't but doesnt that cause issues with the Xbox 360?


As far as I know, there are just some performance considerations with the Xbox and rendertargets. In XNA 4 they apparently changed the interface so that behavior (but not performance!) is the same across platforms. The usual advice is to get something working first, then make a determination if optimization is needed.

Of course, as I said, I'm not really the expert here, so maybe someone else can give a more detailed or accurate answer.

[quote name='Subliminalman' timestamp='1318750597' post='4873066']
No I haven't but doesnt that cause issues with the Xbox 360?


As far as I know, there are just some performance considerations with the Xbox and rendertargets. In XNA 4 they apparently changed the interface so that behavior (but not performance!) is the same across platforms. The usual advice is to get something working first, then make a determination if optimization is needed.

Of course, as I said, I'm not really the expert here, so maybe someone else can give a more detailed or accurate answer.
[/quote]

Well here let me post a screen shot of whats going on. [attachment=5776:Capture.PNG]




As you can see theres only one view port and the background is missing.

Now I think I can fix for the background and everything by applying them to rendertargets then putting them together at the end with an overall rendertarget.

The major problem I'm having right now is drawing all the ViewFinders. I just can't seem to figure out how to do it. They just draw over each other on the entire screen and

I can figure out how to do it properly. I would like for them to all draw to a "final" renderTarget for just the ViewFinders and just draw that to the BackBuffer but I can't figure out how to do that :S

Would preserving the Rendertarget have each ViewFinder draw to it?





As far as I know, there are just some performance considerations with the Xbox and rendertargets. In XNA 4 they apparently changed the interface so that behavior (but not performance!) is the same across platforms. The usual advice is to get something working first, then make a determination if optimization is needed.

Of course, as I said, I'm not really the expert here, so maybe someone else can give a more detailed or accurate answer.


So I figured it out!





Here's the code so if anyone is doing something like this they can use it! Please though just site me in the credits as a Special Thanks and let me know :D






using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;




class ViewFinder
{
#region Variables
public bool isAlive = true;
private float yPosition;
private float seeRadius;
private Point frameSize;
private SpriteEffects spriteEffect = SpriteEffects.None;
public Vector2 position;
public Color viewFinderColor;
private Matrix camera;
private Camera2d cam, cam2;
private Effect mask;
private Texture2D pointer;
private Texture2D lens;
private Texture2D pointRender;
private Texture2D maskTexture, finalMask, flippedFinalMask;
private Texture2D texture;
private RenderTarget2D renderTarget;
private GraphicsDevice graphicsDevice;
public PlayerIndex playerIndex;
private FallingMan cat;
static public bool[] playerView = new bool[4];
public RenderTarget2D finalTarget;
public Texture2D finalTexture;

#endregion

#region Constructors
public ViewFinder(Game game,Vector2 position, Texture2D texture, Point frameSize, Color viewFinderColor, GraphicsDevice graphicsDevice, PlayerIndex playerIndex)
{
mask = game.Content.Load<Effect>(@"Shaders\viewMask");
pointer = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\pointer");
lens = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\lens");
maskTexture = game.Content.Load<Texture2D>(@"Sprite\ViewFinder\mask");
cam = new Camera2d();
cam.Zoom = 3.5f;
cam2 = new Camera2d();
cam2.Zoom = 6;
this.position = position;
this.viewFinderColor = viewFinderColor;
this.texture = texture;
this.frameSize = frameSize;
seeRadius = this.frameSize.X;
this.graphicsDevice = graphicsDevice;
this.playerIndex = playerIndex;
PresentationParameters pp = graphicsDevice.PresentationParameters;
renderTarget = new RenderTarget2D(graphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, graphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
finalTarget = new RenderTarget2D(graphicsDevice, pp.BackBufferWidth, pp.BackBufferHeight, true, graphicsDevice.DisplayMode.Format, DepthFormat.Depth24);
}
#endregion

#region Update
public void Update(GameTime gameTime, Vector2 position, Matrix camera)
{
//Update Postion
this.position = position;

//Update Cam1 Position
cam.position.X = position.X + (frameSize.X / 4);
cam.position.Y = position.Y + (frameSize.Y / 2);
if (position.Y < -camera.Translation.Y)
{
yPosition = 10;
spriteEffect = SpriteEffects.FlipVertically;

}

else if (position.Y > -camera.Translation.Y)
{
yPosition = graphicsDevice.Viewport.Height - pointer.Height;

}

//Update Cam2 Position
cam2.position.X = pointer.Width / 2;
cam2.position.Y = pointer.Width / 2;
this.camera = camera;

}
#endregion

#region Draw
//Call this first to draw the ViewFinder to a RenderTarget
public void PreDraw(GameTime gameTime, SpriteBatch spriteBatch, params Object[] objects)
{


mask.CurrentTechnique = mask.Techniques["Technique1"];
graphicsDevice.SetRenderTarget(renderTarget);

graphicsDevice.DepthStencilState = new DepthStencilState() { DepthBufferEnable = true };

// Draw the scene
graphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, cam.get_transformation(graphicsDevice));


spriteBatch.Draw(texture, new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height), Color.White);


foreach (Object obj in objects)
{

if (obj is List<Platform>)
{
foreach (Platform platform in ((List<Platform>)obj))
{
if (Math.Abs(platform.position.X - position.X) < seeRadius && Math.Abs(platform.position.Y - position.Y) < seeRadius)
{
platform.Draw(gameTime, spriteBatch);
}
}
}

else if (obj is List<PowerUp>)
{
foreach (PowerUp powerUp in ((List<PowerUp>)obj))
{
if (Math.Abs(powerUp.position.X - position.X) < seeRadius && Math.Abs(powerUp.position.Y - position.Y) < seeRadius)
{
powerUp.Draw(gameTime, spriteBatch);
}
}
}
}
spriteBatch.End();



graphicsDevice.SetRenderTarget(finalTarget);
pointRender = (Texture2D)renderTarget;
graphicsDevice.Clear(Color.CornflowerBlue);



spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, mask, camera);
mask.Parameters["spherePort"].SetValue(pointRender);
mask.Parameters["mask"].SetValue(maskTexture);
spriteBatch.Draw(pointRender, new Rectangle(-50, -(int)camera.Translation.Y, pointRender.Width, pointRender.Height), Color.White);
spriteBatch.End();



spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, null, null, null, null, cam2.get_transformation(graphicsDevice));
spriteBatch.Draw(pointer, new Rectangle(-19, 0, pointer.Width +39, pointer.Height), null, viewFinderColor, 0.0f, Vector2.Zero, spriteEffect, 0.1f);
spriteBatch.Draw(lens, new Rectangle(-19,0, lens.Width + 39, lens.Height), Color.White);
spriteBatch.End();
graphicsDevice.SetRenderTarget(null);

finalTexture = (Texture2D)finalTarget;



}

//Call this second to Mask the ViewFinder to have multiple on screen
public void DrawViewFinder(GameTime gameTime, SpriteBatch spriteBatch)
{
spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.LinearClamp, DepthStencilState.Default, RasterizerState.CullNone, mask);
mask.Parameters["spherePort"].SetValue(finalTexture);
if (spriteEffect == SpriteEffects.None)
{
mask.Parameters["mask"].SetValue(finalMask);
}
else
{
mask.Parameters["mask"].SetValue(flippedFinalMask);
}
spriteBatch.Draw(finalTexture, new Rectangle((int)position.X, (int)yPosition, 100, 100), Color.White);
spriteBatch.End();
}
#endregion
}









And then here's the Mask HLSL Code






texture spherePort;
texture mask;

sampler TextureSamplerSphere = sampler_state
{
Texture = <spherePort>;
};

sampler TextureSamplerMask = sampler_state
{
Texture = <mask>;
};

// TODO: add effect parameters here.


float4 PixelShaderFunction(float2 TextureCoordinateSphere : TEXCOORD0, float2 TextureCoordinateMask :TEXCOORD0 ) : COLOR0
{
// TODO: add your pixel shader code here.


return tex2D(TextureSamplerSphere, TextureCoordinateSphere) * tex2D(TextureSamplerMask, TextureCoordinateMask);
}

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


PixelShader = compile ps_2_0 PixelShaderFunction();
}
}







Thanks for the Help :D

This topic is closed to new replies.

Advertisement