OpaqueComparator optimizations

Or, a total misunderstanding on my part… I’m willing to accept either. :wink:



In my quest to find my missing frames with the upgrade (hint: this isn’t it but worth looking at), I ran across some code that made me scratch my head.



Current code:

[java]

public float distanceToCam(Geometry spat){

if (spat == null)

return Float.NEGATIVE_INFINITY;



if (spat.queueDistance != Float.NEGATIVE_INFINITY)

return spat.queueDistance;



Vector3f camPosition = cam.getLocation();

Vector3f viewVector = cam.getDirection();

Vector3f spatPosition = null;



if (spat.getWorldBound() != null){

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

}else{

spatPosition = spat.getWorldTranslation();

}



spatPosition.subtract(camPosition, tempVec);

spat.queueDistance = tempVec.dot(tempVec);



float retval = Math.abs(tempVec.dot(viewVector)

/ viewVector.dot(viewVector));

viewVector.mult(retval, tempVec);



spat.queueDistance = tempVec.length();



return spat.queueDistance;

}

[/java]



Now, no one will tell you that my vector algebra is weaker than I will but some things in there tripped me up at first. When I saw the thrown away, no-side-effect apparent that I can see, initial setting of queueDistance, I began to wonder if this might be the ‘code of many patches’. So I looked deeper and had some questions in case my understanding is faulty.


  1. Is their ever a case where viewVector is not a vector of length 1?


  2. Is queueDistance ever used for anything other than sorting the opaque bin? (I can’t find anywhere that it is doing a grep through the source code.)



    In my understanding, dotting a vector with itself, as in:

    [java]viewVector.dot(viewVector)[/java]



    At worst, will give you the squared length and of course, at best, if viewVector is unit then you get 1.



    At any rate, presuming that queue distance is only used for sorting then it really shouldn’t matter how long viewVector is. A dot() of tempVec and viewVector is enough to determine relative distance and if viewVector is unit then it is also actual distance. Again, presuming my math is right. I’ve been hit over the head with a text book more than once in these kinds of conversations. :slight_smile:



    Given all of that, I believe the method can be shortened to:



    [java]

    public float distanceToCam(Geometry spat){

    if (spat == null)

    return Float.NEGATIVE_INFINITY;



    if (spat.queueDistance != Float.NEGATIVE_INFINITY)

    return spat.queueDistance;



    Vector3f camPosition = cam.getLocation();

    Vector3f viewVector = cam.getDirection();

    Vector3f spatPosition = null;



    if (spat.getWorldBound() != null){

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

    }else{

    spatPosition = spat.getWorldTranslation();

    }



    spatPosition.subtract(camPosition, tempVec);

    spat.queueDistance = tempVec.dot(viewVector);



    return spat.queueDistance;

    }

    [/java]



    In my scene where the stats report that I have 400 objects, this takes me from ~73 FPS to around 80 FPS. The lack of a sqrt call is probably the biggest of the savings but the other removed calls can’t hurt.



    Unfortunately, similar logic cannot be applied to the transparent comparator as it stands since it uses the distanceToEdge() call which always does a sqrt. (no real choice there presuming the near edge is really the better sort criteria.)

This is most likely a mistake on my part, this code was taken directly from jME2, it made me scratch my head but I didn’t think the founders of jME would make a mistake at such a crucial piece of code.



The distanceToEdge() usage in transparent bucket is intended, it leads to better results when e.g you have a small cube inside a large cube.



Would you like to apply this patch yourself or is it okay if I do it?

Didn’t even know that I could apply patches. :slight_smile: You can do it. I’d get all giddy with power and stuff.



In other scene graphs, the transparent sorting distance thing always comes up as a contentious issue. There is no proper solution as it’s trivial to come up with cases where center is best, near edge is best, etc. For example, an L shaped geometry may be closer bounding shape-wise even if the object sitting in the L is technical “in front”.



Transparent sort if probably fine the way it is… you’d have to have a few hundred transparent objects before it even made a blip in performance.