GL instanced shader problem.

Ty PumpkinPudding.

Figures it would be a typo to look past over and over.

       VertexElementUsage.Position, 1),

Most ridiculous thing of all is that the 1 was in the shader the entire time. So i must of accounted for it at some point. Sorry man i feel stupid.

Edit:
I altered the code a bit and pumped out 2 million particles no problem, nice.
The altered working gl code is below it’s a little bit simpler then the previous example.

The shader

#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

//_________________________________________________________________
//__________________________ the gl shader_________________________
//_________________________________________________________________

static const float PI = 3.14159;
static const float PI2 = 6.28318;
static const float EIGHT_PI = 25.13274;

//float Life;
float TotalTime;
matrix WorldViewProjection;

Texture2D ParticleTexture;
sampler2D TexSampler = sampler_state
{
    Texture = <ParticleTexture>;
    //AddressU = Wrap;//AddressV = Wrap;//MinFilter = Anisotropic;//MagFilter = Anisotropic;//MipFilter = Point;
};

//__________________________________________________________

struct VSInstanceInputSimple
{
    float3 InstancePosition : POSITION1;  // ahh wait waat .... like i must have accounted for this at some point and didn't change the cs file as well ... omg there is a lesson here.
    float InstanceTimeOrId : BLENDWEIGHT0;
};

struct VSVertexInputSimple
{
    float4 Position : POSITION0;//SV_POSITION;
    float2 TexCoord : TEXCOORD0;
    //uint InstanceId : SV_InstanceId;
};

struct VSOutputSimple
{
    float4 Position : SV_POSITION;
    float2 TexCoord : TEXCOORD0;
    float4 Color : COLOR0;
};

VSOutputSimple MainVSSimple(in VSVertexInputSimple vertexInput, VSInstanceInputSimple instanceInput)
{
    VSOutputSimple output;
    output.TexCoord = vertexInput.TexCoord;
    float3 InstancePosition = instanceInput.InstancePosition;
    float InstanceTimeOrId = instanceInput.InstanceTimeOrId;
    float movingTime = InstanceTimeOrId * TotalTime + TotalTime;
    float4 posVert = mul(vertexInput.Position, WorldViewProjection);
    float4 posInst = mul(InstancePosition.xyz, WorldViewProjection);
    float4 pos = posVert + posInst;
    output.Position = pos;
    // uncomment the below line for super trippy mode lol
    output.Position = pos * sin(movingTime  * PI2);
    output.Position.x = pos.x * cos(movingTime * PI2) - pos.y * sin(movingTime * PI2);
    output.Position.y = pos.x * sin(movingTime * PI2) + pos.y * cos(movingTime * PI2);
    // change color
    float4 startColor = lerp(float4(1.0, 0.0, 0.0, 1.0), float4(0.0, 0.0, 1.0, 1.0), InstancePosition.x);
    float4 endColor = lerp(float4(0.5, 0.5, 0.0, 1.0), float4(0.0, 1.0, 1.0, 1.0), InstancePosition.y);
    output.Color = lerp(startColor, endColor, (InstancePosition.z + InstanceTimeOrId));
    return output;
}

float4 MainPSSimple(VSOutputSimple input) : COLOR0
{
    float4 col = input.Color * tex2D(TexSampler, input.TexCoord);
    // straight clip alpha draws
    clip(col.a - .05f);
    return col;
}

technique ParticleDrawingSimple
{
    pass
    {
        VertexShader = compile VS_SHADERMODEL MainVSSimple();
        PixelShader = compile PS_SHADERMODEL MainPSSimple();
    }
};

The game1 file

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Runtime.InteropServices;

namespace GLParticleTestTrimed
{
    // the instanceDataType
    [StructLayout(LayoutKind.Sequential)]
    public struct InstanceData : IVertexType
    {
        public Vector3 instancePosition;
        public float instanceTimeOrId;
        public static readonly VertexDeclaration VertexDeclaration;
        static InstanceData()
        {
            var elements = new VertexElement[]
                {
                    new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 1), // oh 0 so bad bad.
                    new VertexElement(12, 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 VertexPositionTexture : IVertexType
    {
        public Vector3 position;
        public Vector2 texCoordinate;
        public static readonly VertexDeclaration VertexDeclaration;
        static VertexPositionTexture()
        {
            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; }
        }
    }

    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        ParticleSystem02 particleSystem;
        Matrix viewProjection;
        Texture2D particleTexture;
        Effect particlesEffect;

        // basically a elaborate timing device.
        float cyclePercentage = 0f;
        public double fullCycleTimeInSeconds = 9d; // you can speed it up or slow it down with this.
        double cycleTime = 0d;
        double elapsedUpdateTime = 0;
        double last = 0d;
        double now = 0d;

        public Game1()
        {
            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()
        {
            SetUpViewProjection();

            particlesEffect = Content.Load<Effect>("ParticleEffect03GL");
            particleTexture = Content.Load<Texture2D>("particle");

            particleSystem = new ParticleSystem02(particlesEffect)
            {
                ParticleSize = new Vector2(2.0f, 2.0f),
                ParticleTexture = particleTexture,
                InitialInstanceCount = 2000500, // Lets push it up to a Million
                //VisiblityDuration = 5.0f,
            };

            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.CreateOrthographic(aspect * width, height, 0.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();

            
            last = now;
            now = gameTime.ElapsedGameTime.TotalSeconds;
            elapsedUpdateTime = now - last;
            cycleTime += elapsedUpdateTime;
            cyclePercentage = (float)(cycleTime / fullCycleTimeInSeconds);
            if (cycleTime > fullCycleTimeInSeconds)
            {
                cycleTime -= fullCycleTimeInSeconds;
            }

            particleSystem.UpdateParticleTime((float)(cyclePercentage));

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);
            //GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Target, Color.Black, 1.0f, 0);
            GraphicsDevice.BlendState = BlendState.Additive;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;

            particleSystem.DrawParticles(viewProjection, GraphicsDevice);

            base.Draw(gameTime);
        }
    }

    public class ParticleSystem02
    {
        // Vertex data
        VertexBuffer vertexBuffer;
        IndexBuffer indexBuffer;
        VertexBufferBinding vertexBufferBinding;

        // Instance data
        InstanceData[] instanceData;
        VertexBuffer instanceBuffer;
        VertexBufferBinding instanceBufferBinding;

        int numInstancesToDraw;
        float totalTime = 0;

        Effect particlesEffect;

        public Vector2 ParticleSize { get; set; }
        public Texture2D ParticleTexture { get; set; }
        public uint InitialInstanceCount { get; set; }
        public int MaxVisibleParticles
        {
            get; private set;
        }
        //public float VisiblityDuration { get; set; }

        #region Initilisation
        public ParticleSystem02(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;
            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 halfWidth = ParticleSize.X / 2;
            float halfHeight = ParticleSize.Y / 2;
            float z = .2f;
            VertexPositionTexture[] vertices = new VertexPositionTexture[4];
            // x,y world positions
            vertices[0].position = new Vector3(-halfWidth, -halfHeight, z);
            vertices[1].position = new Vector3(halfWidth, -halfHeight, z);
            vertices[2].position = new Vector3(-halfWidth, halfHeight, z);
            vertices[3].position = new Vector3(halfWidth, halfHeight, z);
            // 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)(InitialInstanceCount);
            instanceData = new InstanceData[MaxVisibleParticles];
            // set particles randomly
            Random rnd = new Random();
            for (int i = 0; i < MaxVisibleParticles; ++i)
            {
                // instance data float time
                instanceData[i].instanceTimeOrId = -(i + 1) / (float)InitialInstanceCount;
                // instance data float position
                instanceData[i].instancePosition = new Vector3
                    (
                    (rnd.Next(0, 800) - 400),
                    (rnd.Next(0, 600) - 300),
                    rnd.Next(1, MaxVisibleParticles + 1) / (float)(MaxVisibleParticles + 1)
                    );
            }
            //
            instanceBuffer = new VertexBuffer(graphicsDevice, InstanceData.VertexDeclaration, MaxVisibleParticles, BufferUsage.WriteOnly);
            instanceBufferBinding = new VertexBufferBinding(instanceBuffer, 0, 1);
            instanceBuffer.SetData(instanceData);
        }

        #endregion Initilisation

        // 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;
            totalTime += seconds;
        }

        public void DrawParticles(Matrix worldViewProj, GraphicsDevice graphicsDevice)
        {
            // Select the technique.
            particlesEffect.CurrentTechnique = particlesEffect.Techniques["ParticleDrawingSimple"];
            // Initialise our shader constants
            particlesEffect.Parameters["WorldViewProjection"].SetValue(worldViewProj);
            particlesEffect.Parameters["ParticleTexture"].SetValue(ParticleTexture);
            particlesEffect.Parameters["TotalTime"].SetValue((float)totalTime);
            // 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 texture i used

1 Like