How to properly add a matrix to a Instanced Vertex definition ?

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>("FxHwInstanceing05");
            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;
            VertexPositionUv[] vertices = new VertexPositionUv[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, VertexPositionUv.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 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 orientation;
                instanceDataOrientaion[i].instanceForward = Vector3.Forward;
                instanceDataOrientaion[i].instanceUp = Vector3.Up;
                instanceDataOrientaion[i].instanceLeft = Vector3.Left;
                // 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["ParticleTexture"].SetValue(ParticleTexture);
            //particlesEffect.Parameters["CyclePercentageTime"].SetValue(cyclePercentageTime);
            particlesEffect.Parameters["ViewProjection"].SetValue(viewProj);
            // 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(sizeof(float) *3, VertexElementFormat.Vector3, VertexElementUsage.Normal, 1),
                    new VertexElement(sizeof(float) *6, VertexElementFormat.Vector3, VertexElementUsage.Normal, 2),
                    new VertexElement(sizeof(float) *9, VertexElementFormat.Vector3, VertexElementUsage.Normal, 3),
                    //new VertexElement(48, VertexElementFormat.Single, VertexElementUsage.BlendWeight, 0)
                    //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 VertexPositionUv : IVertexType
    {
        public Vector3 position;
        public Vector2 texCoordinate;

        public static readonly VertexDeclaration VertexDeclaration;
        static VertexPositionUv()
        {
            var elements = new VertexElement[]
                {
                    new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
                    new VertexElement(sizeof(float) * 3, 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;
	float3 InstanceForward : NORMAL1;
	float3 InstanceUp : NORMAL2;
	float3 InstanceLeft : NORMAL3;
	//float InstanceTimeOrId : BLENDWEIGHT0;
};

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;
		matrix viewProj = ViewProjection;
		// 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, 1.0f); // <- i may need to zero this out first lets see.
		matrix worldViewProjection = mul(world, viewProj);
		// 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, worldViewProjection);
		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;

		output.Color = float4(1.0f, 0.0f, 0.0f, .99f);

		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.

Can you post the stack trace?

Oh god hold on i just realized i was using the old shader loaded from content.

Im debugging the hell out of a shader thats not loaded lol
Minor alteration it ran straight away. Code is re-edited.
Its not a working shader yet but it runs.

My quote for today … “thats impossible what is going on !!!”.

2 Likes