Calculating distance to camera?

How do I calculate distance to camera in cull_callback?

The Lodnode.cxx file contains:

CPT(TransformState) rel_transform = 

LPoint3f center = cdata->_center * rel_transform->get_mat();

// Determine which child to traverse
float dist = fabs(dot(center, LVector3f::forward()));

However, its not easily obvious what any of this means; and in particular _center seems to be passed-in from another class perhaps?

I’m guessing that _center is the position of our node? That we’re transforming into… camera? … coordinates.

Then once its in camera coordinates, we can just dot it with the cameras forward vector, in camera coordinates, which is just <1,0,0>, or similar.

It looks like the line to get rel_transform, which is I guess the transform from world coordinates to camera coordinates?, will compile ok, so maybe this is good?

So, I guess that we just need to be able to obtain the coordinates of our node, and plug this into _center?


Ok, I think I found it:

  CPT(TransformState) rel_transform = 

 // LPoint3f center = cdata->_center * rel_transform->get_mat();
   LPoint3f objectposobjectaxes;
   LPoint3f objectposworldaxes = objectposobjectaxes * data._net_transform->get_mat();
   LPoint3f objectposcameraaxes = objectposworldaxes * rel_transform->get_mat();

But actually, thinking about it, I guess what I want perhaps is the size of the object on the screen in pixels? Thats probably the most hardware-independent indicator of the level of detail required?


That’s close, but I think it’s not completely right.

First, let me explain about _center in the LODNode: that’s supposed to be the effective center of the node, in its own local coordinate space. It’s very often (0, 0, 0). The cdata-> bit is just to dereference the thread-dependent part of the LODNode; again, imagine that everything within cdata is actually within the node itself.

The reason we have a _center member at all, instead of assuming that everything is always centered at (0, 0, 0), is because that option allows you to apply the LODNode’s local transform onto its vertices, performing what is called a “flatten transform” or “zero transform” in some modeling packages, which can have a performance benefit by removing unneeded transforms in the scene graph.

The rel_transform that is computed is actually the relative transform from local coordinate space to camera coordinate space. Specifically, it is the composition of get_cull_center()->get_net_transform(), which is camera-to-world, and data._net_transform, which is local-to-world. The invert_compose() operation inverts the first transform, so the actual composition is world-to-camera composed with local-to-world, and the resulting transform is local-to-world-to-camera, a.k.a. local-to-camera.

Since rel_transform already includes data._net_transform, you shouldn’t apply that transform to your objectposobjectaxes. If you simply multiply (0, 0, 0) by rel_transform, you will obtain the value of (0, 0, 0) in your object’s coordinates, expressed in camera coordinates; and yes, dot that with the forward vector to get the linear distance.

Whether the linear distance from the camera is the most appropriate metric for deciding LOD switching is a matter of some debate. Certainly it is easy to compute, and it is roughly proportional to the square root of the number of pixels onscreen, so it’s related.

You can go further to get the approximate number of pixels if you assume your object is roughly spherical; but you still need to know the field of view of the camera lens and the size of the DisplayRegion in pixels. All that is available, but it’s not clear whether including it actually adds enough value to justify the additional calculation.

(Note from experience: It turns out that there are LOD cases in which pixel size is not the appropriate metric. We once developed a game that involved, among other things, a complex doorway that turned into a painted flat off in the distance. We were using an engine at the time that automatically scaled LOD switching distances according to the size of the window, to approximate pixel-dependent switches. We developed the game at something like 1024x768, and it worked fine; but then we found that when we ran the game at 640x480, we bumped into the low-level LOD of the doorway–because it didn’t think it needed to switch at the new lower resolution.)