Sorry for the late reply - I got pulled away helping our artist with an unrelated matter. Thanks for the additional replies!
@oblivion165 - I am fearful of adding collision / adjusting their in-world positions. Your approach would definitely solve this issue, but by moving sprites around or away from always being in the exact center of a grid cell, I lose the certainty of units being exactly 1 away from each other. This causes problems with some of our more advanced animations for attacking / blocking / etc that rely on this.
@willmotil - Normally the sprites are actually a little smaller that the screenshot I provided. I scaled them a little larger for testing to give sort of a worst-case for any really large creatures. I figured while I’m working on this I might as well find a solution that works regardless of the actual size of the rendered sprite since they’re not necessarily all the same size. What you’re saying makes perfect sense for limiting the billboard leaning, but I’m seeing some strange skewing when using Matrix.CreateWorld when the sprites are near the edge of the screen. I think perhaps the direction vector to the camera position isn’t playing nicely with the camera being orthographic?
The solution I’m currently using is the one I mentioned in an earlier post - where I simply send a second world matrix I use when calculating depth but otherwise leave the current rendering alone. It is the same world matrix except it uses world up as its Up vector, essentially constraining it not to lean. This seems to be working perfectly when rendering simple textured quads. The below image shows the comparison - the left is without doing this and the right is utilizing this depth world matrix.
Here is the code for how I’m doing it. Any feedback is appreciated, especially if there are any possible concerns about this working. I am still running into issues with Spine using this method, but I’m thinking this may just be an issue with Spine. Basically as soon as I output my own depth value from my pixel shaders it starts acting up, but a normal textured quad has no issues at all.
C# code for setting the shader variables and rendering (with Spine):
Matrix billboardWorld = Matrix.Invert( camera.View );
billboardWorld.Translation = _WorldPosition;
Matrix constrainedBillboardWorld = Matrix.Invert( camera.View );
constrainedBillboardWorld.Up = Vector3.Up;
constrainedBillboardWorld.Translation = _WorldPosition;
skelRender.Effect.Parameters["World"].SetValue( worldScale* billboardWorld );
skelRender.Effect.Parameters["Projection"].SetValue( camera.Projection );
skelRender.Effect.Parameters["View"].SetValue( camera.View );
skelRender.Effect.Parameters["DepthWorld"].SetValue( worldScale* constrainedBillboardWorld );
skelRender.Begin();
skelRender.Draw(skel );
skelRender.End();
And the shader code. I’ve tried to remove all the light code to make it easier to read so if anything looks like it’s missing that is why:
matrix World;
matrix DepthWorld;
matrix View;
matrix Projection;
struct VSInput
{
float4 position : POSITION0;
float4 color : COLOR0;
float2 texCoord : TEXCOORD0;
//Passed down but unused
//float4 color2 : COLOR1;
};
struct VSOutput
{
float4 position : SV_Position;
float4 color : COLOR0;
float2 texCoord : TEXCOORD0;
float depthValue : TEXCOORD1;
float3 WorldPos : TEXCOORD2;
};
sampler TextureSampler : register( s0 );
VSOutput VSQuad(VSInput input)
{
VSOutput output;
float4 worldPosition = mul(input.position, World);
float4 viewPosition = mul(worldPosition, View);
output.position = mul(viewPosition, Projection);
float4 depthWorldPosition = mul(input.position, DepthWorld);
float4 depthViewPosition = mul(depthWorldPosition, View);
output.depthValue = mul(depthViewPosition, Projection).z;
output.texCoord = input.texCoord;
output.color = input.color;
// Need the world position for lighting effects in Pixel Shader
output.WorldPos = mul(input.position, World).xyz;
return output;
}
struct PSOutput
{
float4 color : SV_Target;
float depth : SV_Depth;
};
//float4 PSQuad(VSOutput input) : SV_TARGET
PSOutput PSQuad(VSOutput input)
{
float4 baseColor = tex2D( TextureSampler, input.texCoord );
baseColor *= input.color;
clip(baseColor.a < 0.8f ? -1 : 1);
// Lighting Code
PSOutput output;
output.color = baseColor * float4(totalLight, 1.0f);
output.depth = input.depthValue;
return output;
}
float4 PSQuadAlpha(VSOutput input) : SV_TARGET
{
float4 baseColor = tex2D(TextureSampler, input.texCoord);
baseColor *= input.color;
clip(baseColor.a >= 0.8f ? -1 : 1);
// Lighting Code
return baseColor * float4(totalLight, 1.0f);
}
technique CharacterLit
{
pass P0
{
AlphaBlendEnable = false;
ZEnable = true;
ZWriteEnable = true;
VertexShader = compile vs_4_0 VSQuad();
PixelShader = compile ps_4_0 PSQuad();
}
pass P1
{
AlphaBlendEnable = true;
ZEnable = true;
ZWriteEnable = false;
PixelShader = compile ps_4_0 PSQuadAlpha();
}
}