I was working through an older tutorial listed here, and got it to work for the most part. The RenderTarget for Depth is colored red for some reason, and I've been scratching my head trying to figure out why.
I tried clearing the screen another way, which at least painted the other render targets white instead of black. Also, this code uses the cross platform dlls (OpenGL), but the very same code fails with a strange error with windows only dlls.
Here are some screenshots: https://i.sstatic.net/BBMEo.jpg
Tutorial link: http://www.catalinzima.com/xna/tutorials/deferred-rendering-in-xna/creating-the-g-buffer/
Any help appreciated.
Below is the code I am using, which is almost exactly like the tutorial:
public class Game1 : Game
{
private GraphicsDeviceManager graphics;
private SpriteBatch spriteBatch;
private Model model;
private Texture2D texture;
private float angle = 0f;
private Vector3 FocusPoint;
private Vector3 CameraOffset;
private Matrix RotationMatrix;
private Vector3 RotationOffset;
private Matrix World;
private Matrix View;
private Matrix Projection;
private Effect ClearGBufferEffect;
private Effect GBufferEffect;
private QuadRenderComponent QuadRenderer;
private RenderTarget2D ColorRenderTarget;
private RenderTarget2D NormalRenderTarget;
private RenderTarget2D DepthRenderTarget;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// quad renderer
QuadRenderer = new QuadRenderComponent(this);
Components.Add(QuadRenderer);
// world view projection
FocusPoint = Vector3.Zero;
CameraOffset = new Vector3(0f, 2f, 2f);
RotationMatrix = Matrix.CreateRotationY(MathHelper.PiOver4);
RotationOffset = Vector3.Transform(CameraOffset, RotationMatrix);
World = Matrix.CreateScale(new Vector3(1f, 1f, 1f)) * Matrix.CreateTranslation(new Vector3(0, 0, 0));
View = Matrix.CreateLookAt(RotationOffset, FocusPoint, Vector3.Up);
Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 480f / 480f, 0.1f, 1000f);
// color normal depth
int backBufferWidth = GraphicsDevice.PresentationParameters.BackBufferWidth;
int backBufferHeight = GraphicsDevice.PresentationParameters.BackBufferHeight;
ColorRenderTarget = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);
NormalRenderTarget = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Color, DepthFormat.Depth24);
DepthRenderTarget = new RenderTarget2D(GraphicsDevice, backBufferWidth, backBufferHeight, false, SurfaceFormat.Single, DepthFormat.Depth24Stencil8);
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
// model texture gbuffer
model = Content.Load<Model>("Tile5");
texture = Content.Load<Texture2D>("Red");
ClearGBufferEffect = Content.Load<Effect>("ClearGBuffer");
GBufferEffect = Content.Load<Effect>("GBuffer");
}
protected override void UnloadContent() { }
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
// simple rotation update
angle += 1f;
RotationOffset = Vector3.Transform(CameraOffset, Matrix.CreateRotationY(MathHelper.ToRadians(angle)));
View = Matrix.CreateLookAt(RotationOffset, FocusPoint, Vector3.Up);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
// set render targets
GraphicsDevice.SetRenderTargets(ColorRenderTarget, NormalRenderTarget, DepthRenderTarget);
// clear everything
// ClearGBufferEffect.CurrentTechnique.Passes[0].Apply();
// QuadRenderer.Render(Vector2.One * -1, Vector2.One);
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.White, 1.0f, 0);
// render options
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
GraphicsDevice.RasterizerState = RasterizerState.CullCounterClockwise;
// set gbuffer params
GBufferEffect.Parameters["World"].SetValue(World);
GBufferEffect.Parameters["View"].SetValue(View);
GBufferEffect.Parameters["Projection"].SetValue(Projection);
GBufferEffect.Parameters["Texture"].SetValue(texture);
// render simple mesh
GBufferEffect.CurrentTechnique.Passes[0].Apply();
foreach (var mesh in model.Meshes)
{
foreach (var part in mesh.MeshParts)
{
GraphicsDevice.SetVertexBuffer(part.VertexBuffer);
GraphicsDevice.Indices = part.IndexBuffer;
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, part.PrimitiveCount);
}
}
// unset render targets
GraphicsDevice.SetRenderTargets(null);
// render each target to one 4th of the screen
int hw = GraphicsDevice.Viewport.Width / 2;
int hh = GraphicsDevice.Viewport.Height / 2;
spriteBatch.Begin();
spriteBatch.Draw(ColorRenderTarget, new Rectangle(0, 0, hw, hh), Color.White);
spriteBatch.Draw(NormalRenderTarget, new Rectangle(0, hh, hw, hh), Color.White);
spriteBatch.Draw(DepthRenderTarget, new Rectangle(hw, 0, hw, hh), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
}
public class QuadRenderComponent : DrawableGameComponent
{
//private VertexDeclaration vertexDecl = null;
private VertexPositionTexture[] verts = null;
private short[] ib = null;
public QuadRenderComponent(Game game)
: base(game) { }
protected override void LoadContent()
{
IGraphicsDeviceService graphicsService =
(IGraphicsDeviceService)Game.Services.GetService(
typeof(IGraphicsDeviceService));
verts = new VertexPositionTexture[]
{
new VertexPositionTexture(
new Vector3(0,0,1),
new Vector2(1,1)),
new VertexPositionTexture(
new Vector3(0,0,1),
new Vector2(0,1)),
new VertexPositionTexture(
new Vector3(0,0,1),
new Vector2(0,0)),
new VertexPositionTexture(
new Vector3(0,0,1),
new Vector2(1,0))
};
ib = new short[] { 0, 1, 2, 2, 3, 0 };
}
public void Render(Vector2 v1, Vector2 v2)
{
IGraphicsDeviceService graphicsService = (IGraphicsDeviceService)
base.Game.Services.GetService(typeof(IGraphicsDeviceService));
GraphicsDevice device = graphicsService.GraphicsDevice;
verts[0].Position.X = v2.X;
verts[0].Position.Y = v1.Y;
verts[1].Position.X = v1.X;
verts[1].Position.Y = v1.Y;
verts[2].Position.X = v1.X;
verts[2].Position.Y = v2.Y;
verts[3].Position.X = v2.X;
verts[3].Position.Y = v2.Y;
device.DrawUserIndexedPrimitives(PrimitiveType.TriangleList, verts, 0, 4, ib, 0, 2);
}
}
Here is the ClearGBufferEffect:
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
struct VertexShaderInput
{
float3 Position : SV_POSITION;
};
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
};
struct PixelShaderOutput
{
float4 Color : COLOR0;
float4 Normal : COLOR1;
float4 Depth : COLOR2;
};
VertexShaderOutput MainVS(in VertexShaderInput input)
{
VertexShaderOutput output = (VertexShaderOutput)0;
output.Position = float4(input.Position, 1);
return output;
}
PixelShaderOutput MainPS(VertexShaderOutput input)
{
PixelShaderOutput output = (PixelShaderOutput)0;
output.Color.rgb = 0.0f;
output.Color.a = 0.0f;
output.Normal.rgb = 0.5f;
output.Normal.a = 0.0f;
output.Depth = 1.0f;
return output;
}
technique T0
{
pass P0
{
VertexShader = compile VS_SHADERMODEL MainVS();
PixelShader = compile PS_SHADERMODEL MainPS();
}
};
Here is the GBufferEffect:
#if OPENGL
#define SV_POSITION POSITION
#define VS_SHADERMODEL vs_3_0
#define PS_SHADERMODEL ps_3_0
#else
#define VS_SHADERMODEL vs_4_0_level_9_1
#define PS_SHADERMODEL ps_4_0_level_9_1
#endif
matrix World;
matrix View;
matrix Projection;
float SpecularIntensity = 0.8f;
float SpecularPower = 0.5f;
texture Texture;
sampler DiffuseSampler = sampler_state
{
Texture = (Texture);
MAGFILTER = LINEAR;
MINFILTER = LINEAR;
MIPFILTER = LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
struct VertexShaderInput
{
float4 Position : SV_POSITION;
float3 Normal : NORMAL0;
float2 TexCoord : TEXCOORD0;
};
struct VertexShaderOutput
{
float4 Position : SV_POSITION;
float2 TexCoord : TEXCOORD0;
float3 Normal : TEXCOORD1;
float2 Depth : TEXCOORD2;
};
struct PixelShaderOutput
{
half4 Color : COLOR0;
half4 Normal : COLOR1;
half4 Depth : COLOR2;
};
VertexShaderOutput MainVS(in VertexShaderInput input)
{
VertexShaderOutput output = (VertexShaderOutput)0;
float4 worldPosition = mul(input.Position, World);
float4 viewPosition = mul(worldPosition, View);
output.Position = mul(viewPosition, Projection);
output.TexCoord = input.TexCoord;
output.Normal = mul(input.Normal, World);
output.Depth = output.Position.zw;
return output;
}
PixelShaderOutput MainPS(VertexShaderOutput input)
{
PixelShaderOutput output = (PixelShaderOutput)0;
output.Color.rgb = tex2D(DiffuseSampler, input.TexCoord);
output.Color.a = SpecularIntensity;
output.Normal.rgb = 0.5f * (normalize(input.Normal) + 1.0f);
output.Normal.a = SpecularPower;
output.Depth = input.Depth.x / input.Depth.y;
return output;
}
technique T0
{
pass P0
{
VertexShader = compile VS_SHADERMODEL MainVS();
PixelShader = compile PS_SHADERMODEL MainPS();
}
};