Transparency difficulties

I am currently experimenting with the creation of a 3D editor. So far so good - except that I have a minor transparency problem. I haven’t been able to find a solution so far, so I am posting it here, hope it can ring any bells in any of the experienced developers here…



The problem is as following: to guide the user, I present 3 rectangles, each of them representing a basic plane (XY, XZ, YZ). Each rectangle consists of an outline and a transparent rectangle inside it. I disabled back face culling on these, enabled alpha and put them into the transparency queue bucket.



This gives me the following result:

http://i.imgur.com/04upZ.png



As you can see, the transparency does work… but not exactly as it should. Sometimes the transparency of the overlapping rectangles does not add up. I assume the problem is the drawing order of the rectangles.



Trying to split up each of the rectangles into 4 smaller rectangles to enable them to be ordered properly does not seem to fix the issue. Does anyone here have an idea how to get these ordered properly - preferably without having to write my own code to order the rectangles.



It should be noted that users will be able to add any number of planes to help them draw their model, so the method that is used should be scalable. It can be assumed that many planes will be overlapping.

The problem is that the centers of all 4 rectangles are at the same point - so sorting doesn’t know what order to render them in.



I’m surprised splitting them didn’t work though, what did you do in that case?

With those uniformly colored rectangles, the order should be irrelevant, unless… since the lines around the rectangles are visible, I would guess that you set the stuff correctly, but just in case: What are depth write and ztest set to? Depth write should be turned off, ztest should be turned on.

2 Likes

In fact I have tried two different approaches towards splitting.

  • The 4 smaller rectangles in each plane, as well as the outline, are added to a node. (one node for each plane)
  • The 4 smaller rectangles are added to the root node. The outline is still in a node specifically for each plane.



    I tried the second approach in case the assignment to nodes would affect the ordering.



    This snippet of code takes care of the creation of each plane (2nd approach):

    [java]

    /* Imports skipped for clarity */



    public class PlaneNode extends Node {

    private static final Material MAT_QUAD;

    private static final Material MAT_LINES;



    static {

    MAT_QUAD = new Material(Abstract3DEditorView.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

    MAT_QUAD.setColor("Color", new ColorRGBA(16/255f,127/255f,201/255f, 0.2f));

    MAT_QUAD.getAdditionalRenderState().setBlendMode(BlendMode.Alpha);

    MAT_QUAD.getAdditionalRenderState().setFaceCullMode(RenderState.FaceCullMode.Off);



    MAT_LINES = new Material(Abstract3DEditorView.assetManager, "Common/MatDefs/Misc/Unshaded.j3md");

    MAT_LINES.setColor("Color", new ColorRGBA(14/255f,78/255f,173/255f, 1f));

    }



    public PlaneNode(Node parent, Vector3f center, Vector3f dir1, Vector3f dir2) {

    dir1 = dir1.normalize();

    dir2 = dir2.normalize();



    Mesh quad1 = new Mesh();

    quad1.setMode(Mesh.Mode.TriangleFan);

    quad1.setBuffer(VertexBuffer.Type.Position, 3, new float[] {

    center.x - 0.5f * dir1.x - 0.5f * dir2.x, center.y - 0.5f * dir1.y - 0.5f * dir2.y, center.z - 0.5f * dir1.z - 0.5f * dir2.z,

    center.x - 0.5f * dir2.x, center.y - 0.5f * dir2.y, center.z - 0.5f * dir2.z,

    center.x, center.y, center.z,

    center.x - 0.5f * dir1.x, center.y - 0.5f * dir1.y, center.z - 0.5f * dir1.z

    });

    Geometry quadGeom1 = new Geometry("quad1", quad1);

    quadGeom1.setMaterial(MAT_QUAD);

    quadGeom1.setQueueBucket(Bucket.Transparent);

    parent.attachChild(quadGeom1);



    Mesh quad2 = new Mesh();

    quad2.setMode(Mesh.Mode.TriangleFan);

    quad2.setBuffer(VertexBuffer.Type.Position, 3, new float[] {

    center.x - 0.5f * dir2.x, center.y - 0.5f * dir2.y, center.z - 0.5f * dir2.z,

    center.x + 0.5f * dir1.x - 0.5f * dir2.x, center.y + 0.5f * dir1.y - 0.5f * dir2.y, center.z + 0.5f * dir1.z - 0.5f * dir2.z,

    center.x + 0.5f * dir1.x, center.y + 0.5f * dir1.y, center.z + 0.5f * dir1.z,

    center.x, center.y, center.z

    });

    Geometry quadGeom2 = new Geometry("quad2", quad2);

    quadGeom2.setMaterial(MAT_QUAD);

    quadGeom2.setQueueBucket(Bucket.Transparent);

    parent.attachChild(quadGeom2);



    Mesh quad3 = new Mesh();

    quad3.setMode(Mesh.Mode.TriangleFan);

    quad3.setBuffer(VertexBuffer.Type.Position, 3, new float[] {

    center.x - 0.5f * dir1.x, center.y - 0.5f * dir1.y, center.z - 0.5f * dir1.z,

    center.x, center.y, center.z,

    center.x + 0.5f * dir2.x, center.y + 0.5f * dir2.y, center.z + 0.5f * dir2.z,

    center.x - 0.5f * dir1.x + 0.5f * dir2.x, center.y - 0.5f * dir1.y + 0.5f * dir2.y, center.z - 0.5f * dir1.z + 0.5f * dir2.z

    });

    Geometry quadGeom3 = new Geometry("quad3", quad3);

    quadGeom3.setMaterial(MAT_QUAD);

    quadGeom3.setQueueBucket(Bucket.Transparent);

    parent.attachChild(quadGeom3);



    Mesh quad4 = new Mesh();

    quad4.setMode(Mesh.Mode.TriangleFan);

    quad4.setBuffer(VertexBuffer.Type.Position, 3, new float[] {

    center.x, center.y, center.z,

    center.x + 0.5f * dir1.x, center.y + 0.5f * dir1.y, center.z + 0.5f * dir1.z,

    center.x + 0.5f * dir1.x + 0.5f * dir2.x, center.y + 0.5f * dir1.y + 0.5f * dir2.y, center.z + 0.5f * dir1.z + 0.5f * dir2.z,

    center.x + 0.5f * dir2.x, center.y + 0.5f * dir2.y, center.z + 0.5f * dir2.z

    });

    Geometry quadGeom4 = new Geometry("quad4", quad4);

    quadGeom4.setMaterial(MAT_QUAD);

    quadGeom4.setQueueBucket(Bucket.Transparent);

    parent.attachChild(quadGeom4);



    Mesh lines = new Mesh();

    lines.setMode(Mesh.Mode.LineLoop);

    lines.setBuffer(VertexBuffer.Type.Position, 3, new float[] {

    center.x - 0.5f * dir1.x - 0.5f * dir2.x, center.y - 0.5f * dir1.y - 0.5f * dir2.y, center.z - 0.5f * dir1.z - 0.5f * dir2.z,

    center.x + 0.5f * dir1.x - 0.5f * dir2.x, center.y + 0.5f * dir1.y - 0.5f * dir2.y, center.z + 0.5f * dir1.z - 0.5f * dir2.z,

    center.x + 0.5f * dir1.x + 0.5f * dir2.x, center.y + 0.5f * dir1.y + 0.5f * dir2.y, center.z + 0.5f * dir1.z + 0.5f * dir2.z,

    center.x - 0.5f * dir1.x + 0.5f * dir2.x, center.y - 0.5f * dir1.y + 0.5f * dir2.y, center.z - 0.5f * dir1.z + 0.5f * dir2.z

    });

    lines.setLineWidth(2.0f);

    Geometry linesGeom = new Geometry("lines", lines);

    linesGeom.setMaterial(MAT_LINES);

    attachChild(linesGeom);

    }

    }

    [/java]

Depth write was on. Turning it off fixed the problem.



Thanks!

getAdditionalRenderState().setDepthWrite(false);



Edit: Ah you found it yourself.

could you show a screenshot of the correct result? thx

Sure! Here it is:







Note that in the meantime I have added 3 green axis for further clarity.



I have also simplified my code such that it now uses only 1 rectangle - since cvlad made the intelligent note that the drawing order is irrelevant. (I hope, though, that it doesn’t interfere with future modifications).

1 Like

Just a few notes in case it comes up in the future:

  1. as full quads, no rendering order would have been correct. There is no back to front rendering order that would have worked because this is a textbook example of a case where sorting is fully ambiguous. No matter which quad you pick to render first there is always one behind it.
  2. The reason splitting them didn’t work is because 0,0 was always in the same place. You created the meshes in the different locations instead of translating the geometries. So all of them were still at the same location with the same bounding volume.



    Your solution of not writing depth is the probably the proper one because I assume you intend to render objects there later… and in that case you wouldn’t want them partly obscured by one of the planes if they are also transparent. If they use anything other than straight alpha blending then you will again run into sorting issues, though.
2 Likes

Yeah, number 1 was obvious to me pretty quick.



As of number 2 - that is good to know. Although I won’t need that knowledge for now, it may come in handy later. Thanks!