Alpha blending artifacts, probable noob question

I'm doing a card game.  I have the felt as a quad in the background, and then three cards which slightly overlap.  The cards have a texture with Alpha 0.0 corners, so the cards look like they have rounded corners.  When the cards are static, alpha blending works fine; however, when I animate the cards to flip them face up, the corners wind up with artifacts of the felt showing through.  It looks exactly like what happens when I render a similar scene in the wrong order in OpenGL.



I'm setting the quads that make up the cards to QUEUE_TRANSPARENT, which I thought would work.  But, it doesn't.  What should I be looking for as the culprit here?  (I'll be glad to post code if you think that will help.)

could you post a screenshot of the artifacts?

Make sure the card has a gap between the felt and each card.  When moving them, don't let the quad cut through any other polygons.  Hopefully that the problem since its easy to fix.


After finally finding some webhosting I still have access to: http://astro.temple.edu/~netzaper/artifact.png.

That looks like a zOrder problem… The top card is rendered before the card under it, try making it the other way around by using the newly improved setZOrder(int zOrder, boolean setOnChildren) in Spatial. (This only works in QUEUE_ORTHO, if you want to use QUEUE_TRANSPARENT I have no idea what to do)

I really don't want to put them in the ortho queue, as they aren't always orthogonal to the viewing axis.  They're cards on a table… they routinely flip into the Z axis.



However, I agree that they appear to be drawing in the incorrect order.  I don't understand it, actually.  Isn't the transparent queue supposed to render back to front for precisely this reason?



The cards do intersect in the course of the animation, but the artifacts I posted occur only after the animation has ended and they are once again in good order.  Does the fact that they once intersected screw up the depth buffering from there on in?  I'm clearing the depth buffer (via Renderer.clearBuffers()) before rendering each frame.



Thanks for ya'll's suggestions so far.

Z-fighting maybe? Try to make the z distance between the cards a bit larger, just as a test.

If I put a proportionally huge gap, I can reduce the frequency with which I see the artifacts.  However, I cannot make them disappear.



I've also made sure that they don't interpenetrate when they're flipping.

Try printing out the distance from the camera location to each card's worldTranslation.  That is what ordering uses to do back to front.

Okay, then I'd like to make a bug report. grin



Since the queuing is based on the distance from the camera, X-Y translations make as much difference as the Z translation.  The result is that the X difference in the cards causes the right-most two cards to be closer to the camera (and hence rendered sooner) than the cards that are closer in the Z direction but not in the X.



It seems that a better ordering scheme would be to project the centerpoints of the queued entities onto a ray from the center of the camera's view, take those distances, and then order based on that.

I know it's a bit of a workaround, but could you just use polygons for the rounded corners?



I had a similar problem in my game with intersecting transparent polygons, luckily they were blended in "add" mode so I could just disable the z-buffer writing on those nodes, to stop them hiding each other. Your problem seems much trickier :frowning:



Just one thought - is there any guarantee as to the order in which nodes are drawn, if they are NOT in the transparent queue? If so, could you sort the cards as children of a node, by "height above the table"? It seems like that could fix the draw issue from any angle. You could either do it brute force by moving the children around in a normal Node, or subclass Node to use a sorted list for children. That might be quite a useful technique for anything like that, like little displays in world space (assuming they are not already using Swing :slight_smile: or decals on walls, etc.

I could use polygons for the rounded corners… and, if I can't fix this problem, that's what we'll do.



Right now, however, I'm editing RenderQueue so that it computes distances to camera in a less pathological manner.

So, here's the patch to RenderQueue.java.  It could probably use a bit of cleanup, obviously.  But, this patch completely solves my problem–and it looks like the rest of rendering is unaffected, as well.



    /**

    * Calculates the distance from a spatial to the camera. Distance is absolute.

    *

    * @param spat

    *            SceneElement to distancize.

    * @return Distance of spat from camera along view axis.

    */

    private float distanceToCam(SceneElement spat) {

if (spat.queueDistance != Float.NEGATIVE_INFINITY)

                return spat.queueDistance;

Camera camera = renderer.getCamera();

        spat.queueDistance = 0;



Vector3f camPosition = camera.getLocation();

Vector3f spatPosition = null;

Vector3f viewVector = camera.getDirection();



        if (Vector3f.isValidVector(camera.getLocation())) {

            if (spat.getWorldBound() != null && Vector3f.isValidVector(spat.getWorldBound().getCenter())){

                spatPosition = spat.getWorldBound().getCenter();

    }

            else if (spat instanceof Spatial && Vector3f.isValidVector(((Spatial)spat).getWorldTranslation())){

spatPosition = ((Spatial) spat).getWorldTranslation();

    }

}



Vector3f spatVector = spatPosition.subtract(camPosition);



float retval = Math.abs(spatVector.dot(viewVector) / viewVector.dot(viewVector));

viewVector = viewVector.mult(retval);



spat.queueDistance = viewVector.length();

        return spat.queueDistance;

    }

Hmm, so now running the TestRenderQueue, the transparent box intersecting the other box will change as I rotate the camera.  I guess that is ok?  I'd like a better transparent test to confirm though as this is a potentially big behavior change for renderqueue

Further testing with a much more complex example (terrain with tons of trees… etc.) shows no artifacts, perhaps even 1 less pop than the original.  One question though, it seems like the "project to camera ray" method would have problems sorting objects with objects on the edge of your vision?  like if two objects were on the left edge of my vision and one was closer to the plane of my camera, but it was further left than the other object, it would still get rendered first…  Trying to visualize if that would be a problem.  Any thoughts?



Edit: I've gone ahead and checked this in and cleaned it up to get rid of extra object creation.  I think it looks good, but we can roll back if there are unforeseen issues.

I thought about the edge-of-vision issue as well.  You may be right. 



But, I think the problem comes from the use of centroids to define locations for sorting.  If you draw points on a piece of paper, you can quickly see that in order for the render order of two points to matter, they must be colinear with the center of the camera.  In such a case, the projected vector length of the occluded point is necessarily longer than that of the foreground point.



The problem comes when we stop drawing points, and start drawing volume-defining polygons.  Draw boxes around your points, and you can see that the local origins no longer have to be colinear.  But, with the distance-from-camera approach, you get the exact same sorts of problems.  Especially since the centroid isn't even computed, but is simply a local definition of [0 0 0], you're always going to have these problems.



A ray-intersection approach would provide the best results, I think–but, I also think that it might be much slower.  I'll think about it while I continue working.

Cool, keep the suggestions coming.  :slight_smile: