10-11-2017, 12:37 PM
(This post was last modified: 10-11-2017, 12:41 PM by tim.rutter.)

I am creating a view in which I want to highlight certain 3D points. The object I use to highlight the point is a cross hair and I need this object to stay in the selected 3D location but scale as the camera is zoomed/panned so that the cross hair is always the same size. I'm struggling to work out the maths to calculate the object size based on the camera distance and width.

What I'm doing at present is drawing a small PlaneVisual3D on which I paste a bitmap of the cross hair. I then rotate this plane so that it always faces the camera by applying the same rotation as the camera - this part works well.

I then want to scale the plane so that it is always the same size on the screen. This of course depends on where the plane is relative to the camera.

I also need this to work with a perspective and an orthographic camera as I have two separate views that use both camera types.

Here's what I have tried so far. This neither works in perspective nor orthographic views. It does work at times but I think I'm going about it wrong.

var fieldOfViewInRadians = MainCamera.FieldOfView * (Math.PI / 180.0);

var cam = MainCamera;

var t = cam.TargetPosition;

var camQuat = cam.ConvertCameraAnglesToQuaternion();

var vectorC2T = new Vector3D(0, 0, cam.Distance);

//this part converts cameras rotation into a toration matrix

var camMatrix = new Transformation(new Vector3D(), camQuat).ToMatrix();

//then calculate the camera to target vector

vectorC2T = camMatrix.Transform(vectorC2T);

//this is the vector of the target

var vectorT = new Vector3D(t.X, t.Y, t.Z);

foreach (var p in PCSPoints)

{

//this is the world position of the point (i have to swap hand conventions)

var wp = p.WorldPosition.SwapHandedness();

//the vector of the point

var vectorP = new Vector3D(wp.X, wp.Y, wp.Z);

//calculate the vector of the camera to the point

var vectorC2P = vectorC2T + vectorP - vectorT;

//the distance is then length of this vector

var distance = vectorC2P.Length;

var width = 2 * distance * Math.Tan(fieldOfViewInRadians / 2);

var newVSize = width * (_viewType == ViewType.Perspective ? 0.02 : 0.005);

Debug.WriteLine($"fov:{CameraAndMouseController.MainCamera.FieldOfView} d:{CameraAndMouseController.MainCamera.Distance} w:{width} newsize:{newVSize}");

p.Plane.Size = new Size(newVSize, newVSize);

//the plane is on x y plane so rotate to x z plane

camQuat *= new Quaternion(new Vector3D(1, 0, 0), -90);

p.Rotation = camQuat;

}

Of course if there is an entirely different way of doing this I'm open to suggestions.

What I'm doing at present is drawing a small PlaneVisual3D on which I paste a bitmap of the cross hair. I then rotate this plane so that it always faces the camera by applying the same rotation as the camera - this part works well.

I then want to scale the plane so that it is always the same size on the screen. This of course depends on where the plane is relative to the camera.

I also need this to work with a perspective and an orthographic camera as I have two separate views that use both camera types.

Here's what I have tried so far. This neither works in perspective nor orthographic views. It does work at times but I think I'm going about it wrong.

var fieldOfViewInRadians = MainCamera.FieldOfView * (Math.PI / 180.0);

var cam = MainCamera;

var t = cam.TargetPosition;

var camQuat = cam.ConvertCameraAnglesToQuaternion();

var vectorC2T = new Vector3D(0, 0, cam.Distance);

//this part converts cameras rotation into a toration matrix

var camMatrix = new Transformation(new Vector3D(), camQuat).ToMatrix();

//then calculate the camera to target vector

vectorC2T = camMatrix.Transform(vectorC2T);

//this is the vector of the target

var vectorT = new Vector3D(t.X, t.Y, t.Z);

foreach (var p in PCSPoints)

{

//this is the world position of the point (i have to swap hand conventions)

var wp = p.WorldPosition.SwapHandedness();

//the vector of the point

var vectorP = new Vector3D(wp.X, wp.Y, wp.Z);

//calculate the vector of the camera to the point

var vectorC2P = vectorC2T + vectorP - vectorT;

//the distance is then length of this vector

var distance = vectorC2P.Length;

var width = 2 * distance * Math.Tan(fieldOfViewInRadians / 2);

var newVSize = width * (_viewType == ViewType.Perspective ? 0.02 : 0.005);

Debug.WriteLine($"fov:{CameraAndMouseController.MainCamera.FieldOfView} d:{CameraAndMouseController.MainCamera.Distance} w:{width} newsize:{newVSize}");

p.Plane.Size = new Size(newVSize, newVSize);

//the plane is on x y plane so rotate to x z plane

camQuat *= new Quaternion(new Vector3D(1, 0, 0), -90);

p.Rotation = camQuat;

}

Of course if there is an entirely different way of doing this I'm open to suggestions.