Math help?

I have a line in 3d. I need to find the angle between start and stop in camera cords. Every thing i tried did not work well. Maybe you can solve it? The inputs are A,B - line stand and end and the C - camera position.

Thanks!

  1. calculate vectors CA and CB using vector subtraction
  2. normalize CA and CB
  3. angle = acos(dot(CA, CB))

Arkaein, yes but this will be in 3d space. I want in camera space. There is no function to convert angles to camera space hence my biggest problem.

By camera space you mean the space represented by base.camera node?

You could associate two nodes to positions A and B then use the wrtReparentTo function to set them as childs of base.camera without changing their position in the world.

The building a axis angle from the cross product and the dot product of these two vectors.

I might be missing the problem entirely, but to get the angle from the camera to the points of the line in camera space should be

a = base.camera.getRelativePoint(render,A).relativeAngleDeg(base.camera.getRelativePoint(render,B))

note that this is only the angle between the vectors…not from an axis.

treeform, I think you need to be clearer about exactly what you want. “Angles in camera space” doesn’t make any sense because an angle is a scalar quantity, only vectors exist in any sort of space. So it seems you either want some sort of vectors, or angles relative to some aspect of the camera such as the look direction vector.

Do you actually want the 2D projections of each point, e.g., to draw a line between the 3D points using a 2D line in screen space? In which case you may just want to project each 3D point to determine the 2D points, using the camera’s lens:

panda3d.org/apiref.php?page=Lens#project

well see what i really want to do is draw paths in 3d that always face the user like a billboard. So i need the vectors to be parallel cameras side and up vector as well as having a consistent angle between them (less parallelogram like effect)

I guess i am not sure what i want at this point …

Your solution might work except that if the angle is not in cameras frustum i think it will mess up.

Okay, so you want to display rectangular objects that have a rotation determined by two points in a scene, but without the perspective projection that is normally associated with rendering 3D objects?

That would be tricky. Something like this is doable, but there will be some kind of sever distortions no matter what approach you take. If you imagine moving the camera such that the two points overlap each other on the screen then the billboard will either have to shrink down to nothing (if the aspect ratio of the billboard is preserved), or it will get squished down into a thin line (if the height of the billboard stays constant but the length varies based on the screen space distance between the two points).

No i would like the size of the line be perspective in view. I just want the line to always face the camera. Right now i draw a cross plane sot hat there is always geometry in the line but then the “flat” looking pice always looks odd.

Okay, I think I understand now. So you want essentially a billboard on an axle (which is the path between the points), so that when the camera moves the billboard will rotate around that axle to face the camera as much as possible.

It won’t be able to perfectly face the camera most of the time because the rotation will be restricted.

So I think what you really want is the angle between the camera look direction (projected onto a plane perpendicular to the axis vector) and a “default” billboard rotation’s forward vector. This angle would tell you how much to rotate the billboard around the axis so that it always faces the camera as much as possible.

This is also tricky. Part of the problem is that it requires defining a sort of default rotation (or at least facing direction) for each billboard. Let’s try anyways, in pseudocode:

  1. axis = normalize(A - B)
  2. defaultVec = normalize(cross(axis, up))
  3. camToAxis = C - A
  4. camToAxisProj = normalize(camToAxis - axis * dot(camToAxis, axis))
  5. angle = acos(dot(defaultVec, camToAxisProj))

To use this, you would first need to define a transformation for the billboard that uses defaultVec and set the appropriate billboard position. Then, for each frame you calculate angle and use this to determine a rotation around axis which is applied on top of the default transformation.

Also note that this method will fail if axis is parallel to up. Up is just an arbitrary vector that is needed to define a complete coordinate system for the billboard, and can be any vector which is not nearly parallel to axis.

Hope this helps.

Arkaein, wow it does.
Ill try this code out and see how it goes. I kinda get lost in the math though.

Note that the Rope class includes an RMBillboard rendering method which achieves the sort of axial billboard rotation you describe. It works well except when the camera is nearly looking down the rope, of course, in which case it starts to look a little weird.

David

treeform, I was thinking about this, and although the Rope class method David mentioned is probably the way to go there is actually a much simpler method to calculate the rotation for the billboard in matrix form.

You start with two vectors: L, the look (or forward) vector of the camera, and A, the axis calculated as the normalized difference of the two points.

Next calculate T as the normalized cross-product of L and A. This is the perpendicular of the billboard axis (basically A runs left to right on the billboard, while T will run bottom to top). Finally calculate P as the cross-product of T and P.

This will give you three unit length vectors which form the rows of the rotation matrix for your billboard, which I believe can be set manually and converted into a standard Panda3D rotation. Set the correct position and a scale factor proportional to the distance between the two points and you have a complete billboard.