Problem with Billboarding Instanced Particles

Started by
1 comment, last by FromShadow 11 years, 5 months ago
Hello,

I am having a hard time billboarding my particles. I am following this tutorial:
http://xnauk-randomc...utorial-vi.html

The instancing is not a problem and works. I understand the formulas for billboarding given in the link, but when I implement them, the particles disappear. The difference in my implementation is that I represent the particles by a position only, while the tutorial uses world matrices.

Here is the relevant shader code:

[source lang="cpp"]
struct InstanceData
{
float4 Position : TEXCOORD1;
float4 Velocity : TEXCOORD2;
float4 Acceleration : TEXCOORD3;
float T0 : FOG0;
float T1 : FOG1;
};

struct VSInput
{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
};

struct VSOutput
{
float4 Position : POSITION0;
float2 TextureCoordinate : TEXCOORD0;
float Alpha : FOG0;
};

VSOutput InstancingVS(VSInput input, InstanceData instance)
{

VSOutput output = (VSOutput)0;

// Calculate the particle's position
float dt = T - instance.T0;
input.Position += instance.Position;
input.Position += dt * instance.Velocity;
input.Position += 0.5 * dt * dt * instance.Acceleration;

// start using float3 because we need cross products
float3 center = mul(input.Position, World); // looks fishy since input.Position is float4, but it works in the tutorial
float3 eyeVector = center - CameraPosition;

float3 pos = center;
float3 sideVector;
float3 upVector;
sideVector = normalize(cross(eyeVector, (float3)(0, 1, 0)));
upVector = normalize(cross(sideVector, eyeVector));


// Billboarding offset
pos += (input.TextureCoordinate.x - 0.5) * sideVector;
pos += (0.5 - input.TextureCoordinate.y) * upVector;

// pack into float4
float4 pos4 = (float4)(pos, 1);

pos4 = mul(pos4, View);
pos4 = mul(pos4, Projection);

output.Position = pos4;
output.TextureCoordinate = input.TextureCoordinate;
output.Alpha = (instance.T1 - T) / (instance.T1 - instance.T0);

return output;

}

float4 InstancingPS(VSOutput input) : COLOR0
{

float4 color = tex2D(TextureSampler, input.TextureCoordinate);

color.a = color.a * input.Alpha;

return color;

}
[/source]

Now, I suspect there is something wrong with float3/float4 mixture. For example, If I change line 50 to

[source lang="cpp"]
float4 pos4 = input.Position;
[/source]

the particles are drawn correctly, but without billboarding, which is expected. However, if I try

[source lang="cpp"]
float4 pos4 = (float4)(input.Position.xyz, 1);
[/source]

which I assumed to do basically the same thing, I see nothing.
Can somebody explain this? I don't see the difference between the these two lines (except for the w-compenent, which shouldn't matter, should it?). I have been fiddling with those conversions for two days now and I am very much lost.

Appreciating any help.
Advertisement
How about :

float4 pos4 = float4(input.Position.xyz, 1); //just to verify that it isn't question of syntax.

the w-component needs to 1 for the projection matrix multiplication to work correctly. If the w component is 0 then the result will be 0 too which isn't good.

By the standard, if your position is defined as 3-component vector from the program side and float4 in the shader side, the 4th component is automatically given value of 1.0.

float3 center = mul(input.Position, World); // There is nothing fishy here. The input.Position is multiplied by the 4x4 world matrix which doesn't affect the w-component typically. The cast of float4 to float3 works as intended ie. the xyz components are copied.

Cheers!
Feeling like a total scrub now. Your correction works.
The particles are visible now and do turn (arround some wrong axis, though).
I think I can safely work from here. ^^

Thanks a lot, and sorry for this stupidity.

Edit:
Here is the new shader with a workarround using the View matrix for the billdboard orientation.
This way I don't need to use float3 at all.

[source lang="cpp"]
VSOutput ParticleVS(VSInput input, InstanceData instance)
{

VSOutput output = (VSOutput)0;

float lifeTimeFactor = (instance.T1 - T) / (instance.T1 - instance.T0);
input.Position *= instance.Size * lifeTimeFactor;

// transform to Screenspace
float4x4 transform = transpose(View);
transform[3] = 0;
input.Position = mul(input.Position, transform);

// Calculate the particle's position
float dt = T - instance.T0;
input.Position += instance.Position;
input.Position += dt * instance.Velocity;
input.Position += 0.5 * dt * dt * instance.Acceleration;

float4 pos4 = mul(input.Position, World);
pos4.w = 1;
pos4 = mul(pos4, View);
pos4 = mul(pos4, Projection);

output.Position = pos4;
output.TextureCoordinate = input.TextureCoordinate;
output.Alpha = lifeTimeFactor;

return output;
}[/source]

This topic is closed to new replies.

Advertisement