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.
Problem with Billboarding Instanced Particles
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!
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]
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
Popular Topics
Advertisement