G-буферы. Часть 5

G-буферы. Часть 5

Теперь рассмотрим еще один интересный G-буфер — буфер идентификаторов.

Для рисования в буфер идентификаторов каждому объекту мы сопоставим некоторый уникальный идентификатор. Таким образом, каждый объект в полученном буфере будет иметь собственный уникальный цвет.

Буфер идентификаров можно применить в ряде интересных алгоритмов, один из которых мы рассмотрим в следующий раз. Пока же просто реализуем G-буфер идентификаторов.

Идентификатор объекта будет задаваться в основной программе, и передаваться в шейдер в качестве параметра.

Опять же, разумнее было бы использовать для идентификаторов только, например, альфа-канал, чтобы сэкономить память и время. Хотя результат был бы не слишком показательным.

Так что сейчас мы будем считать, что идентификаторо объекта – трехмерный вектор.

Шейдер

float4x4 World;

float4x4 View;

float4x4 Projection;

float3 ID;

// TODO: add effect parameters here.

struct VertexShaderInput

{


float4 Position : POSITION0;


// TODO: add input channels such as texture


// coordinates and vertex colors here.

};

struct VertexShaderOutput

{


float4 Position : POSITION0;


float4 Color : COLOR0;


// TODO: add vertex shader outputs such as colors and texture


// coordinates here. These values will automatically be interpolated


// over the triangle, and provided as input to your pixel shader.

};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)

{

VertexShaderOutput output;


float4 worldPosition = mul(input.Position, World);


float4 viewPosition = mul(worldPosition, View);

output.Position = mul(viewPosition, Projection);


output.Color.rgb = ID.rgb;

output.Color.a = 1;


return output;

}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0

{


return input.Color;

}

technique Technique1

{


pass Pass1

{


// TODO: set renderstates here.


VertexShader = compile
vs_1_1 VertexShaderFunction();


PixelShader = compile
ps_1_1 PixelShaderFunction();

}

}

Код, который нужно тривиален и аналогичен предудущим, остановимся лишь на методе DrawIDs()


private
void DrawIDs(ref
Matrix world, ref
Matrix view, ref
Matrix projection)

{

GraphicsDevice.SetRenderTarget(0, targetID);

GraphicsDevice.Clear(Color.Black);

effectID.Parameters[«View»].SetValue(view);

effectID.Parameters[«Projection»].SetValue(projection);

world = Matrix.CreateRotationY(MathHelper.ToRadians(60)) * Matrix.CreateTranslation(1.5f, 0.8f, 0);

effectID.Parameters[«World»].SetValue(world);

effectID.Parameters[«ID»].SetValue(new
Vector3(0,1,0));

teapot.Draw(effectID);

world = Matrix.CreateTranslation(1.5f, 0, 0);

effectID.Parameters[«World»].SetValue(world);

effectID.Parameters[«ID»].SetValue(new
Vector3(0, 0, 1));

cube.Draw(effectID);

world = Matrix.CreateTranslation(0, 0, 0);

effectID.Parameters[«World»].SetValue(world);

effectID.Parameters[«ID»].SetValue(new
Vector3(1, 0, 0));

cylinder.Draw(effectID);

}

Я установил идентификаторы для каждого объекта таким образом, чтобы они не совпали с собственными цветами объектов в сцене, чтобы был лучше понятен принцип работы буфера идентификаторов.

Полный код Game1 приведен в конце статьи.

При запуске мы должны получить такую картину:

Исходный код Game1.cs

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 Microsoft.Xna.Framework.Net;

using Microsoft.Xna.Framework.Storage;

using Primitives3D;

namespace XNA_MRT

{


///
<summary>


/// This is the main type for your game


///
</summary>


public
class
Game1 : Microsoft.Xna.Framework.Game

{


GraphicsDeviceManager graphics;


SpriteBatch spriteBatch;


CubePrimitive cube;


TeapotPrimitive teapot;


CylinderPrimitive cylinder;


Effect effectLight;


Effect effectDepth;


Effect effectID;


Effect effectNormals;


RenderTarget2D targetDepth;


RenderTarget2D targetID;


RenderTarget2D targetNormals;


SpriteComponent spriteComp;


public Game1()

{

graphics = new
GraphicsDeviceManager(this);

Content.RootDirectory = «Content»;

}


///
<summary>


/// Allows the game to perform any initialization it needs to before starting to run.


/// This is where it can query for any required services and load any non-graphic


/// related content. Calling base.Initialize will enumerate through any components


/// and initialize them as well.


///
</summary>


protected
override
void Initialize()

{


// TODO: Add your initialization logic here

cube = new
CubePrimitive(GraphicsDevice);

teapot = new
TeapotPrimitive(GraphicsDevice);

cylinder = new
CylinderPrimitive(GraphicsDevice);

spriteComp = new
SpriteComponent(this);


this.Components.Add(spriteComp);


base.Initialize();

}


///
<summary>


/// LoadContent will be called once per game and is the place to load


/// all of your content.


///
</summary>


protected
override
void LoadContent()

{


// Create a new SpriteBatch, which can be used to draw textures.

spriteBatch = new
SpriteBatch(GraphicsDevice);


// TODO: use this.Content to load your game content here

effectDepth = Content.Load<Effect>(«drawDepth»);

effectID = Content.Load<Effect>(«drawID»);

effectNormals = Content.Load<Effect>(«drawNormals»);

effectLight = Content.Load<Effect>(«Light»);

targetDepth = new
RenderTarget2D(GraphicsDevice, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight, 1, SurfaceFormat.Color);

targetID = new
RenderTarget2D(GraphicsDevice, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight, 1, SurfaceFormat.Color);

targetNormals = new
RenderTarget2D(GraphicsDevice, graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight, 1, SurfaceFormat.Color);

}


///
<summary>


/// UnloadContent will be called once per game and is the place to unload


/// all content.


///
</summary>


protected
override
void UnloadContent()

{


// TODO: Unload any non ContentManager content here

}


///
<summary>


/// Allows the game to run logic such as updating the world,


/// checking for collisions, gathering input, and playing audio.


///
</summary>


///
<param name=»gameTime»>Provides a snapshot of timing values.</param>


protected
override
void Update(GameTime gameTime)

{


// Allows the game to exit


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


this.Exit();


// TODO: Add your update logic here


base.Update(gameTime);

}


///
<summary>


/// This is called when the game should draw itself.


///
</summary>


///
<param name=»gameTime»>Provides a snapshot of timing values.</param>


protected
override
void Draw(GameTime gameTime)

{

GraphicsDevice.RenderState.AlphaBlendEnable = false;

GraphicsDevice.RenderState.DepthBufferEnable = true;


Matrix world = Matrix.Identity;


Matrix view = Matrix.CreateLookAt(new
Vector3(-3, 0, 2), Vector3.Zero, Vector3.Up);


Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), GraphicsDevice.Viewport.AspectRatio, 0.1f, 10f);

DrawDepth(ref world, ref view, ref projection);

DrawNormals(ref world, ref view, ref projection);

DrawIDs(ref world, ref view, ref projection);

DrawScene(ref world, ref view, ref projection);

spriteComp.Clear();


//spriteComp.Add(targetDiffuse.GetTexture());

spriteComp.Add(targetDepth.GetTexture());

spriteComp.Add(targetNormals.GetTexture());

spriteComp.Add(targetID.GetTexture());


base.Draw(gameTime);

}


private
void DrawDepth(ref
Matrix world, ref
Matrix view, ref
Matrix projection)

{

GraphicsDevice.SetRenderTarget(0, targetDepth);

GraphicsDevice.Clear(Color.Black);

effectDepth.Parameters[«View»].SetValue(view);

effectDepth.Parameters[«Projection»].SetValue(projection);

effectDepth.Parameters[«Eye»].SetValue(new
Vector3(-3, 0, 2));

world = Matrix.CreateRotationY(MathHelper.ToRadians(60)) * Matrix.CreateTranslation(1.5f, 0.8f, 0);

effectDepth.Parameters[«World»].SetValue(world);

teapot.Draw(effectDepth);

world = Matrix.CreateTranslation(1.5f, 0, 0);

effectDepth.Parameters[«World»].SetValue(world);

cube.Draw(effectDepth);

world = Matrix.CreateTranslation(0, 0, 0);

effectDepth.Parameters[«World»].SetValue(world);

cylinder.Draw(effectDepth);

}


private
void DrawNormals(ref
Matrix world, ref
Matrix view, ref
Matrix projection)

{

GraphicsDevice.SetRenderTarget(0, targetNormals);

GraphicsDevice.Clear(Color.Black);

effectNormals.Parameters[«View»].SetValue(view);

effectNormals.Parameters[«Projection»].SetValue(projection);

world = Matrix.CreateRotationY(MathHelper.ToRadians(60)) * Matrix.CreateTranslation(1.5f, 0.8f, 0);

effectNormals.Parameters[«World»].SetValue(world);

teapot.Draw(effectNormals);

world = Matrix.CreateTranslation(1.5f, 0, 0);

effectNormals.Parameters[«World»].SetValue(world);

cube.Draw(effectNormals);

world = Matrix.CreateTranslation(0, 0, 0);

effectNormals.Parameters[«World»].SetValue(world);

cylinder.Draw(effectNormals);

}


private
void DrawIDs(ref
Matrix world, ref
Matrix view, ref
Matrix projection)

{

GraphicsDevice.SetRenderTarget(0, targetID);

GraphicsDevice.Clear(Color.Black);

effectID.Parameters[«View»].SetValue(view);

effectID.Parameters[«Projection»].SetValue(projection);

world = Matrix.CreateRotationY(MathHelper.ToRadians(60)) * Matrix.CreateTranslation(1.5f, 0.8f, 0);

effectID.Parameters[«World»].SetValue(world);

effectID.Parameters[«ID»].SetValue(new
Vector3(0,1,0));

teapot.Draw(effectID);

world = Matrix.CreateTranslation(1.5f, 0, 0);

effectID.Parameters[«World»].SetValue(world);

effectID.Parameters[«ID»].SetValue(new
Vector3(0, 0, 1));

cube.Draw(effectID);

world = Matrix.CreateTranslation(0, 0, 0);

effectID.Parameters[«World»].SetValue(world);

effectID.Parameters[«ID»].SetValue(new
Vector3(1, 0, 0));

cylinder.Draw(effectID);

}


private
void DrawScene(ref
Matrix world, ref
Matrix view, ref
Matrix projection)

{

GraphicsDevice.SetRenderTarget(0, null);

GraphicsDevice.Clear(Color.Black);

effectLight.Parameters[«View»].SetValue(view);

effectLight.Parameters[«Projection»].SetValue(projection);

effectLight.Parameters[«Eye»].SetValue(new
Vector3(-3, 0, 2));

effectLight.Parameters[«LightPosition»].SetValue(new
Vector3(0, 0.5f, 1));

world = Matrix.CreateRotationY(MathHelper.ToRadians(60)) * Matrix.CreateTranslation(1.5f, 0.8f, 0);

effectLight.Parameters[«World»].SetValue(world);

effectLight.Parameters[«DiffuseColor»].SetValue(new
Vector4(1, 0, 0, 1));

teapot.Draw(effectLight);

world = Matrix.CreateTranslation(1.5f, 0, 0);

effectLight.Parameters[«World»].SetValue(world);

effectLight.Parameters[«DiffuseColor»].SetValue(new
Vector4(0, 1, 0, 1));

cube.Draw(effectLight);

world = Matrix.CreateTranslation(0, 0, 0);

effectLight.Parameters[«World»].SetValue(world);

effectLight.Parameters[«DiffuseColor»].SetValue(new
Vector4(0, 0, 1, 1));

cylinder.Draw(effectLight);

}

}

}

Реклама
Запись опубликована в рубрике Uncategorized. Добавьте в закладки постоянную ссылку.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s