Search code examples
c#wpf3dviewportmodelvisual3d

Align 3d Object to Camera position


I am using the Viewport control to visualize 3d Tool Models with the help of AB4D PowerToys.

Currently I'm trying to align my 3D Text (which is a group of lines) to the camera, so it rotates always to the camera and appears like 2D text.

Is it possible to bind the Transformation of my Visual to the position of my camera?


Solution

  • Finally found the answer myself:

    The following code should be called on the "CameraChanged" Event.

    private void UpdateTransforms()
        {
            if (!this.IsAttachedToViewport3D())
            {
                return;
            }
    
            Matrix3D view, projection;
            if (Camera.GetCameraMatrixes(out view, out projection))
            {
                Vector3D up = new Vector3D(view.M12, view.M22, view.M32);
                Vector3D look = new Vector3D(view.M13, view.M23, view.M33);
    
                Transform3D transform = Transform;
                Matrix3D inverseWorld = this.GetTransform();
                inverseWorld.Invert();
    
                look = inverseWorld.Transform(look);
                look.Normalize();
    
                up = inverseWorld.Transform(up);
                up.Normalize();
    
                Quaternion q = LookAtRotation(look, up);
    
                Transform3DGroup grp = new Transform3DGroup();
                grp.Children.Add(new RotateTransform3D(new QuaternionRotation3D(q), CenterPosition));
                grp.Children.Add(transform);
                Transform = grp;
    
                Camera.Refresh();
            }
        }
    
        private static Quaternion LookAtRotation(Vector3D lookAt, Vector3D upDirection)
        {
            Vector3D forward = lookAt;
            Vector3D up = upDirection;
    
            // Orthonormalize
            forward.Normalize();
            up -= forward * Vector3D.DotProduct(up, forward);
            up.Normalize();
    
            Vector3D right = Vector3D.CrossProduct(up, forward);
    
            Quaternion q = new Quaternion
            {
                W = Math.Sqrt(1.0 + right.X + up.Y + forward.Z) * 0.5
            };
    
            double w4Recip = 1.0 / (4.0 * q.W);
            q.X = (up.Z - forward.Y) * w4Recip;
            q.Y = (forward.X - right.Z) * w4Recip;
            q.Z = (right.Y - up.X) * w4Recip;
    
            return q;
        }