[PR]
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
プログラミング、3DCGとその他いろいろについて
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
float4x4 World, View, Projection;
float Shatter;
texture Texture;
sampler TextureSampler = sampler_state
{
Texture = (Texture);
};
struct VertexPositionTexture
{
float4 Position : POSITION;
float2 TextureCoordinate : TEXCOORD;
};
VertexPositionTexture ShatterVertexShader(
float4 position:POSITION,
float4 normal:NORMAL,
float2 textureCoordinate :TEXCOORD
)
{
VertexPositionTexture output;
position.xyz += normal.xyz * Shatter;
float4x4 transform = mul(World, mul(View, Projection));
output.Position = mul(position, transform);
output.TextureCoordinate = textureCoordinate;
return output;
}
float4 ShatterPixelShader(float2 textureCoordinate : TEXCOORD) : COLOR
{
return tex2D(TextureSampler, textureCoordinate);
}
technique ShatterEffect
{
pass
{
VertexShader = compile vs_2_0 ShatterVertexShader();
PixelShader = compile ps_2_0 ShatterPixelShader();
}
}
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
class MyGame : Game
{
GraphicsDeviceManager graphics;
ContentManager content;
//Graphics Device Objects
Effect effect;
Model model;
public MyGame()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
effect = content.Load<Effect>("ShatterEffect");
model = loadModel("Ship", effect);
}
}
Model loadModel(string modelName, Effect effect)
{
Model result = content.Load<Model>(modelName);
foreach (ModelMesh mesh in result.Meshes)
{
foreach (ModelMeshPart part in mesh.MeshParts)
{
effect.Parameters["Texture"].SetValue(
((BasicEffect)part.Effect).Texture
);
part.Effect = effect.Clone(graphics.GraphicsDevice);
}
}
return result;
}
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
{ content.Unload(); }
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (Effect effect in mesh.Effects)
{
setEffectParameters(
effect,
gameTime.TotalGameTime.TotalSeconds
);
}
mesh.Draw();
}
}
private void setEffectParameters(Effect effect, double totalSeconds)
{
Matrix world = Matrix.CreateRotationY(
(float)totalSeconds * 2
);
Matrix view = Matrix.CreateLookAt(
new Vector3(0, 0, 3000), new Vector3(), Vector3.UnitY
);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(90),
(float)graphics.GraphicsDevice.Viewport.Width / graphics.GraphicsDevice.Viewport.Height,
1, 10000
);
effect.Parameters["Shatter"].SetValue(
(float)(1 + System.Math.Sin(totalSeconds)) * 100
);
effect.Parameters["World"].SetValue(world);
effect.Parameters["View"].SetValue(view);
effect.Parameters["Projection"].SetValue(projection);
}
}
//グローバル変数(C#側からセット)
float4x4 World;
float4x4 View;
float4x4 Projection;
texture Texture;
//頂点シェーダ
struct VertexPositionTexture
{
float4 Position : POSITION;
float4 TextureCoordinate : TEXCOORD;
};
VertexPositionTexture VertexShader(VertexPositionTexture input)
{
VertexPositionTexture output;
output.Position = mul(input.Position, mul(World, mul(View, Projection)));
output.TextureCoordinate = input.TextureCoordinate;
return output;
}
//ピクセルシェーダ
sampler DiffuseSampler = sampler_state{
Texture = (Texture);
};
float4 PixelShader(float2 textureCoordinate : TEXCOORD) : COLOR
{
return tex2D(DiffuseSampler, textureCoordinate);
}
technique SimpleEffect
{
pass
{
VertexShader = compile vs_1_1 VertexShader();
PixelShader = compile ps_2_0 PixelShader();
}
}
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
public class MyGame : Game
{
GraphicsDeviceManager graphics;
ContentManager content;
Model model;
public MyGame()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
model = content.Load<Model>("Ship");
ChangeEffectUsedByModel(
content.Load<Effect>("SimpleEffect")
);
}
}
void ChangeEffectUsedByModel(Effect replacementEffect)
{
Texture2D texture = content.Load<Texture2D>("ShipDiffuse");
foreach (ModelMesh mesh in model.Meshes)
{
foreach (ModelMeshPart part in mesh.MeshParts)
{
Effect newEffect = replacementEffect.Clone(
graphics.GraphicsDevice
);
newEffect.Parameters["Texture"].SetValue(
texture
);
part.Effect = newEffect;
}
}
}
protected override void UnloadGraphicsContent(bool unloadAllContent)
{
if (unloadAllContent)
content.Unload();
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
Matrix world = Matrix.CreateRotationY(
MathHelper.ToRadians(-40)
);
Matrix view = Matrix.CreateLookAt(
new Vector3(3000, 1500, 0),
Vector3.Zero,
Vector3.Up
);
Matrix projection = Matrix.CreatePerspectiveFieldOfView(
MathHelper.ToRadians(45),
(float)graphics.GraphicsDevice.Viewport.Width / graphics.GraphicsDevice.Viewport.Height,
1000, 10000
);
DrawModel(world, view, projection);
}
void DrawModel(Matrix world, Matrix view, Matrix projection)
{
Matrix[] transforms = new Matrix[model.Bones.Count];
model.CopyAbsoluteBoneTransformsTo(transforms);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (Effect effect in mesh.Effects)
{
Matrix localWorld = transforms[mesh.ParentBone.Index] * world;
effect.Parameters["World"].SetValue(localWorld);
effect.Parameters["View"].SetValue(view);
effect.Parameters["Projection"].SetValue(projection);
}
mesh.Draw();
}
}
}
void ChangeEffectUsedByModel(Effect replacementEffect)
{
foreach (ModelMesh mesh in model.Meshes)
{
foreach (ModelMeshPart part in mesh.MeshParts)
{
Effect newEffect = replacementEffect.Clone(
graphics.GraphicsDevice
);
newEffect.Parameters["Texture"].SetValue(
((BasicEffect)part.Effect).Texture
);
part.Effect = newEffect;
}
}
}
| 上手く表示されるテクスチャ | 上手く表示されないテクスチャ | |
| Width | 256 | 256 |
| Height | 256 | 256 |
| ResourceManagementMode | Automatic | Automatic |
| ResourceUsage | None | None |
| Format | Dxt5 | Color |
| LevelCount | 9 | 1 |
| LevelOfDetail | 0 | 0 |
| IsDisposed | False | False |
| Tag | ||
| Name | ||
| ResourceType | Texture2D | Texture2D |
| Priority | 0 | 0 |
前回はハードウェア・インスタンシングをやりましたが、これはGPUシェーダー・モデル3.0以上でなければ動きません。
どうやらまだ2.0までのものがよく使われているそうなので、これでは困る場合もあるでしょう。
実は、シェーダーモデルが2.0でも上手くいく方法があります。
グラフィックスカードのメモリを少々食うのですが、モデルそのものはたくさん複製して1つのVertexBufferに入れておいて、インスタンスの情報は配列にしてHLSLのグローバル変数としてセットしてしまうというものです。
これをシェーダー・インスタンシングといいます。
ハードウェア・インスタンシングではVertexBufferにインスタンスの情報を格納しましたが、こちらはHLSLのグローバル変数に格納します。
そして、本来のVertexBufferの中にあるそれぞれのモデルに、インデックスを振ります。
そのインデックスから対応するインスタンスの情報を特定して、頂点に適用するのです。(どうもわかりにくいですね・・・)
こうすることによって、1つのVertexBufferから、自由に動かせる複数のモデルを一度に描画することが出来ます。
モデルのデータを複製して1つのVertexBufferに入れるため、その分無駄なグラフィックス・カードのメモリを食うのですが、それでも一つ一つモデルを描画するよりもパフォーマンスが良くなる(CPUの負荷が減るので)そうです。
HLSLのコードは次のようになります:
ShaderInstancing.fx
float4x4 InstanceTransforms[10];
struct VertexPositionColor
{
float4 Position : POSITION;
float4 Color : COLOR;
};
VertexPositionColor VertexShader(
VertexPositionColor input,
float instanceIndex : TEXCOORD1
)
{
VertexPositionColor output;
output.Position = mul(input.Position, InstanceTransforms[instanceIndex]);
output.Color = input.Color;
return output;
}
float4 PixelShader(float4 color : COLOR):COLOR
{
return color;
}
technique ShaderInstancing
{
pass ShaderInstancingPass
{
VertexShader = compile vs_2_0 VertexShader();
PixelShader = compile ps_2_0 PixelShader();
}
}
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
struct VertexPositionColorIndex
{
public Vector3 Position;
public Color Color;
public float Index;
public static readonly int SizeInBytes
= System.Runtime.InteropServices.Marshal.SizeOf(
typeof(VertexPositionColorIndex)
);
public static readonly VertexElement[] VertexElements
= new VertexElement[]{
new VertexElement(
0,
0,
VertexElementFormat.Vector3,
VertexElementMethod.Default,
VertexElementUsage.Position,
0
),
new VertexElement(
0,
sizeof(float)*3,
VertexElementFormat.Color,
VertexElementMethod.Default,
VertexElementUsage.Color,
0
),
new VertexElement(
0,
sizeof(float)*3 + 4,
VertexElementFormat.Single,
VertexElementMethod.Default,
VertexElementUsage.TextureCoordinate,
1
)
};
}
class MyGame : Game
{
GraphicsDeviceManager graphics;
ContentManager content;
const int instanceCount = 10;
VertexPositionColorIndex[] vertices
= new VertexPositionColorIndex[3 * instanceCount];
Matrix[] instanceTransforms = new Matrix[instanceCount];
Effect effect;
VertexBuffer vertexBuffer;
public MyGame()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
for (int i = 0; i < instanceCount; i++)
{
vertices[3 * i].Color = Color.Blue;
vertices[3 * i].Position = new Vector3(-0.1f, 0.1f, 0);
vertices[3 * i].Index = i;
vertices[3 * i + 1].Color = Color.White;
vertices[3 * i + 1].Position = new Vector3(0.1f, 0.1f, 0);
vertices[3 * i + 1].Index = i;
vertices[3 * i + 2].Color = Color.Red;
vertices[3 * i + 2].Position = new Vector3(0.1f, -0.1f, 0);
vertices[3 * i + 2].Index = i;
}
for (int i = 0; i < instanceTransforms.Length; i++)
{
instanceTransforms[i] = Matrix.CreateTranslation(0.1f * i, 0, 0);
}
}
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
effect = content.Load<Effect>("ShaderInstancing");
vertexBuffer = new VertexBuffer(
graphics.GraphicsDevice,
vertices.Length * VertexPositionColorIndex.SizeInBytes,
ResourceUsage.None
);
vertexBuffer.SetData<VertexPositionColorIndex>(vertices);
graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration(
graphics.GraphicsDevice,
VertexPositionColorIndex.VertexElements
);
}
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
graphics.GraphicsDevice.Vertices[0].SetSource(
vertexBuffer,
0,
VertexPositionColorIndex.SizeInBytes
);
effect.Parameters["InstanceTransforms"].SetValue(instanceTransforms);
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Begin();
graphics.GraphicsDevice.DrawPrimitives(
PrimitiveType.TriangleList,
0,
vertices.Length / 3
);
pass.End();
}
effect.End();
}
}
| Hardware Instancing |
Windows (shader 3.0) |
| Shader Instancing |
Windows (shader 2.0) |
| VFetch | Xbox360 |
| 解説 | |
| GraphicsDevice.Vertices[0] | 普通のVertexBufferと同じ。モデルを構成する頂点を持っています。ここでは、C#で言うなら「クラス」の役割を果たします。 |
| GraphicsDevice.Vertices[1] | 頂点の代わりに、モデルの各インスタンス固有の情報をもっています。C#で言うなら「メンバ変数」がいっぱい詰まっている感じ。構造体の配列みたい。 |
struct VertexPositionColor
{
float4 Position : POSITION0;
float4 Color : COLOR;
};
VertexPositionColor VertexShader(
VertexPositionColor input, float3 position:POSITION1
)
{
input.Position.xyz += position;
return input;
}
float4 PixelShader(float4 color : COLOR) : COLOR0
{
return color;
}
technique HardwareInstancing
{
pass Pass1
{
VertexShader = compile vs_3_0 VertexShader();
PixelShader = compile ps_3_0 PixelShader();
}
}
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
class MyGame : Game
{
GraphicsDeviceManager graphics;
ContentManager content;
VertexPositionColor[] vertices = new VertexPositionColor[]{
new VertexPositionColor(new Vector3(-0.1f, 0.1f, 0), Color.Blue),
new VertexPositionColor(new Vector3(0.1f, 0.1f, 0), Color.White),
new VertexPositionColor(new Vector3(0.1f, -0.1f, 0), Color.Red)
};
Vector3[] trianglePositions = new Vector3[] {
new Vector3(),
new Vector3(0.1f, 0.1f, 0)
};
//Graphics Device Objects
Effect effect;
VertexBuffer triangleVertexBuffer;
IndexBuffer indexBuffer;
VertexBuffer positionVertexBuffer;
public MyGame()
{
graphics = new GraphicsDeviceManager(this);
content = new ContentManager(Services);
}
protected override void LoadGraphicsContent(bool loadAllContent)
{
if (loadAllContent)
{
effect = content.Load<Effect>("HardwareInstancing");
graphics.GraphicsDevice.VertexDeclaration
= createVertexDeclaration();
triangleVertexBuffer = new VertexBuffer(
graphics.GraphicsDevice,
VertexPositionColor.SizeInBytes * vertices.Length,
ResourceUsage.None
);
triangleVertexBuffer.SetData<VertexPositionColor>(vertices);
indexBuffer = new IndexBuffer(
graphics.GraphicsDevice,
sizeof(int) * 3,
ResourceUsage.None,
IndexElementSize.ThirtyTwoBits
);
indexBuffer.SetData<int>(new int[] { 0, 1, 2 });
positionVertexBuffer = new VertexBuffer(
graphics.GraphicsDevice,
sizeof(float) * 3 * trianglePositions.Length,
ResourceUsage.None
);
positionVertexBuffer.SetData<Vector3>(trianglePositions);
}
}
VertexDeclaration createVertexDeclaration()
{
System.Collections.Generic.List<VertexElement> elements
= new System.Collections.Generic.List<VertexElement>();
elements.AddRange(VertexPositionColor.VertexElements);
elements.Add(
new VertexElement(
1,
0,
VertexElementFormat.Vector3,
VertexElementMethod.Default,
VertexElementUsage.Position,
1)
);
return new VertexDeclaration(
graphics.GraphicsDevice,
elements.ToArray()
);
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
graphics.GraphicsDevice.Vertices[0].SetSource(
triangleVertexBuffer,
0,
VertexPositionColor.SizeInBytes
);
graphics.GraphicsDevice.Vertices[0].SetFrequencyOfIndexData(
trianglePositions.Length
);
graphics.GraphicsDevice.Vertices[1].SetSource(
positionVertexBuffer,
0,
sizeof(float) * 3
);
graphics.GraphicsDevice.Vertices[1].SetFrequencyOfInstanceData(1);
graphics.GraphicsDevice.Indices = indexBuffer;
effect.Begin();
foreach (EffectPass pass in effect.CurrentTechnique.Passes)
{
pass.Begin();
graphics.GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0, //baseVertex
0, //minVertexIndex
vertices.Length, //numVertices
0, //startIndex
vertices.Length/3 //primitiveCount
);
pass.End();
}
effect.End();
}
}
| 名前 | 値 | |
| ALUT_WAVEFORM_SINE | 0x100 | |
| ALUT_WAVEFORM_SQUARE | 0x101 | |
| ALUT_WAVEFORM_SAWTOOTH | 0x102 | |
| ALUT_WAVEFORM_WHITENOISE | 0x103 | |
| ALUT_WAVEFORM_IMPULSE | 0x104 |
using System;
using System.Runtime.InteropServices;
class AudioSource
{
[DllImport("OpenAL32.dll")]
static extern void alGenSources(int resultSize, int[] result);
[DllImport("OpenAL32.dll")]
static extern void alDeleteSources(int nameCount, int[] sourceNames);
[DllImport("OpenAL32.dll")]
static extern void alSourcei(int sourceName, int propertyType, int value);
const int AL_BUFFER = 0x1009;
[DllImport("OpenAL32.dll")]
static extern void alSourcePlay(int sourceName);
private int name;
public AudioSource()
{
int[] names = new int[1];
alGenSources(names.Length, names);
this.name = names[0];
}
~AudioSource()
{
alDeleteSources(1, new int[] { this.name });
}
public int Buffer
{
set
{
alSourcei(this.name, AL_BUFFER, value);
}
}
public void Play()
{
alSourcePlay(this.name);
}
}
class AudioBuffer
{
[DllImport("alut.dll")]
static extern int alutCreateBufferWaveform(
WaveForm waveShape,
float frequency,
float phase,
float duration
);
[DllImport("OpenAL32.dll")]
static extern void alDeleteBuffers(int nameCount, int[] bufferNames);
private int name;
public int Name { get { return this.name; } }
public AudioBuffer(WaveForm waveShape, float frequency, float phase, float duration)
{
this.name = alutCreateBufferWaveform(waveShape, frequency, phase, duration);
}
~AudioBuffer()
{
alDeleteBuffers(1, new int[] { name });
}
}
enum WaveForm
{
//ALUT_WAVEFORM_SINE
Sine = 0x100,
//ALUT_WAVEFORM_SQUARE
Square,
//ALUT_WAVEFORM_SAWTOOTH
SawTooth,
//ALUT_WAVEFORM_WHITENOISE
WhiteNoize,
//ALUT_WAVEFORM_IMPULSE
Impulse
}
class Program
{
[DllImport("alut.dll")]
static extern void alutInit(IntPtr argcp, string[] argv);
[DllImport("alut.dll")]
static extern void alutExit();
static void Main()
{
alutInit(IntPtr.Zero, null);
foreach (WaveForm waveShape in Enum.GetValues(typeof(WaveForm)))
{
System.Console.WriteLine(waveShape);
AudioBuffer buffer = new AudioBuffer(waveShape, 440, 0, 1);
AudioSource source = new AudioSource();
source.Buffer = buffer.Name;
source.Play();
System.Threading.Thread.Sleep(2000);
}
alutExit();
}
}