[PR]
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
プログラミング、3DCGとその他いろいろについて
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
float4x4 World; float4x4 View; float4x4 Projection; struct VertexShaderInput { float4 Position : POSITION0; }; struct VertexShaderOutput { float4 Position : POSITION0; float DistanceFromCamera : TEXCOORD0; }; VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); output.DistanceFromCamera = output.Position.z; return output; } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { return input.DistanceFromCamera; } technique Technique1 { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_1_1 PixelShaderFunction(); } }シャドウマップを作るシェーダーです。
float4x4 World; float4x4 View; float4x4 Projection; texture ShadowMap; sampler ShadowMapSampler = sampler_state { Texture = (ShadowMap); }; float4x4 LightView; float4x4 LightProjection; struct VertexShaderInput { float4 Position : POSITION0; float4 Color : COLOR0; }; struct VertexShaderOutput { float4 Position : POSITION0; float4 PositionOnShadowMap : TEXCOORD0; float4 Color : COLOR0; }; VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); output.Color = input.Color; output.PositionOnShadowMap = mul( worldPosition, mul(LightView, LightProjection) ); return output; } bool isLighted(float4 positionOnShadowMap) { float2 texCoord;
texCoord.x = (positionOnShadowMap.x / positionOnShadowMap.w + 1) / 2;
texCoord.y = (-positionOnShadowMap.y / positionOnShadowMap.w + 1) / 2;
//誤差があるはずなので、光が当たっているかどうかは //ほんの少しだけ甘く判定します。 return positionOnShadowMap.z <= tex2D(ShadowMapSampler, texCoord).x + 0.001f; } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { if(isLighted(input.PositionOnShadowMap)) return input.Color; else return input.Color / 3; } technique Technique1 { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_2_0 PixelShaderFunction(); } }
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; public class MyGame : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; VertexPositionColor[] triangleVertices = { new VertexPositionColor(new Vector3(0, 1, 0), Color.White), new VertexPositionColor(new Vector3(1, 0, 0), Color.Red), new VertexPositionColor(new Vector3(-1, 0, 0), Color.Blue) }; Matrix[] triangles = { Matrix.Identity, Matrix.Identity }; Effect effect; Effect shadowMapCreator; RenderTarget2D shadowMap; public MyGame() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { triangles[0] *= Matrix.CreateRotationX(MathHelper.ToRadians(-90)); triangles[0] *= Matrix.CreateTranslation(0, 0, 0.5f); triangles[0] *= Matrix.CreateScale(3); triangles[0] *= Matrix.CreateTranslation(0, -4, 0); triangles[1] *= Matrix.CreateRotationX(MathHelper.ToRadians(-90)); triangles[1] *= Matrix.CreateTranslation(0, 0, 0.5f); triangles[1] *= Matrix.CreateTranslation(0, -2, 0); base.Initialize(); } protected override void LoadContent() { GraphicsDevice.VertexDeclaration = new VertexDeclaration( GraphicsDevice, VertexPositionColor.VertexElements ); Matrix lightView = Matrix.CreateLookAt( new Vector3(0, 1, 0), new Vector3(), Vector3.Forward ); Matrix lightProjection = Matrix.CreateOrthographic( 8, 8, 0.1f, 30 ); shadowMapCreator = Content.Load<Effect>("ShadowMapCreator"); shadowMapCreator.Parameters["View"].SetValue(lightView); shadowMapCreator.Parameters["Projection"].SetValue(lightProjection); effect = Content.Load<Effect>("DrawUsingShadowMap"); effect.Parameters["View"].SetValue( Matrix.CreateLookAt( new Vector3(0, 1, 8), new Vector3(), Vector3.Up ) ); effect.Parameters["Projection"].SetValue( Matrix.CreatePerspectiveFieldOfView( MathHelper.ToRadians(90), GraphicsDevice.Viewport.AspectRatio, 0.1f, 100 ) ); effect.Parameters["LightView"].SetValue(lightView); effect.Parameters["LightProjection"].SetValue(lightProjection); shadowMap = new RenderTarget2D( GraphicsDevice, 512, 512, 1, SurfaceFormat.Single ); } protected override void UnloadContent() { shadowMap.Dispose(); } protected override void Draw(GameTime gameTime) { initShadowMap(); GraphicsDevice.Clear(Color.CornflowerBlue); effect.Parameters["ShadowMap"].SetValue(shadowMap.GetTexture()); foreach (Matrix triangleTransform in triangles) { effect.Parameters["World"].SetValue(triangleTransform); effect.Begin(); effect.CurrentTechnique.Passes[0].Begin(); GraphicsDevice.DrawUserPrimitives<VertexPositionColor>( PrimitiveType.TriangleList, triangleVertices, 0, 1 ); effect.CurrentTechnique.Passes[0].End(); effect.End(); } base.Draw(gameTime); } private void initShadowMap() { GraphicsDevice.SetRenderTarget(0, shadowMap); GraphicsDevice.Clear(Color.White); foreach (Matrix triangleTransform in triangles) { shadowMapCreator.Parameters["World"].SetValue(triangleTransform); shadowMapCreator.Begin(); shadowMapCreator.CurrentTechnique.Passes[0].Begin(); GraphicsDevice.DrawUserPrimitives<VertexPositionColor>( PrimitiveType.TriangleList, triangleVertices, 0, 1 ); shadowMapCreator.CurrentTechnique.Passes[0].End(); shadowMapCreator.End(); } GraphicsDevice.SetRenderTarget(0, null); } static void Main(string[] args) { using (MyGame game = new MyGame()) { game.Run(); } } }
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; struct VertexPositionNormalTextureTangent { public Vector3 Position; public Vector3 Normal; public Vector2 TextureCoordinate; public Vector3 NormalMapXDirection; public VertexPositionNormalTextureTangent( Vector3 position, Vector3 normal, Vector2 textureCoordinate, Vector3 normalMapXDirection) { this.Position = position; this.Normal = normal; this.TextureCoordinate = textureCoordinate; this.NormalMapXDirection = normalMapXDirection; } public static readonly VertexElement[] VertexElements = { new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0), new VertexElement( 0, sizeof(float) * (3 + 3), VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0), new VertexElement( 0, sizeof(float) * (3 + 3 + 2), VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 1) }; } public class MyGame : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; Effect effect; //四角形の頂点です。 VertexPositionNormalTextureTangent[] rectangleVertices = { new VertexPositionNormalTextureTangent( new Vector3(-1, 1, 0), Vector3.UnitZ, new Vector2(), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(1,1,0), Vector3.UnitZ, new Vector2(1,0), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(-1,-1,0), Vector3.UnitZ, new Vector2(0,1), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(1,1,0), Vector3.UnitZ, new Vector2(1,0), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(1,-1,0), Vector3.UnitZ, new Vector2(1,1), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(-1,-1,0), Vector3.UnitZ, new Vector2(0, 1), Vector3.UnitX ) }; Matrix worldTransform = Matrix.Identity; public MyGame() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void LoadContent() { effect = Content.Load<Effect>("BumpMapping"); effect.Parameters["View"].SetValue( Matrix.CreateLookAt(new Vector3(0, 0, 3), new Vector3(), Vector3.Up) ); effect.Parameters["Projection"].SetValue( Matrix.CreatePerspectiveFieldOfView( MathHelper.ToRadians(90), (float)GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, 0.1f, 1000 )); effect.Parameters["Light0Direction"].SetValue( new Vector3(-1, 0, -1) ); effect.Parameters["HeightMap"].SetValue( Content.Load<Texture2D>("HeightMap") ); GraphicsDevice.VertexDeclaration = new VertexDeclaration( GraphicsDevice, VertexPositionNormalTextureTangent.VertexElements ); } //↑↓←→キーで //四角形を回転します。 protected override void Update(GameTime gameTime) { KeyboardState keyboardState = Keyboard.GetState(); if (keyboardState.IsKeyDown(Keys.Left)) { worldTransform *= Matrix.CreateRotationY(-0.03f); } if (keyboardState.IsKeyDown(Keys.Right)) { worldTransform *= Matrix.CreateRotationY(0.03f); } if (keyboardState.IsKeyDown(Keys.Up)) { worldTransform *= Matrix.CreateRotationX(-0.03f); } if (keyboardState.IsKeyDown(Keys.Down)) { worldTransform *= Matrix.CreateRotationX(0.03f); } } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); effect.Parameters["World"].SetValue(worldTransform); effect.Begin(); effect.CurrentTechnique.Passes[0].Begin(); GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTextureTangent>( PrimitiveType.TriangleList, rectangleVertices, 0, 2 ); effect.CurrentTechnique.Passes[0].End(); effect.End(); base.Draw(gameTime); } static void Main() { using (MyGame game = new MyGame()) { game.Run(); } } }
float4x4 World; float4x4 View; float4x4 Projection; float3 Light0Direction; texture HeightMap; sampler HeightSampler = sampler_state { Texture = (HeightMap); }; struct VertexShaderInput { float4 Position : POSITION; float4 Normal : NORMAL; float2 TextureCoordinate : TEXCOORD0; float4 NormalMapXDirection : TEXCOORD1; }; struct VertexShaderOutput { float4 Position : POSITION0; float2 TextureCoordinate : TEXCOORD0; float3 LightDirectionToPolygon : TEXCOORD1; }; VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { //Position VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); //TextureCoordinate output.TextureCoordinate = input.TextureCoordinate; //LightDirectionToPolygon float3 zDirection = normalize(mul(input.Normal, (float3x3)World)); float3 xDirection = normalize(mul(input.NormalMapXDirection, (float3x3)World)); float3 normalizedLight0Direction = normalize(Light0Direction); output.LightDirectionToPolygon = float3( dot(normalizedLight0Direction, xDirection), dot(normalizedLight0Direction, cross(zDirection, xDirection)), dot(normalizedLight0Direction, zDirection) ); return output; } float3 getNormal(float2 texCoord) { const float HeightMapWidth = 128; const float HeightMapHeight = 128; float3 current = 2 * tex2D(HeightSampler, texCoord); float3 left = 2 * tex2D( HeightSampler, float2(texCoord.x - 1.0 / HeightMapWidth, texCoord.y) ); float3 up = 2 * tex2D( HeightSampler, float2(texCoord.x, texCoord.y - 1.0 / HeightMapHeight) ); return normalize(float3(left.x - current.x, up.x - current.x, 1)); } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { float4 diffuse = dot( getNormal(input.TextureCoordinate), -input.LightDirectionToPolygon ); return diffuse; } technique Technique1 { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_2_0 PixelShaderFunction(); } }
どうもGPUでのエリア総和テーブルは上手くいかないので、問題に対処するもっとも有効で一般的な方法、すなわち現実逃避に走ることにします。
そう、そもそもなぜエリア総和テーブルをやろうとしていたのかというとAIに画像処理をやらせようとしていたからなんです!
べつにGPUでなくてもCPUで計算すればいいだけのことなので、いつまでもGPUでエリア総和テーブルをやることにこだわっているのは建設的ではありません!
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; struct VertexPositionNormalTextureTangent { public Vector3 Position; public Vector3 Normal; public Vector2 TextureCoordinate; public Vector3 NormalMapXDirection; public VertexPositionNormalTextureTangent( Vector3 position, Vector3 normal, Vector2 textureCoordinate, Vector3 normalMapXDirection) { this.Position = position; this.Normal = normal; this.TextureCoordinate = textureCoordinate; this.NormalMapXDirection = normalMapXDirection; } public static readonly VertexElement[] VertexElements = { new VertexElement( 0, 0, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Position, 0), new VertexElement( 0, sizeof(float) * 3, VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.Normal, 0), new VertexElement( 0, sizeof(float) * (3 + 3), VertexElementFormat.Vector2, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 0), new VertexElement( 0, sizeof(float) * (3 + 3 + 2), VertexElementFormat.Vector3, VertexElementMethod.Default, VertexElementUsage.TextureCoordinate, 1) }; } public class MyGame : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; Effect effect; //四角形の頂点です。 VertexPositionNormalTextureTangent[] rectangleVertices = { new VertexPositionNormalTextureTangent( new Vector3(-1, 1, 0), Vector3.UnitZ, new Vector2(), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(1,1,0), Vector3.UnitZ, new Vector2(1,0), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(-1,-1,0), Vector3.UnitZ, new Vector2(0,1), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(1,1,0), Vector3.UnitZ, new Vector2(1,0), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(1,-1,0), Vector3.UnitZ, new Vector2(1,1), Vector3.UnitX ), new VertexPositionNormalTextureTangent( new Vector3(-1,-1,0), Vector3.UnitZ, new Vector2(0, 1), Vector3.UnitX ) }; Matrix worldTransform = Matrix.Identity; public MyGame() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void LoadContent() { effect = Content.Load<Effect>("BumpMapping"); effect.Parameters["View"].SetValue( Matrix.CreateLookAt(new Vector3(0, 0, 3), new Vector3(), Vector3.Up) ); effect.Parameters["Projection"].SetValue( Matrix.CreatePerspectiveFieldOfView( MathHelper.ToRadians(90), (float)GraphicsDevice.Viewport.Width / GraphicsDevice.Viewport.Height, 0.1f, 1000 )); effect.Parameters["Light0Direction"].SetValue( new Vector3(-1, 0, -1) ); effect.Parameters["NormalMap"].SetValue( Content.Load<Texture2D>("NormalMap2") ); GraphicsDevice.VertexDeclaration = new VertexDeclaration( GraphicsDevice, VertexPositionNormalTextureTangent.VertexElements ); } //↑↓←→キーで //四角形を回転します。 protected override void Update(GameTime gameTime) { KeyboardState keyboardState = Keyboard.GetState(); if (keyboardState.IsKeyDown(Keys.Left)) { worldTransform *= Matrix.CreateRotationY(-0.03f); } if(keyboardState.IsKeyDown(Keys.Right)) { worldTransform *= Matrix.CreateRotationY(0.03f); } if (keyboardState.IsKeyDown(Keys.Up)) { worldTransform *= Matrix.CreateRotationX(-0.03f); } if (keyboardState.IsKeyDown(Keys.Down)) { worldTransform *= Matrix.CreateRotationX(0.03f); } } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); effect.Parameters["World"].SetValue(worldTransform); effect.Begin(); effect.CurrentTechnique.Passes[0].Begin(); GraphicsDevice.DrawUserPrimitives<VertexPositionNormalTextureTangent>( PrimitiveType.TriangleList, rectangleVertices, 0, 2 ); effect.CurrentTechnique.Passes[0].End(); effect.End(); base.Draw(gameTime); } static void Main() { using (MyGame game = new MyGame()) { game.Run(); } } }
float4x4 World; float4x4 View; float4x4 Projection; float3 Light0Direction; texture NormalMap; sampler NormalSampler = sampler_state { Texture = (NormalMap); }; struct VertexShaderInput { float4 Position : POSITION; float4 Normal : NORMAL; float2 TextureCoordinate : TEXCOORD0; float4 NormalMapXDirection : TEXCOORD1; }; struct VertexShaderOutput { float4 Position : POSITION0; float2 TextureCoordinate : TEXCOORD0; float3 LightDirectionToPolygon : TEXCOORD1; }; VertexShaderOutput VertexShaderFunction(VertexShaderInput input) { //Position VertexShaderOutput output; float4 worldPosition = mul(input.Position, World); float4 viewPosition = mul(worldPosition, View); output.Position = mul(viewPosition, Projection); //TextureCoordinate output.TextureCoordinate = input.TextureCoordinate; //LightDirectionToPolygon float3 zDirection = normalize(mul(input.Normal, (float3x3)World)); float3 xDirection = normalize(mul(input.NormalMapXDirection, (float3x3)World)); float3 normalizedLight0Direction = normalize(Light0Direction); output.LightDirectionToPolygon = float3( dot(normalizedLight0Direction, xDirection), dot(normalizedLight0Direction, cross(zDirection, xDirection)), dot(normalizedLight0Direction, zDirection) ); return output; } float3 getNormal(float2 texCoord) { return normalize(2 * tex2D(NormalSampler, texCoord) - 1); } float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0 { float4 diffuse = dot( getNormal(input.TextureCoordinate), -input.LightDirectionToPolygon ); return diffuse; } technique Technique1 { pass Pass1 { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_2_0 PixelShaderFunction(); } }
エリア総和テーブル(Summed Area table)を作る実験をまたやってみました。
前回は横方向にだけ足しましたが、今回は縦方向にも足します。
驚いたことに、ちょっとした修正をするだけで縦方向にも足せるようになりますね。
これでようやくエリア総和テーブルとして使えるようになるはずです。(たぶん)
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; public class MyGame : Game { GraphicsDeviceManager graphics; Texture2D texture; BasicEffect basicEffect; VertexDeclaration vertexDeclaration; Effect tableCreationEffect; RenderTarget2D renderTarget; public MyGame() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void LoadContent() { //指定したサイズのテクスチャを作ります。 //サイズをいろいろ変えると、 //いろいろなサイズのエリア総和テーブルが作れます。 initTexture(8, 8); renderTarget = new RenderTarget2D( GraphicsDevice, texture.Width, texture.Height, 1, SurfaceFormat.Vector4 ); tableCreationEffect = Content.Load<Effect>("SummedAreaTableCreator"); basicEffect = new BasicEffect(GraphicsDevice, null); vertexDeclaration = new VertexDeclaration( GraphicsDevice, VertexPositionTexture.VertexElements ); GraphicsDevice.VertexDeclaration = vertexDeclaration; } private void initTexture(int width, int height) { texture = new Texture2D( GraphicsDevice, width, height, 1, TextureUsage.None, SurfaceFormat.Vector4 ); Vector4[] data = new Vector4[texture.Width * texture.Height]; for (int i = 0; i < data.Length; i++) data[i] = Vector4.One / data.Length; texture.SetData<Vector4>(data); } protected override void UnloadContent() { texture.Dispose(); renderTarget.Dispose(); basicEffect.Dispose(); vertexDeclaration.Dispose(); } protected override void Draw(GameTime gameTime) { GraphicsDevice.SetRenderTarget(0, renderTarget); GraphicsDevice.Clear(Color.CornflowerBlue); drawTexture(texture); createSummedAreaTable(); GraphicsDevice.SetRenderTarget(0, null); GraphicsDevice.Clear(Color.CornflowerBlue); drawTexture(renderTarget.GetTexture()); } //GraphicsDeviceにセットされているレンダーターゲットを、 //自分自身のエリア総和テーブルに変えます。 private void createSummedAreaTable() { tableCreationEffect.Parameters["Width"].SetValue(renderTarget.Width); tableCreationEffect.Parameters["Height"].SetValue(renderTarget.Height); tableCreationEffect.Begin(); //横方向に足す for (int i = 0; i < System.Math.Log(renderTarget.Width, 2); i++) { tableCreationEffect.CurrentTechnique.Passes["SumXPass"].Begin(); GraphicsDevice.SetRenderTarget(0, null); tableCreationEffect.Parameters["PreviousProduct"].SetValue(renderTarget.GetTexture()); GraphicsDevice.SetRenderTarget(0, renderTarget); tableCreationEffect.Parameters["PassIndex"].SetValue(i); drawRect(); tableCreationEffect.CurrentTechnique.Passes["SumXPass"].End(); } //縦方向に足す for (int i = 0; i < System.Math.Log(renderTarget.Height, 2); i++) { tableCreationEffect.CurrentTechnique.Passes["SumYPass"].Begin(); GraphicsDevice.SetRenderTarget(0, null); tableCreationEffect.Parameters["PreviousProduct"].SetValue(renderTarget.GetTexture()); GraphicsDevice.SetRenderTarget(0, renderTarget); tableCreationEffect.Parameters["PassIndex"].SetValue(i); drawRect(); tableCreationEffect.CurrentTechnique.Passes["SumYPass"].End(); } tableCreationEffect.End(); } private void drawTexture(Texture2D texture) { basicEffect.TextureEnabled = true; basicEffect.Texture = texture; basicEffect.Begin(); basicEffect.CurrentTechnique.Passes[0].Begin(); drawRect(); basicEffect.CurrentTechnique.Passes[0].End(); basicEffect.End(); } private void drawRect() { //四角形(テクスチャつき)の頂点 VertexPositionTexture[] vertices = { new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2()), new VertexPositionTexture(new Vector3(1, 1, 0), new Vector2(1, 0)), new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0, 1)), new VertexPositionTexture(new Vector3(1, 1, 0), new Vector2(1, 0)), new VertexPositionTexture(new Vector3(1, -1, 0), new Vector2(1, 1)), new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0, 1)) }; GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>( PrimitiveType.TriangleList, vertices, 0, 2 ); } static void Main() { using (MyGame game = new MyGame()) { game.Run(); } } }
texture PreviousProduct; sampler TextureSampler = sampler_state { Texture = (PreviousProduct); }; float Width; float Height; int PassIndex; struct VertexPositionTexture { float4 Position : POSITION; float2 TextureCoordinate : TEXCOORD; }; VertexPositionTexture VertexShaderFunction(VertexPositionTexture input) { return input; } float4 getColor(float2 texCoord) { if(texCoord.x < 0 || texCoord.y < 0) return 0; else return tex2D(TextureSampler, texCoord + float2(0.5/Width, 0.5/Height)); } float4 SumX(float2 textureCoordinate : TEXCOORD):COLOR { return getColor(textureCoordinate + float2((-1/ Width) * exp2(PassIndex), 0)) + getColor(textureCoordinate); } float4 SumY(float2 textureCoordinate : TEXCOORD):COLOR { return getColor(textureCoordinate + float2(0, (-1/ Height) * exp2(PassIndex))) + getColor(textureCoordinate); } technique Technique1 { pass SumXPass { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_2_0 SumX(); } pass SumYPass { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_2_0 SumY(); } }
private void createSummedAreaTable() { tableCreationEffect.Parameters["Width"].SetValue(renderTarget.Width); tableCreationEffect.Parameters["Height"].SetValue(renderTarget.Height); tableCreationEffect.Begin(); //横方向に足す tableCreationEffect.CurrentTechnique.Passes["SumXPass"].Begin(); for (int i = 0; i < System.Math.Log(renderTarget.Width, 2); i++) { GraphicsDevice.SetRenderTarget(0, null); tableCreationEffect.Parameters["PreviousProduct"].SetValue(renderTarget.GetTexture()); GraphicsDevice.SetRenderTarget(0, renderTarget); tableCreationEffect.Parameters["PassIndex"].SetValue(i); tableCreationEffect.CommitChanges(); drawRect(); } tableCreationEffect.CurrentTechnique.Passes["SumXPass"].End(); //縦方向に足す tableCreationEffect.CurrentTechnique.Passes["SumYPass"].Begin(); for (int i = 0; i < System.Math.Log(renderTarget.Height, 2); i++) { GraphicsDevice.SetRenderTarget(0, null); tableCreationEffect.Parameters["PreviousProduct"].SetValue(renderTarget.GetTexture()); GraphicsDevice.SetRenderTarget(0, renderTarget); tableCreationEffect.Parameters["PassIndex"].SetValue(i); tableCreationEffect.CommitChanges(); drawRect(); } tableCreationEffect.CurrentTechnique.Passes["SumYPass"].End(); tableCreationEffect.End(); }
2 | 4 | 1 | 3 |
1 | 0 | 2 | 0 |
0 | 3 | 0 | 2 |
2 | 1 | 0 | 4 |
2 | 6 | 7 | 10 |
3 | 7 | 10 | 13 |
3 | 10 | 13 | 18 |
5 | 13 | 16 | 25 |
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; public class MyGame : Game { GraphicsDeviceManager graphics; Texture2D texture; BasicEffect basicEffect; VertexDeclaration vertexDeclaration; Effect tableCreationEffect; RenderTarget2D renderTarget; public MyGame() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void LoadContent() { //このinitTextureの引数をいろいろ変えてみることで、 //テクスチャのサイズ(横幅)が変わり、 //画面に表示される画像の滑らかさが変わります。 //たとえば、initTexture(8);ならカクカクしますが、 //initTexture(128)なら滑らかです。 initTexture(128); renderTarget = new RenderTarget2D( GraphicsDevice, texture.Width, texture.Height, texture.LevelCount, SurfaceFormat.Vector4 ); tableCreationEffect = Content.Load<Effect>("SummedAreaTableCreator"); basicEffect = new BasicEffect(GraphicsDevice, null); vertexDeclaration = new VertexDeclaration( GraphicsDevice, VertexPositionTexture.VertexElements ); GraphicsDevice.VertexDeclaration = vertexDeclaration; } private void initTexture(int width) { texture = new Texture2D( GraphicsDevice, width, 1, 1, TextureUsage.None, SurfaceFormat.Vector4 ); Vector4[] data = new Vector4[texture.Width * texture.Height]; for (int i = 0; i < data.Length; i++) data[i] = Vector4.One / texture.Width; texture.SetData<Vector4>(data); } protected override void UnloadContent() { texture.Dispose(); renderTarget.Dispose(); basicEffect.Dispose(); vertexDeclaration.Dispose(); } protected override void Draw(GameTime gameTime) { GraphicsDevice.SetRenderTarget(0, renderTarget); GraphicsDevice.Clear(Color.CornflowerBlue); drawTexture(texture); createSummedAreaTable(); GraphicsDevice.SetRenderTarget(0, null); GraphicsDevice.Clear(Color.CornflowerBlue); drawTexture(renderTarget.GetTexture()); } private void createSummedAreaTable() { tableCreationEffect.Parameters["Width"].SetValue(renderTarget.Width); tableCreationEffect.Parameters["Height"].SetValue(renderTarget.Height); tableCreationEffect.Begin(); for (int i = 0; i < System.Math.Log(texture.Width, 2); i++) { tableCreationEffect.CurrentTechnique.Passes[0].Begin(); GraphicsDevice.SetRenderTarget(0, null); tableCreationEffect.Parameters["PreviousProduct"].SetValue(renderTarget.GetTexture()); GraphicsDevice.SetRenderTarget(0, renderTarget); tableCreationEffect.Parameters["PassIndex"].SetValue(i); drawRect(); tableCreationEffect.CurrentTechnique.Passes[0].End(); } tableCreationEffect.End(); } private void drawTexture(Texture2D texture) { basicEffect.TextureEnabled = true; basicEffect.Texture = texture; basicEffect.Begin(); basicEffect.CurrentTechnique.Passes[0].Begin(); drawRect(); basicEffect.CurrentTechnique.Passes[0].End(); basicEffect.End(); } private void drawRect() { //四角形(テクスチャつき)の頂点 VertexPositionTexture[] vertices = { new VertexPositionTexture(new Vector3(-1, 1, 0), new Vector2()), new VertexPositionTexture(new Vector3(1, 1, 0), new Vector2(1, 0)), new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0, 1)), new VertexPositionTexture(new Vector3(1, 1, 0), new Vector2(1, 0)), new VertexPositionTexture(new Vector3(1, -1, 0), new Vector2(1, 1)), new VertexPositionTexture(new Vector3(-1, -1, 0), new Vector2(0, 1)) }; GraphicsDevice.DrawUserPrimitives<VertexPositionTexture>( PrimitiveType.TriangleList, vertices, 0, 2 ); } static void Main() { using (MyGame game = new MyGame()) { game.Run(); } } }
texture PreviousProduct; sampler TextureSampler = sampler_state { Texture = (PreviousProduct); }; float Width; float Height; int PassIndex; struct VertexPositionTexture { float4 Position : POSITION; float2 TextureCoordinate : TEXCOORD; }; VertexPositionTexture VertexShaderFunction(VertexPositionTexture input) { return input; } float4 getColor(float2 texCoord) { if(texCoord.x < 0 || texCoord.y < 0) return 0; else return tex2D(TextureSampler, texCoord + float2(0.5/Width, 0.5/Height)); } float4 SumX(float2 textureCoordinate : TEXCOORD):COLOR { return getColor(textureCoordinate + float2((-1/ Width) * exp2(PassIndex), 0)) + getColor(textureCoordinate); } technique Technique1 { pass SumXPass { VertexShader = compile vs_1_1 VertexShaderFunction(); PixelShader = compile ps_2_0 SumX(); } }
0.5 | 0.5 |
0.5 | 1.0 |