Im not very good at hlsl semantics.
What is the prefered or proper way to pass a orientation matrix thru to a shader.
Specifically the questions i have at the moment are related to passing and accessing.
Which data type should i use?
Is it ok to use position or should i use blendweights or texturecoordinates whats the difference ?
Are there limits to how many i can pass of a type ?
Are there specific cavets or hlsl access rules for them ?
the cs.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Runtime.InteropServices;
namespace GLParticleTestTrimed
{
public class Game2_HwiShader05 : Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
SpriteFont font;
ParticleSystem05 particleSystem;
Matrix viewProjection;
Texture2D particleTexture;
Effect particlesEffect;
// basically a elaborate timing device.
float cyclePercentage = 0f;
double fullCycleTimeInSeconds = 1.2d;
double cycleTime = 0d;
double elapsedUpdateTime = 0;
double last = 0d;
double now = 0d;
public Game2_HwiShader05()
{
graphics = new GraphicsDeviceManager(this);
graphics.GraphicsProfile = GraphicsProfile.HiDef;
graphics.PreferMultiSampling = false;
Window.AllowUserResizing = true;
graphics.PreferredBackBufferWidth = 1024;
graphics.PreferredBackBufferHeight = 768;
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
font = Content.Load<SpriteFont>("MgFont");
particlesEffect = Content.Load<Effect>("ParticleEffect03GL");
particleTexture = Content.Load<Texture2D>("particle");
particleSystem = new ParticleSystem05(particlesEffect)
{
// Set this to blast out more particles
InstanceCount = 10000,
ParticleSize = new Vector2(3.0f, 7.0f),
ParticleTexture = particleTexture
};
SetUpViewProjection();
particleSystem.IntializeParticleSystemBuffers(GraphicsDevice);
}
public void SetUpViewProjection()
{
// Setup the worldViewProj matrix
float width = GraphicsDevice.PresentationParameters.BackBufferWidth;
float height = GraphicsDevice.PresentationParameters.BackBufferHeight;
float aspect = width / height;
Matrix viewMatrix = Matrix.CreateLookAt(new Vector3(0.01f, 0.01f, 5.0f), Vector3.Forward, Vector3.Up);
Matrix projMatrix = Matrix.CreatePerspectiveFieldOfView(1.56f, aspect, .1f, 1000);
viewProjection = viewMatrix * projMatrix;
}
protected override void UnloadContent()
{
Content.Unload();
}
protected override void Update(GameTime gameTime)
{
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
CycleTiming(gameTime);
particleSystem.UpdateParticleTime((float)(cyclePercentage));
base.Update(gameTime);
}
public void CycleTiming(GameTime gameTime)
{
last = now;
now = gameTime.TotalGameTime.TotalSeconds;
elapsedUpdateTime = now - last;
cycleTime += elapsedUpdateTime;
if (cycleTime >= fullCycleTimeInSeconds)
cycleTime -= fullCycleTimeInSeconds;
cyclePercentage = (float)(cycleTime / fullCycleTimeInSeconds);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
GraphicsDevice.BlendState = BlendState.Additive;
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
particleSystem.DrawParticles(viewProjection, GraphicsDevice);
spriteBatch.Begin();
spriteBatch.DrawString(font, cyclePercentage.ToString(), new Vector2(20, 20), Color.Green);
spriteBatch.End();
base.Draw(gameTime);
}
}
public class ParticleSystem05
{
// Vertex data
VertexBuffer vertexBuffer;
IndexBuffer indexBuffer;
VertexBufferBinding vertexBufferBinding;
// Instance data
InstanceDataOrientation[] instanceDataOrientaion;
VertexBuffer instanceBuffer;
VertexBufferBinding instanceBufferBinding;
int numInstancesToDraw;
float cyclePercentageTime = 0;
Effect particlesEffect;
public Vector2 ParticleSize { get; set; }
public Texture2D ParticleTexture { get; set; }
public uint InstanceCount { get; set; }
public int MaxVisibleParticles
{
get; private set;
}
public ParticleSystem05(Effect effect)
{
particlesEffect = effect;
}
public void IntializeParticleSystemBuffers(GraphicsDevice graphicsDevice)
{
// set up the indice stuff
int[] indices = new int[6];
// indices to triangle vertices
indices[0] = 1; indices[1] = 0; indices[2] = 2; // ccw
indices[3] = 3; indices[4] = 1; indices[5] = 2;
//
indexBuffer = new IndexBuffer(graphicsDevice, typeof(int), 6, BufferUsage.WriteOnly);
indexBuffer.SetData(indices);
// set up the vertex stuff
// Create a single quad centered at the origin
float halfParticleWidth = ParticleSize.X / 2;
float halfParticleHeight = ParticleSize.Y / 2;
float z = 0.0f;
VertexPositionTexture[] vertices = new VertexPositionTexture[4];
//vertices[3].texCoordinate = new Vector2(1.0f, 1.0f);
vertices[0].position = new Vector3(-halfParticleWidth, -halfParticleHeight, z); // lt 0
vertices[1].position = new Vector3(halfParticleWidth, -halfParticleHeight, z); // rt 1
vertices[2].position = new Vector3(-halfParticleWidth, halfParticleHeight, z); // lb 2
vertices[3].position = new Vector3(halfParticleWidth, halfParticleHeight, z); // rb 3
// u,v texture coords
vertices[0].texCoordinate = new Vector2(0.0f, 0.0f);
vertices[1].texCoordinate = new Vector2(1.0f, 0.0f);
vertices[2].texCoordinate = new Vector2(0.0f, 1.0f);
vertices[3].texCoordinate = new Vector2(1.0f, 1.0f);
//
vertexBuffer = new VertexBuffer(graphicsDevice, VertexPositionTexture.VertexDeclaration, 4, BufferUsage.WriteOnly);
vertexBuffer.SetData(vertices);
vertexBufferBinding = new VertexBufferBinding(vertexBuffer);
// set up the instance stuff
MaxVisibleParticles = (int)(InstanceCount);
instanceDataOrientaion = new InstanceDataOrientation[MaxVisibleParticles];
// set particles randomly
Random rnd = new Random();
/* randomly places the particle positions, and color changer */
float halfWidth = graphicsDevice.PresentationParameters.BackBufferWidth * .5f;
float halfHeight = graphicsDevice.PresentationParameters.BackBufferHeight * .5f;
for (int i = 0; i < MaxVisibleParticles; ++i)
{
// instance orientation;
instanceDataOrientaion[i].instanceForward = Vector3.Forward;
instanceDataOrientaion[i].instanceUp = Vector3.Up;
instanceDataOrientaion[i].instanceLeft = Vector3.Left;
// instance data float position
instanceDataOrientaion[i].instancePosition = new Vector3
(
(rnd.Next(0, (int)(halfWidth) * 2) - halfWidth),
(rnd.Next(0, (int)(halfHeight * 2)) - halfHeight),
((float)(rnd.Next(1, MaxVisibleParticles + 1)) / (float)(MaxVisibleParticles + 1) * 650 + 350) * -1f
);
// instance data float time
instanceDataOrientaion[i].instanceTimeOrId = (float)(rnd.Next(0, MaxVisibleParticles + 1)) / (float)(MaxVisibleParticles + 1);//(float)(i) / (float)(MaxVisibleParticles + 1f); // for a timed id
}
instanceBuffer = new VertexBuffer(graphicsDevice, InstanceDataOrientation.VertexDeclaration, MaxVisibleParticles, BufferUsage.WriteOnly);
instanceBufferBinding = new VertexBufferBinding(instanceBuffer, 0, 1);
instanceBuffer.SetData(instanceDataOrientaion);
}
// We could draw less instances here.
public void UpdateParticleTime(float seconds)
{
// i could use my dynamic dead alive buffer here to keep the sorting smooth.
numInstancesToDraw = MaxVisibleParticles;
cyclePercentageTime = seconds;
}
public void DrawParticles(Matrix viewProj, GraphicsDevice graphicsDevice)
{
// Select the technique.
particlesEffect.CurrentTechnique = particlesEffect.Techniques["ParticleDrawingSimple"];
// Initialise our shader constants
particlesEffect.Parameters["ViewProjection"].SetValue(viewProj);
particlesEffect.Parameters["ParticleTexture"].SetValue(ParticleTexture);
particlesEffect.Parameters["CyclePercentageTime"].SetValue(cyclePercentageTime);
// Set buffers to device
graphicsDevice.SetVertexBuffers(vertexBufferBinding, instanceBufferBinding);
graphicsDevice.Indices = indexBuffer;
// Draw
particlesEffect.CurrentTechnique.Passes[0].Apply();
graphicsDevice.DrawInstancedPrimitives(PrimitiveType.TriangleList, 0, 0, 2, numInstancesToDraw);
}
}
// the instanceDataType
[StructLayout(LayoutKind.Sequential)]
public struct InstanceDataOrientation : IVertexType
{
public Vector3 instanceForward;
public Vector3 instanceUp;
public Vector3 instanceLeft;
public Vector3 instancePosition;
public float instanceTimeOrId;
public static readonly VertexDeclaration VertexDeclaration;
static InstanceDataOrientation()
{
var elements = new VertexElement[]
{
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 1), // The usage index must match.
new VertexElement(12, VertexElementFormat.Single, VertexElementUsage.BlendWeight, 0),
new VertexElement(24, VertexElementFormat.Vector3, VertexElementUsage.BlendWeight, 1),
new VertexElement(36, VertexElementFormat.Vector3, VertexElementUsage.BlendWeight, 2),
new VertexElement(48, VertexElementFormat.Vector3, VertexElementUsage.BlendWeight, 3),
//new VertexElement( offset in bytes, VertexElementFormat.Single, VertexElementUsage. option, shader element usage id number )
};
VertexDeclaration = new VertexDeclaration(elements);
}
VertexDeclaration IVertexType.VertexDeclaration
{
get { return VertexDeclaration; }
}
}
// the vertexDataType
[StructLayout(LayoutKind.Sequential)]
public struct VertexPositionTextureNormal : IVertexType
{
public Vector3 position;
public Vector2 texCoordinate;
public static readonly VertexDeclaration VertexDeclaration;
static VertexPositionTextureNormal()
{
var elements = new VertexElement[]
{
new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
new VertexElement(12, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0),
};
VertexDeclaration = new VertexDeclaration(elements);
}
VertexDeclaration IVertexType.VertexDeclaration
{
get { return VertexDeclaration; }
}
}
}
the shader
// FxHwInstanceing05.fx
#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
#define PS_SHADERMODEL ps_4_0
#endif
//_________________________________________________________________
static const float PI = 3.14159;
static const float PI2 = 6.28318;
static const float EIGHT_PI = 25.13274;
matrix ViewProjection;
float CyclePercentageTime;
Texture2D ParticleTexture;
sampler2D TexSampler = sampler_state
{
Texture = <ParticleTexture>;
//AddressU = Wrap;//AddressV = Wrap;//MinFilter = Anisotropic;//MagFilter = Anisotropic;//MipFilter = Point;
};
//__________________________________________________________
struct VSInstanceInputSimple
{
float3 InstancePosition : POSITION1;
float InstanceTimeOrId : BLENDWEIGHT0;
float3 InstanceForward : BLENDWEIGHT1;
float3 InstanceUp : BLENDWEIGHT2;
float3 InstanceLeft : BLENDWEIGHT3;
};
struct VSVertexInputSimple
{
float4 Position : POSITION0;//SV_POSITION;
float2 TexCoord : TEXCOORD0;
//float3 Normal : NORMAL0;
};
struct VSOutputSimple
{
float4 Position : SV_POSITION;
float2 TexCoord : TEXCOORD0;
float4 Color : COLOR0;
};
VSOutputSimple MainVSSimple(in VSVertexInputSimple vertexInput, VSInstanceInputSimple instanceInput)
{
VSOutputSimple output;
// first i have to get this all to compile without error.
float3 instancePosition = instanceInput.InstancePosition;
float instanceTimeOrId = instanceInput.InstanceTimeOrId;
// create the world
float4x4 world;
world[0] = float4(instanceInput.InstanceForward, 0.0f);
world[1] = float4(instanceInput.InstanceUp, 0.0f);
world[2] = float4(instanceInput.InstanceLeft, 0.0f);
world[3] = float4(instancePosition, 0.0f); // <- i may need to zero this out first lets see.
matrix worldViewProjection = mul(world, ViewProjection);
// here is the tricky part the intention is to put this into the proper wvp position in one shot.
// however i might have to mult the world without translation.
// then translate the vertexposition by the instanceposition and multiply.
float4 posVert = mul(vertexInput.Position, ViewProjection);
output.Position = posVert;
// pass textcoords thru
output.TexCoord = vertexInput.TexCoord;
// change color
float4 colRed = float4(1.0f, 0.0f, 0.0f, .99f);
float4 colGreen = float4(0.0f, 1.0f, 0.0f, .99f);
float4 colBlue = float4(0.0f, 0.0f, 1.0f, .99f);
output.Color =
(colRed * instanceTimeOrId) + // colors are based on the instance id or time not x y order as such they go from zero to 1 and blue is drawn first.
(colGreen* ((0.5f - abs(instanceTimeOrId - 0.5f))*2.0f)) +
(colBlue * (1.0f - instanceTimeOrId));
output.Color.a = 1.0f;
return output;
}
float4 MainPSSimple(VSOutputSimple input) : COLOR0
{
float4 col = tex2D(TexSampler, input.TexCoord) * input.Color;
// straight clip alpha draws
clip(col.a - .05f);
return col;
}
technique ParticleDrawingSimple
{
pass
{
VertexShader = compile VS_SHADERMODEL MainVSSimple();
PixelShader = compile PS_SHADERMODEL MainPSSimple();
}
};
it also uses a small texture.
Well it's compiling with blendweights but im getting a error on my passed view projection matrix that says its not set to a instance of a object ? though it looks set to me.