I've been at this for nearly 10 hours going in circles trying to get Alpha transparency working with the depth buffer. I'm fairly certain what's causing my issue is that I need to draw my transparent models from back-to-front based on how close they are to the camera, but I can't ever seem to get it working properly. Any help would be appreciated, but please, do not offer order-independent transparency.
Image of what it looks like: https://i.stack.imgur.com/UGR3j.png
As you can see, the sphere on the left is bleeding through the observing sphere, and the sphere on the right is blending as it should. The right-sided sphere was drawn first, the observing drawn second, and the left-sided drawn last.
Snips of code:
Each entity has it's own draw function as follows:
public void Draw()
{
var worldMatrix = Transform * MathConverter.Convert(entity.WorldTransform);
model.CopyAbsoluteBoneTransformsTo(boneTransforms);
foreach (ModelMesh mesh in model.Meshes)
{
foreach (BasicEffect effect in mesh.Effects)
{
effect.Alpha = alpha;
//If we have a texture enable it and set it, then remove colour
if (texture != null)
{
effect.TextureEnabled = true;
//Texture2D ModifiedTexture = new Texture2D()
effect.Parameters["Texture"].SetValue(texture);
//But only if colour isn't set
if (colour == null)
effect.AmbientLightColor = Color.White.ToVector3();
}
else
{
effect.TextureEnabled = false;
effect.AmbientLightColor = Color.Brown.ToVector3();
}
//If colour is set and isn't what we want, thrn set it to the lighting of the model
if (colour != null && effect.AmbientLightColor != colour.ToVector3())
effect.AmbientLightColor = colour.ToVector3();
effect.World = boneTransforms[mesh.ParentBone.Index] * worldMatrix;
effect.View = MathConverter.Convert((Game as Game1).camera.ViewMatrix);
effect.Projection = MathConverter.Convert((Game as Game1).camera.ProjectionMatrix);
}
mesh.Draw();
}
}
Draws are called from the main Draw function:
foreach (EntityModel mdl in Globals.MainObjects)
{
if (mdl.alpha >= 1)
{
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque;
mdl.Draw();
}
else
{
GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.AlphaBlend;
mdl.Draw();
}
}
And the LinkedList of entities to draw is currently sorted like so:
if (MainObjects.Count() >= 1)
MainObjects = new LinkedList<EntityModel>(MainObjects.OrderByDescending(i => i.alpha).ThenBy(l => l.entity.InstanceId));
TL;DR I need to sort the models by their depth from the camera but don't know how to do so and am looking for either help in what needs to be done and how it could be done or raw code that can do this.
edit: Currently made a small amount of progress facing a different problem. Sorting by DepthIndex (see below) causes some form of clipping to happen based on the camera's angle.
DepthIndex = Microsoft.Xna.Framework.Vector3.Transform(MathConverter.Convert(entity.Position), MathConverter.Convert((Game as Game1).camera.ViewMatrix * (Game as Game1).camera.ProjectionMatrix)).Z;
Each column is of the same frame with a block that is either rendered with transparency or not at all. When there is transparency some are cut, but when there is not all appear fine.
edit2: Source project by request: (removed)
It's written in VS2013 XNA4.0 .NET-4.5.