Hi, Iv been trying to get the Particle3DSample from XNA to work in Monogame.
Found the “Custom effect: unable to compile 3D Particle Sample effect” thread which helped me compile an .mgfxo file from the .fx using 2MGFX.exe, but I’m getting an error message when trying to build the project.
Error Message:
An error occurred while preparing to draw. This is probably because the current vertex declaration does not include all the elements required by the current vertex shader. The current vertex declaration includes these elements: SV_Position0, SV_Position1, NORMAL0, COLOR0, TEXCOORD0.
Thought maybe that as the error identifies SV_Position0 & SV_Position1 that I could change the shader references ‘POSITION0’ & ‘POSITION1’ to ‘SV_Position0’ & ‘SV_Position1’ but this results in not being able to compile the shader as I get the error:
C:\Program Files (x86)\MSBuild\MonoGame\v3.0\Tools\ParticleEffect.fx(58,23): error X4502: invalid input semantic ‘SV_Position1’: Legal indices are in [0,0]
I’m stuck now and don’t know what the correct semantics of the effect file should be.
Has anyone got this to work and can point me in the right direction?
Also the only file I have changed from the original example project is the fx
My modified ParticleEffect.fx
//-----------------------------------------------------------------------------
// ParticleEffect.fx
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
// Camera parameters.
float4x4 View;
float4x4 Projection;
float2 ViewportScale;
// The current time, in seconds.
float CurrentTime;
// Parameters describing how the particles animate.
float Duration;
float DurationRandomness;
float3 Gravity;
float EndVelocity;
float4 MinColor;
float4 MaxColor;
// These float2 parameters describe the min and max of a range.
// The actual value is chosen differently for each particle,
// interpolating between x and y by some random amount.
float2 RotateSpeed;
float2 StartSize;
float2 EndSize;
// Particle texture and sampler.
texture Texture;
sampler SamState = sampler_state
{
Texture = <Texture>;
MinFilter = Linear;
MagFilter = Linear;
MipFilter = Point;
AddressU = Clamp;
AddressV = Clamp;
};
// Vertex shader input structure describes the start position and
// velocity of the particle, and the time at which it was created,
// along with some random values that affect its size and rotation.
struct VertexShaderInput
{
float2 Corner : POSITION0;
float3 Position : POSITION1;
float3 Velocity : NORMAL0;
float4 Random : COLOR0;
float Time : TEXCOORD0;
};
// Vertex shader output structure specifies the position and color of the particle.
struct VertexShaderOutput
{
float4 Position : POSITION0;
float4 Color : COLOR0;
float2 TextureCoordinate : COLOR1;
};
// Vertex shader helper for computing the position of a particle.
float4 ComputeParticlePosition(float3 position, float3 velocity,
float age, float normalizedAge)
{
float startVelocity = length(velocity);
// Work out how fast the particle should be moving at the end of its life,
// by applying a constant scaling factor to its starting velocity.
float endVelocity = startVelocity * EndVelocity;
// Our particles have constant acceleration, so given a starting velocity
// S and ending velocity E, at time T their velocity should be S + (E-S)*T.
// The particle position is the sum of this velocity over the range 0 to T.
// To compute the position directly, we must integrate the velocity
// equation. Integrating S + (E-S)*T for T produces S*T + (E-S)*T*T/2.
float velocityIntegral = startVelocity * normalizedAge +
(endVelocity - startVelocity) * normalizedAge *
normalizedAge / 2;
position += normalize(velocity) * velocityIntegral * Duration;
// Apply the gravitational force.
position += Gravity * age * normalizedAge;
// Apply the camera view and projection transforms.
return mul(mul(float4(position, 1), View), Projection);
}
// Vertex shader helper for computing the size of a particle.
float ComputeParticleSize(float randomValue, float normalizedAge)
{
// Apply a random factor to make each particle a slightly different size.
float startSize = lerp(StartSize.x, StartSize.y, randomValue);
float endSize = lerp(EndSize.x, EndSize.y, randomValue);
// Compute the actual size based on the age of the particle.
float size = lerp(startSize, endSize, normalizedAge);
// Project the size into screen coordinates.
return size * Projection._m11;
}
// Vertex shader helper for computing the color of a particle.
float4 ComputeParticleColor(float4 projectedPosition,
float randomValue, float normalizedAge)
{
// Apply a random factor to make each particle a slightly different color.
float4 color = lerp(MinColor, MaxColor, randomValue);
// Fade the alpha based on the age of the particle. This curve is hard coded
// to make the particle fade in fairly quickly, then fade out more slowly:
// plot x*(1-x)*(1-x) for x=0:1 in a graphing program if you want to see what
// this looks like. The 6.7 scaling factor normalizes the curve so the alpha
// will reach all the way up to fully solid.
color.a *= normalizedAge * (1-normalizedAge) * (1-normalizedAge) * 6.7;
return color;
}
// Vertex shader helper for computing the rotation of a particle.
float2x2 ComputeParticleRotation(float randomValue, float age)
{
// Apply a random factor to make each particle rotate at a different speed.
float rotateSpeed = lerp(RotateSpeed.x, RotateSpeed.y, randomValue);
float rotation = rotateSpeed * age;
// Compute a 2x2 rotation matrix.
float c = cos(rotation);
float s = sin(rotation);
return float2x2(c, -s, s, c);
}
// Custom vertex shader animates particles entirely on the GPU.
VertexShaderOutput ParticleVertexShader(VertexShaderInput input)
{
VertexShaderOutput output;
// Compute the age of the particle.
float age = CurrentTime - input.Time;
// Apply a random factor to make different particles age at different rates.
age *= 1 + input.Random.x * DurationRandomness;
// Normalize the age into the range zero to one.
float normalizedAge = saturate(age / Duration);
// Compute the particle position, size, color, and rotation.
output.Position = ComputeParticlePosition(input.Position, input.Velocity,
age, normalizedAge);
float size = ComputeParticleSize(input.Random.y, normalizedAge);
float2x2 rotation = ComputeParticleRotation(input.Random.w, age);
output.Position.xy += mul(input.Corner, rotation) * size * ViewportScale;
output.Color = ComputeParticleColor(output.Position, input.Random.z, normalizedAge);
output.TextureCoordinate = (input.Corner + 1) / 2;
return output;
}
// Pixel shader for drawing particles.
float4 ParticlePixelShader(VertexShaderOutput input) : COLOR0
{
return tex2D(SamState, input.TextureCoordinate) * input.Color;
}
// Effect technique for drawing particles.
technique Particles
{
pass P0
{
VertexShader = compile vs_4_0_level_9_1 ParticleVertexShader();
PixelShader = compile ps_4_0_level_9_1 ParticlePixelShader();
}
}