Determine point on upper right side of horizon of sphere

I am trying to get the location of a point that would be on the upper right side of a sphere’s horizon from the perspective of a given camera.

For example, this code works correctly for objects roughly in the middle of the field of view:

private Vector3 GetEdgePoint(Camera camera, Vector3 possition, float diameter){
        var shift =   (diameter/2) / SQRT_TWO;
        var edgePoint = possition + (camera.transform.up.normalized * shift) + (camera.transform.right.normalized * shift);

        return edgePoint;
    }

I understand why this doesn’t work for objects near the edge of the field of view - the ‘direction’ of the camera’s transform is still directly ahead so I can’t use it to determine the plane on which to shift my point.

I suspect I could solve the problem by making an empty GameObject, copying in the position and rotation of the camera, performing a LookAt to the target and then using the direction of that GameObject as the normal for my cross section plane for the sphere. The thing is, that kinda seems like a hack and I feel there must be a better way to do it. It would happen for a number of onscreen targets each frame so I’m looking to keep it pretty efficient (which I may already not be doing - I’m fully amateur at this).

Any suggestions?

Why create a GO and copy the information?

Just do the math that is like doing all that.

Quaternion.LookRotation is effetively like LookAt, you just need to calculate the direciton:

The direction would be (targetPosition - cameraPosition).

So:

var q = Quaternion.LookRotation(targetPosition - cameraPosition);

(I guess in your code cameraPosition would be possition)

As for getting the ‘up’ and ‘right’, you can see from the source code it’s really just the rotation * Vector3.up, or Vector3.right:

public Vector3 up { get { return rotation * Vector3.up; } set { rotation = Quaternion.FromToRotation(Vector3.up, value); } }

(note you also don’t need to normalize those, they’re already unit vectors)

And since we calculated the rotation that would be looking at the target position as ‘q’, our up and right would be:

var up = q * Vector3.up;
var right = q * Vector3.right;

Now you have your values for your formula.

Thanks for the reply, but this doesn’t work when I switch my camera to view the objects top down. The point seems to assume it was from the perspective of a side camera even when the camera is above (my camera can observe its target from any point in a surrounding sphere).

If I implement my edge point as follows (where ‘phantomTransform’ is a from a placeholder GameObject), it all works fine - so I’d love to be able to implement the equivalent of this but using the math directly as you suggest:

    private Vector3 GetEdgePointPhantom(Camera camera, Vector3 possition, float diameter){
        var shift =   (diameter/2) / SQRT_TWO;
      
        phantomTransform.position = camera.transform.position;

        phantomTransform.LookAt(possition, camera.transform.up);

        var edgePoint = possition + (phantomTransform.up.normalized * shift) + (phantomTransform.right.normalized * shift);

        return edgePoint;
    }

OK - this seems to work. Just added the camera’s up to the LookRotation. Thanks for your help!

    private Vector3 GetEdgePoint(Camera camera, Vector3 possition, float diameter){
        var shift =   (diameter/2) / SQRT_TWO;

        var q = Quaternion.LookRotation(possition - camera.transform.position, camera.transform.up);

        var up = q * Vector3.up;
        var right = q * Vector3.right;

        var edgePoint = possition + (up * shift) + (right * shift);

        return edgePoint;
    }