Modify Reflection Probe Offset

I’m trying to figure out if it’s possible to use a script to modify a reflection probe’s offset.

What I’m attempting to do is create a reflection probe that, while the user is within the bounds of a trigger, will follow the user around. I can get the probe to follow the camera, but the issue is that the area the probe is reflecting also follows. I need the center of the reflection probe to follow the camera while the area the reflection probe reflects remains constant. The probe is using box projection, which is why the extents need to remain constant.

I cannot find anything in the API about using a script to modify the Box Offset property. Am I missing it, or is that not possible? If it is not possible, does anyone have any suggestions about achieving the desired results? This is for VR Architectural walk-throughs, so it’s important that the reflections show correctly from the actual perspective of the user. The user can see their hands and interact with things, so I can’t just use a single box projection probe in the center of the space.

Thanks!

It took a lot of experimenting, but I got it to work. I’m going to post what I did for the convenience of anyone else attempting to accomplish this. Also for critiquing. I’m pretty sure I did this in probably the worst way possible, but I can’t think of anything better.

//Keep track of the camera head so that the reflection probe is always at the correct height
    public GameObject cameraHead;

    //Which axes do we want to track?
    public bool lockX = false;
    public bool lockY = true;
    public bool lockZ = false;

    //Reflection probe reference
    private ReflectionProbe probe;

    //The trigger used to determine when the user enters or exits the bounds of this reflection probe
    public BoxCollider trigger;
    //The last position the reflection probe was located at
    private Vector3 lastPos;
    //Is this probe active?
    private bool isProbeActive;

    //The original extents height of the probe
    Vector3 originalExtents;
    Vector3 originalProbeCenter;
    Vector3 originalProbePosition;

    public bool isPlayerWithinTrigger
    {
        get
        {
            return trigger.bounds.Contains(cameraHead.transform.position);
        }

        private set { }
    }



    // Use this for initialization
    void Start () {
        probe = this.gameObject.GetComponent<ReflectionProbe>();

        originalExtents = probe.bounds.extents;
        originalProbeCenter = probe.center;
        originalProbePosition = this.gameObject.transform.position;

        trigger.center = probe.center;
        trigger.center += Vector3.up * probe.gameObject.transform.position.y;
        trigger.size = probe.size;

        lastPos = transform.position;
        isProbeActive = false;
    }
 
    // Update is called once per frame
    void Update () {

        if (isPlayerWithinTrigger)
        {
            //If we just moved from being outside of the trigger to inside of it, set this reflection probe to
            //realtime and make it follow the player
            if (!isProbeActive)
            {
                probe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.EveryFrame;
                isProbeActive = true;
            }

            float newX = this.gameObject.transform.position.x;
            if (lockX) newX = cameraHead.transform.position.x;

            float newY = this.gameObject.transform.position.y;
            if (lockY) newY = cameraHead.transform.position.y;

            float newZ = this.gameObject.transform.position.z;
            if (lockZ) newZ = cameraHead.transform.position.z;

            Vector3 newPos = new Vector3(newX, newY, newZ);

            Vector3 newProbeCenter = trigger.bounds.center + (trigger.center - newPos) - originalProbeCenter - (Vector3.up*originalProbePosition.y);

            probe.center = newProbeCenter;
            this.gameObject.transform.position = newPos;


        }
        else
        {
            //If we just moved from inside of the probe to outside of it, deactivate the probe
            if (isProbeActive)
            {
                //Move the probe back to its starting point and refresh it one more time
                this.gameObject.transform.position = originalProbePosition - (Vector3.up * originalProbePosition.y);
                probe.center = trigger.center;
                probe.refreshMode = UnityEngine.Rendering.ReflectionProbeRefreshMode.OnAwake;
                isProbeActive = false;
            }
        }

    }

To set this up, attached to a reflection probe that is the child of a gameobject with nothing but a box collider marked as a trigger.

When the player enters the extents of the trigger, the reflection probe starts to follow the player, and offsets it’s center to keep the reflection area constant. When the player leaves the extents of the trigger, the reflection probe resets to its original position. While the reflection probe is active, it is refreshing every frame. Once the play leaves the trigger area, it goes back to not refreshing.

The cameraHead variable is your main camera,or, in the case of VR, the center eye camera. The trigger is the box collider of the parent object. Locking X, Y, and Z is for determining which axes you want to probe to follow in. This can be useful for creating mirror surfaces where the reflection probe will match the user’s height, and follow them along a flat surface.

I didn’t show it in that code snippit, but this is the body of a monobehavior script.

It’s not a perfect solution, and I’m definitely open to suggestions, but it achieves what I am looking for, or at least close to it.

1 Like

I was looking for a solution to this today, and managed to simplify your code a bit. This solution isn’t as robust, it wont handle you entering or leaving the bounds of the probe, but it will get you started building a custom probe offset solution of your own.

probe.transform.position = cam.transform.position;
probe.center = originalProbePosition - cam.transform.position;

Set the originalProbePosition in start like you are doing above, and simply read the camera’s position and call this code every frame. The end result is a consistent bounding box, with an origin that follows the main camera.

Like I said, far less robust, but worked for what I needed so I figured I’d share.

1 Like