0
\$\begingroup\$

I've been having a bit of trouble with this small piece of code. To set my relative PortalCam position, I first take the distance and angle from the Portal and Player Cam. Then apply the distance and rotation to my OtherPortal to get the PortalCams position.

Desmos link to all the maths

float newX, newY, newZ;
float d;    // Distance between Portal and PlayerCam
float phi;  // Angle between Portal and PortalCam
            // Angle between Portals
float delta = Quaternion.Angle(portal.rotation, otherPortal.rotation);
d = Mathf.Sqrt( (playerCam.position.x - portal.position.x)^2 +
                (playerCam.position.z - portal.position.z)^2 );
if(playerCam.position.x >= portal.position.x)
    d = -d;
phi = Mathf.Atan( (playerCam.position.z - portal.position.z)
                / (playerCam.position.x - portal.position.x) );

newX = otherPortal.position.x - d*Mathf.Sin(phi - delta);
newY = playerCam.position.y + otherPortal.position.y - portal.position.y;
newZ = otherPortal.position.z + d*Mathf.Cos(phi - delta);
transform.position = new Vector3(newX, newY, newZ);

My problem is that, while this works perfectly when the portals are at 90degrees to each other. The code seems to fail when the portals are in-line.
Is there a mistake in my math? In my code? How can I best fix this bug?

\$\endgroup\$
0

1 Answer 1

0
\$\begingroup\$

Myself, I'd skip the manual math and use Unity's built-in transformation functions for this.

const Quaternion FLIP = Quaternion.Euler(0, 180, 0); // (0, 1, 0, 0)

void CrossPortals(Transform subject, Transform entrance, Transform exit) {
    // Map subject position into "entrance portal space" coordinates.
    Vector3 entrancePosition = entrance.InverseTransformPoint(subject.position);

    // Here I assume both portals face "outwards", 
    // so "into" the entrance portal needs to be rotated
    // to map to "out" of the exit portal.
    Vector3 exitPosition = FLIP * entrancePosition;
    
    subject.position = exit.TransformPoint(exitPosition);

    // Order matters here (read from the end, back toward the beginning).
    Quaternion relativeRotation =
            // 3. Apply exit portal's orientation.
            exit.rotation 
            // 2. Account for portals facing opposite directions.
            * FLIP
            // 1. Express orientation in entrance coordinates.
            * Quaternion.Inverse(entrance.rotation);

    subject.rotation = relativeRotation * subject.rotation;
}
\$\endgroup\$
6
  • \$\begingroup\$ sory im still way too new at this, but Unity has a built in Transform.InverseTransfromPoint and Transform.TransformPoint. InverseTransformPoint is basically the "inverse" of TransformPoint, but TransformPoint will be like, "Okay, take this Object and move it relative to this OtherObject." <br>Like moving a Child Object in a Prefab, you can scale & rotate the Prefab and the Child Object within it will be scaled & rotated Relative to the Prefab's "[0,0]". \$\endgroup\$ Commented Oct 19, 2022 at 20:00
  • \$\begingroup\$ Sorry, is that a question? I'm not sure what it is you're asking. \$\endgroup\$
    – DMGregory
    Commented Oct 19, 2022 at 20:05
  • \$\begingroup\$ yes, sorry yes. Just to clarify. I did a quick look into the API and from my understanding... [insert my word vomit here]. Do I have the right idea of how the code you've provided works? \$\endgroup\$ Commented Oct 19, 2022 at 20:13
  • \$\begingroup\$ TransformPoint/InverseTransformPoint are just math functions, so they do not actually move any objects. They take a point in one coordinate system, and give you the same point expressed in a different coordinate system. TransformPoint takes a point from an object's local coordinate system (like the coordinates of vertices in its mesh, or localPosition values of its direct child objects) and maps it into world space. The inverse version does the opposite. \$\endgroup\$
    – DMGregory
    Commented Oct 19, 2022 at 20:31
  • \$\begingroup\$ Thanks so much. So from your code: Im taking "Player" position relativeTo "PortalA" (Player coords 'as if' Portal A is '[0,0]'). Then apply that to my "PortalCam" relative to "PortalB". Setting its World Position relative to a Local Position. (Plus I gotta flip the position so that the camera is behind the portal, but you know, extra details...) \$\endgroup\$ Commented Oct 19, 2022 at 20:51

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .