Hey all,
Was wondering if I code get some assistance implementing a snap-to function that snaps a users gaze point projection on a sphere to the user's/camera's projection transform onto the world. I want to maintain the world-up as to say I do not want the sphere rotation to twist/roll when rotating from one point to another / using a latitude and longitude coordinate system.
I have been using Unity so the code below is what I have been working with. I was storing the world rotation in a current latitude and longitude variable and subtracting it from the projection of the user projection ray onto the sphere. This way, the user can walk around the object and center/rotate the sphere to face the user/camera transform projection on the sphere. However, the result does not work as intended because as the user goes behind the sphere, the offsets should slowly be reversed. I suspect a Sin/Cos based on longitude but still can't make it work.
Intended behavior:
When user is in front of globe and requests "Center" on a location such as San Diego the globe moves San Diego from the San Diego location to the intersection of the (user camera position/ globe) ray on the globe.
When user is behind globe and requests "Center" on a location such as Tokyo the globe moves Tokyo from the Tokyo location to the intersection of the (user camera position/ globe) ray on the globe.
Code I have so far in C# Unity:
void Update()
{
if(rotationInProgress)
{
// slowly move the currentLat / Lon towards our targetLat / Lon
currentLat = Mathf.LerpAngle(currentLat, targetLat, Time.deltaTime * 5);
currentLon = Mathf.LerpAngle(currentLon, targetLon, Time.deltaTime * 5);
// build our rotation from the two angles
transform.localRotation =
Quaternion.AngleAxis(-currentLat, Vector3.right) *
Quaternion.AngleAxis(currentLon, Vector3.up);
if (Mathf.Abs(currentLat - targetLat) < 0.05f && Mathf.Abs(currentLon - targetLon) < 0.05f)
rotationInProgress = false;
}
}
void Center()
{
// Do a raycast into the world based on the user's
// head position and orientation.
var headPosition = Camera.main.transform.position;
var gazeDirection = Camera.main.transform.forward;
var headGlobeDirection = transform.position - Camera.main.transform.position;
RaycastHit hitInfo, posInfo;
if (Physics.Raycast(headPosition, gazeDirection, out hitInfo) && Physics.Raycast(headPosition,headGlobeDirection,out posInfo))
{
#region Determine offset location
// convert the hit point into local coordinates
Vector3 localPos = transform.InverseTransformPoint(posInfo.point);
Vector3 longDir = localPos;
// zero y to project the vector to the x-z-plane
longDir.y = 0;
//calculate the angle between our reference and the hitpoint
float offsetLon = Vector3.Angle(-Vector3.forward, longDir);
// if our point is on the western hemisphere negate the angle
if (longDir.x < 0)
offsetLon = -offsetLon;
offsetLon -= currentLon;
// calculate the latitude in degree
float offsetLat = Mathf.Asin(localPos.normalized.y) * Mathf.Rad2Deg - currentLat;
#endregion
#region Determine Globe Pan-To Location
// convert the hit point into local coordinates
localPos = transform.InverseTransformPoint(hitInfo.point);
longDir = localPos;
// zero y to project the vector to the x-z-plane
longDir.y = 0;
//calculate the angle between our reference and the hitpoint
targetLon = Vector3.Angle(-Vector3.forward, longDir);
// if our point is on the western hemisphere negate the angle
if (longDir.x < 0)
targetLon = -targetLon;
// calculate the latitude in degree
targetLat = Mathf.Asin(localPos.normalized.y) * Mathf.Rad2Deg;
targetLon -= offsetLon;
targetLat -= offsetLat;
#endregion
rotationInProgress = true;
}
}
Thanks in advance if this brings about a solution to my problem! If I am not clear I can provide explain more in a further post.