開発環境 |
Microsoft Visual C# 2010 Express (SP1) |
実行環境 |
Microsoft Windows XP Home Edition (SP3) |
プロジェクトの種類 |
Windows Game (4.0) |
プロジェクト名 |
XnaShader |
ColorMap.pngは下記サイトからダウンロードする。
参考
Program_3.cs
// #3
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
class Game1 : Game
{
GraphicsDeviceManager graphics;
VertexBuffer vb;
Effect effect;
RenderTarget2D renderTarget;
bool updateCachedTexture = true;
Vector2 offset = new Vector2(-0.25f, 0.0f);
float zoom = 3.0f;
// 頂点構造体
struct MyVertex : IVertexType
{
Vector2 Position;
Vector2 UV;
public MyVertex(Vector2 position, Vector2 uv)
{
Position = position;
UV = uv;
}
public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration(
new VertexElement[] {
new VertexElement(0, VertexElementFormat.Vector2,
VertexElementUsage.Position, 0),
new VertexElement(8, VertexElementFormat.Vector2,
VertexElementUsage.TextureCoordinate, 0),
});
VertexDeclaration IVertexType.VertexDeclaration { get { return VertexDeclaration;} }
}
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
graphics.PreferredBackBufferWidth = 800;
graphics.PreferredBackBufferHeight = 600;
Window.AllowUserResizing = true;
}
protected override void LoadContent()
{
const int numVertices = 4;
vb = new VertexBuffer(GraphicsDevice, typeof(MyVertex), numVertices,
BufferUsage.None);
MyVertex[] vertices = new MyVertex[numVertices] {
new MyVertex(new Vector2(-1.0f, 1.0f), new Vector2(0.0f, 1.0f)), // LT
new MyVertex(new Vector2( 1.0f, 1.0f), new Vector2(1.0f, 1.0f)), // RT
new MyVertex(new Vector2(-1.0f, -1.0f), new Vector2(0.0f, 0.0f)), // LB
new MyVertex(new Vector2( 1.0f, -1.0f), new Vector2(1.0f, 0.0f)), // RB
};
vb.SetData(vertices);
// ContentにMandelbrot.fxを追加しておく
effect = Content.Load<Effect>("Mandelbrot");
// ContentにColorMap.pngを追加しておく
effect.Parameters["colorMapTexture"].SetValue(Content.Load<Texture2D>("ColorMap"));
if (renderTarget == null) {
renderTarget = new RenderTarget2D(
GraphicsDevice,
GraphicsDevice.PresentationParameters.BackBufferWidth,
GraphicsDevice.PresentationParameters.BackBufferHeight);
updateCachedTexture = true;
}
base.LoadContent();
}
protected override void UnloadContent()
{
if (renderTarget != null) {
renderTarget.Dispose();
renderTarget = null;
}
base.UnloadContent();
}
protected override void Update(GameTime gameTime)
{
float oldZoom = zoom;
Vector2 oldOffset = offset;
// 移動量
float offsetMove = 0.01f * (float)Math.Log(zoom + 1.0f);
KeyboardState key = Keyboard.GetState();
if (key.IsKeyDown(Keys.Left)) {
offset.X -= offsetMove;
}
if (key.IsKeyDown(Keys.Right)) {
offset.X += offsetMove;
}
if (key.IsKeyDown(Keys.Down)) {
offset.Y -= offsetMove;
}
if (key.IsKeyDown(Keys.Up)) {
offset.Y += offsetMove;
}
if (key.IsKeyDown(Keys.PageDown)) {
zoom *= 1.05f;
}
if (key.IsKeyDown(Keys.PageUp))
{
zoom /= 1.05f;
}
if (key.IsKeyDown(Keys.Escape)) {
Exit();
}
updateCachedTexture |= (oldZoom != zoom || oldOffset != offset);
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
// 再描画が必要なときだけテクスチャ・レンダリングを行う
if (updateCachedTexture) {
//エフェクトのパラメータ更新
effect.Parameters["Zoom"].SetValue(zoom);
effect.Parameters["Aspect"].SetValue(GraphicsDevice.Viewport.AspectRatio);
effect.Parameters["Offset"].SetValue(offset);
RenderTargetBinding[] rtb = GraphicsDevice.GetRenderTargets();
GraphicsDevice.SetRenderTarget(renderTarget);
// エフェクト描画
effect.CurrentTechnique = effect.Techniques["Mandelbrot"];
GraphicsDevice.SetVertexBuffer(vb);
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Apply();
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
}
GraphicsDevice.SetRenderTargets(rtb);
updateCachedTexture = false;
}
// テクスチャにレンダリングされたマンデルブロ集合のイメージをそのまま表示する
effect.Parameters["cachedTexture"].SetValue((Texture2D)renderTarget);
effect.CurrentTechnique = effect.Techniques["Cached"];
GraphicsDevice.SetVertexBuffer(vb);
foreach(EffectPass pass in effect.CurrentTechnique.Passes) {
pass.Apply();
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleStrip, 0, 2);
}
effect.Parameters["cachedTexture"].SetValue((Texture2D)null);
base.Draw(gameTime);
}
}
class Program
{
static void Main()
{
using (Game1 game = new Game1()) {
game.IsMouseVisible = true;
game.Run();
}
}
}
Mandelbrot_3.fx
float Aspect = 1.0f;
float Zoom = 1.0f;
float2 Offset = float2(0.0f, 0.0f);
texture colorMapTexture;
texture cachedTexture;
// サンプラー
sampler ColorMap = sampler_state
{
Texture = <colorMapTexture>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
};
sampler CachedMap = sampler_state
{
Texture = <cachedTexture>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Linear;
AddressU = Wrap;
};
// 構造体
struct VertexIn
{
float2 Pos : POSITION;
float2 UV : TEXCOORD0;
};
struct VertexOut
{
float4 ScreenPos : POSITION;
float2 UV : TEXCOORD0;
};
struct PixelIn
{
float2 UV : TEXCOORD0;
};
struct PixelOut
{
float4 Color : COLOR0;
};
// Mandelbrot
VertexOut MandelbrotVS(VertexIn input)
{
VertexOut output;
output.ScreenPos = float4(input.Pos, 0.0f, 1.0f);
output.UV = (input.UV - 0.5f) * float2(1.0f, -Aspect) * Zoom + Offset;
return output;
}
PixelOut GetMandelbrotColor(int n, uniform int MaxIterate)
{
PixelOut output;
if (n < MaxIterate) {
float u = (float)n / (float)MaxIterate;
output.Color.rgb = tex1D(ColorMap, 2.0f * u);
} else {
output.Color.rgb = 0.0f;
}
output.Color.a = 1.0f;
return output;
}
PixelOut MandelbrotPSImpl(PixelIn input, uniform int MaxIterate)
{
float2 p = 0;
int n;
for (n = 0; n < MaxIterate && dot(p, p) < 4.0f; n++) {
p = float2(p.x * p.x - p.y * p.y, 2.0f * p.x * p.y) + input.UV;
}
return GetMandelbrotColor(n, MaxIterate);
}
PixelOut MandelbrotPSImpl(PixelIn input, uniform int Loop1, uniform int Loop2)
{
const int MaxIterate = Loop1 * 128 + Loop2;
float2 p = 0;
bool finite = true;
int n = 0;
for (int j = 0; j < Loop1 && finite; j++) {
for (int i = 0; i < 128 && finite; i++) {
p = float2(p.x * p.x - p.y * p.y, 2.0f * p.x * p.y) + input.UV;
finite = dot(p, p) < 4.0f;
n++;
}
}
if (Loop2 > 0) {
for (int j = 0; j < Loop2 && dot(p, p); j++) {
p = float2(p.x * p.x - p.y * p.y, 2.0f * p.x * p.y) + input.UV;
n++;
}
}
return GetMandelbrotColor(n, MaxIterate);
}
PixelOut MandelbrotPS(PixelIn input, uniform int MaxIterate)
{
if (MaxIterate > 254) {
return MandelbrotPSImpl(input, MaxIterate / 128, MaxIterate % 128);
} else {
return MandelbrotPSImpl(input, MaxIterate);
}
}
// CachedImage
VertexOut CachedImageVS(VertexIn input)
{
VertexOut output;
output.ScreenPos = float4(input.Pos, 0.0f, 1.0f);
output.UV = input.UV;
return output;
}
PixelOut CachedImageShader(PixelIn input)
{
PixelOut output;
output.Color = tex2D(CachedMap, input.UV);
return output;
}
// レンダー
technique Mandelbrot
{
pass Pass0
{
VertexShader = compile vs_3_0 MandelbrotVS();
PixelShader = compile ps_3_0 MandelbrotPS(128);
}
}
technique Cached
{
pass Pass0
{
VertexShader = compile vs_3_0 CachedImageVS();
PixelShader = compile ps_3_0 CachedImageShader();
}
}
最終更新:2012年11月07日 21:47