Search code examples
unity-game-enginevirtual-reality

Relative position to created object issue


I have a unity project with a user controller avatar, quad surface 1, another avatar, and another quad surface. I am attempting to replicate my movements in VR onto the avatar representation of my player character relative to created surfaces. For example, if I move to the left of my created surface, then a representation of my avatar should also move to the left of its own surface. Similarly, if I point to the top left corner of my surface, then my representation should also point to the top left of its own surface.

I accomplish this by mapping my avatar's parent object (Player1) position and rotation relative to my quad surface. From there, I project the position and rotational values onto the parent object of the avatar's representation (Player2) relative to its own surface. Afterward each of the representation's parts (head, left hand, right hand) are updated to match the local position of the player-controlled avatar's parts.

In general, the movements and overall position/rotation of my avatar are mapped correctly. I begin to encounter issues, however, when I try to be more precise (e.g. touching a corner of the surface.) In this scenario, I will be touching the corner while my avatar representation will be touching near the area, but not exactly in the corner. It should be noted that both surfaces have the same scale values. Below is the code that I am using to map my movements onto the avatar.


using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PuppetMovement : MonoBehaviour
{

    //Player Variables
    public GameObject Player1;
    public GameObject Player1Head;
    public GameObject Player1LeftHand;
    public GameObject Player1RightHand;
    
    //Representation Variables
    public GameObject Player2;
    public GameObject Player2Head;
    public GameObject Player2LeftHand;
    public GameObject Player2RightHand;
    
    //Surface Variables
    public GameObject Surface1;
    public GameObject Surface2;

    // Update is called once per frame
    void Update()
    {
        Vector3 playerRelativeToSurface = Surface1.transform.InverseTransformPoint(Player1.transform.position);
        
        Quaternion playerRotationRelativeToSurface = Player1.transform.rotation * Quaternion.Inverse(Surface1.transform.rotation);
        Player2.transform.rotation = Surface2.transform.rotation * playerRotationRelativeToSurface ;
        
        Vector3 rotatedDirection = Surface2.transform.rotation * playerRelativeToSurface;
        
        Player2.transform.position = rotatedDirection + Surface2.transform.position;

        Player2Head.transform.localPosition = Player1Head.transform.localPosition;
        Player2Head.transform.localRotation = Player1Head.transform.localRotation;
        
        Player2LeftHand.transform.localPosition = Player1LeftHand.transform.localPosition;
        Player2LeftHand.transform.localRotation = Player1LeftHand.transform.localRotation;
        
        Player2RightHand.transform.localPosition = Player1RightHand.transform.localPosition;
        Player2RightHand.transform.localRotation = Player1RightHand.transform.localRotation;
        
    }
}

This is the view from the player controlled avatar. As you can see the right controller is touching the top right corner.

This is what the representation avatar looks like. It's in the general area, but is not precisely where I am touching my surface.

I would appreciate any help in solving this issue. Thank you!


Solution

  • I can't tell exactly where your code fails except it doesn't take scaling into account.

    The back conversion of the

    Vector3 playerRelativeToSurface = Surface1.transform.InverseTransformPoint(Player1.transform.position);
    

    would actually simply be

    Player2.transform.position = Surface2.transform.TransformPoint(playerRelativeToSurface);
    

    Little side note: If you directly use Transform for the fields

    public Transform Player1;
    public Transform Player1Head;
    public Transform Player1LeftHand;
    public Transform Player1RightHand;
    // ...
    

    you can get rid of the .transform everywhere which imho makes it a bit cleaner.