Quantcast
Channel: Community | MonoGame - Latest topics
Viewing all articles
Browse latest Browse all 6821

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

$
0
0

@willmotil wrote:

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.

Posts: 1

Participants: 1

Read full topic


Viewing all articles
Browse latest Browse all 6821

Trending Articles