Raycast2D or ContactPoint2D Normal Rotation

Hello all,

I’m attempting to have a working portal projectile that will rotate/align itself to the surface it hits, however, I cannot seem to get the proper rotation from the hit.normal with the Raycast2D or from using a ContactPoint2D when the projectile collides. I’ve vaguely given up on ContactPoint2D for now, so I’m using the Raycast2D to pop along the path of the projectile and calculate the rotation, hopefully, which is why it is set to be a Trigger currently.

The portals are specifically projectile-based rather than only Raycast-based, as I want the ability to shoot the portal projectile through linked portals later, similar to how the portals work in Darksiders.

I understand at least theoretically how to do this in 3D, as I can use Quaternion.FromToRotation or LookRotation, however, the methods use Vector3s and I can’t seem to adapt it to rotate properly (only in Z) for 2D. None of the guides I’ve found for 2D Portals have been sufficiently helpful to make this work, and I haven’t found a forum post that explains it, but if you know of one, happy to look at it.

private void OnTriggerEnter2D(Collider2D other)
{
    // ContactPoint2D contactPoint = other.GetContact(0);

    int theLayer = other.gameObject.layer;
    if(!(collisionMask == (collisionMask | (1 << theLayer))))//LayerMask witchery that I don't remember the exacts of
    {
        RaycastHit2D hit = Physics2D.Raycast(rayOrigin, transform.up, Mathf.Infinity, ~collisionMask);
        Debug.Log(LayerMask.LayerToName(other.gameObject.layer) + ", Position: " + hit.point + " & " + hit.normal);

        GameObject portal = Instantiate(Resources.Load<GameObject>("Portal_" + portalColor), hit.point, Quaternion.FromToRotation(rayOrigin, -hit.normal), portalParent);
        // portal.transform.rotation = Quaternion.Euler(0, 0, portal.transform.rotation.z - 18.464f);
        portal.name = "Portal_" + portalColor; //name the portal correctly in the hierarchy
        portal.GetComponent<Portal>().pColor = Portal.stringToPortalColor(portalColor); //by the grace of God I don't remember why I did this
        portals.PortalCheck(portal); //call the PortalCheck method to limit existing portals to one of each color

        // Instantiate(Resources.Load<GameObject>("Portal_Red"), contactPoint.point, Quaternion.FromToRotation(Vector3.forward, contactPoint.normal));
        Destroy(this.gameObject); //kill projectile object
    }
}

In true Unity fashion, Quaterion.FromToRotation(Vector3.up, hit.normal) now works beautifully, and I don’t 100% know why.