Hello everyone.

The Mixed Reality Forums here are no longer being used or maintained.

There are a few other places we would like to direct you to for support, both from Microsoft and from the community.

The first way we want to connect with you is our mixed reality developer program, which you can sign up for at https://aka.ms/IWantMR.

For technical questions, please use Stack Overflow, and tag your questions using either hololens or windows-mixed-reality.

If you want to join in discussions, please do so in the HoloDevelopers Slack, which you can join by going to https://aka.ms/holodevelopers, or in our Microsoft Tech Communities forums at https://techcommunity.microsoft.com/t5/mixed-reality/ct-p/MicrosoftMixedReality.

And always feel free to hit us up on Twitter @MxdRealityDev.

Manipulation using colliders and world anchors?

I have been trying to adapt this script by @Patrick to use colliders and/or rigid body so they will collide with world surfaces as determined by the spatial mapping data:

public class SavingWorldAnchors_Untouched : MonoBehaviour
{
private Quaternion toQuat;
private static int maxCrates = 7;
private static string baseName = "crate_";
private static int count = 0;

//returns the filename that hasn't used yet, up to the maxCrate number
//NOTE: if all files are being used, it will use the last file available
public static string getFileName()
{
    string fileName = baseName + count;

    while ((File.Exists(fileName)) && (count < maxCrates))
    {
        count = count + 1;
        fileName = baseName + count;
    }

    return (fileName);
}


public string ObjectAnchorStoreName = getFileName();

WorldAnchorStore anchorStore;

bool Placing = false;
// Use this for initialization
void Start()
{
    WorldAnchorStore.GetAsync(AnchorStoreReady);
}

void AnchorStoreReady(WorldAnchorStore store)
{
    anchorStore = store;
    Placing = true;

    Debug.Log("looking for " + ObjectAnchorStoreName);
    string[] ids = anchorStore.GetAllIds();
    for (int index = 0; index < ids.Length; index++)
    {
        Debug.Log(ids[index]);
        if (ids[index] == ObjectAnchorStoreName)
        {
            WorldAnchor wa = anchorStore.Load(ids[index], gameObject);
            Placing = false;
            break;
        }
    }
}

// Update is called once per frame
void Update()
{
    if (Placing)
    {
        gameObject.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 2;
        // Rotate this object to face the user.
        toQuat = Camera.main.transform.localRotation;
        toQuat.x = 0;
        toQuat.z = 0;
        this.transform.rotation = toQuat;
    }
}

public void OnSelect()
{
    if (anchorStore == null)
    {
        return;
    }

    if (Placing)
    {
        WorldAnchor attachingAnchor = gameObject.AddComponent<WorldAnchor>();
        if (attachingAnchor.isLocated)
        {
            Debug.Log("Saving persisted position immediately");
            bool saved = anchorStore.Save(ObjectAnchorStoreName, attachingAnchor);
            Debug.Log("saved: " + saved);
        }
        else
        {
            attachingAnchor.OnTrackingChanged += AttachingAnchor_OnTrackingChanged;
        }
    }
    else
    {
        WorldAnchor anchor = gameObject.GetComponent<WorldAnchor>();
        if (anchor != null)
        {
            DestroyImmediate(anchor);
        }

        string[] ids = anchorStore.GetAllIds();
        for (int index = 0; index < ids.Length; index++)
        {
            Debug.Log(ids[index]);
            if (ids[index] == ObjectAnchorStoreName)
            {
                bool deleted = anchorStore.Delete(ids[index]);
                Debug.Log("deleted: " + deleted);
                break;
            }
        }
    }

    Placing = !Placing;
}

public void AttachingAnchor_OnTrackingChanged(WorldAnchor self, bool located)
{
    if (located)
    {
        Debug.Log("Saving persisted position in callback");
        bool saved = anchorStore.Save(ObjectAnchorStoreName, self);
        Debug.Log("saved: " + saved);
        self.OnTrackingChanged -= AttachingAnchor_OnTrackingChanged;
    }
}

}

The problem is that when I try to combine the placement stage with the collision from this next script, you can't place the object back down once you pick it up:

        if (Placing)
        {
            targetPoint = ProposeTransformPosition();
            force = (targetPoint - this.transform.position);

            this.GetComponent<Rigidbody>().velocity = force.normalized * this.GetComponent<Rigidbody>().velocity.magnitude;
            this.GetComponent<Rigidbody>().AddForce(force * correctionForce);               
            this.GetComponent<Rigidbody>().velocity *= Mathf.Min(1.0f, force.magnitude / 2);

            // Rotate this object to face the user.
            toQuat = Camera.main.transform.localRotation;
            toQuat.x = 0;
            toQuat.z = 0;
            this.transform.rotation = toQuat;

        }
    }

    Vector3 ProposeTransformPosition()
    {
        Vector3 retval;
        if (snapToSurfaces)
        {
            // We prefer to put the model on a real world surface.
            RaycastHit hitInfo;

            if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, snapDistance, SpatialMappingManager.Instance.LayerMask))
            {
                retval = hitInfo.point;
            }
            else
            {
                // But if we don't have a ray that intersects the real world, just put the model 2m in
                // front of the user.
                retval = Camera.main.transform.position + Camera.main.transform.forward * placementDistance;
            }
        }
        else
        {
            retval = Camera.main.transform.position + Camera.main.transform.forward * placementDistance;
        }

        return retval;
    }
}

}

I really need help with this script, I've spent days slamming my head against the wall and have gotten nowhere. Again, my goal is to use the saving world anchors script above, except to modify the placement stage so that the object you're moving collides with real world surfaces. Thank you!

Answers

  • @ConleyCW without looking at the specifics of your script, I ran into a similar problem when I was ramping up on TapToPlace where things looked like they should work but were not and it took me a while to realize that the "origin point" of your model needs to be included inside your collider (or could have an extra box collider fitted loosely around it.

    For example if the box collider in the above image was tight to the House model and didn't include the model origin (where the gizmo is) this model would be imposible to place with the default logic inside the TapToPlace script, which appears to be very similar placing logic to what you have above.

    Alternatively, if you don't want to have an oversized collider, you can also use the empty gameobject parent workaround to position an abstracted origin in the desired place relative to your model or edit your model's origin before you import it into Unity since you can not actually edit the model's origin and vertex's in Unity's editor.

    Another important point was that the colliders needed to be at the same level of the hierarchy for that script which was different from the Origami code where the collider was expected on the child of the stage which would get placed.

    HTH

    Windows Holographic User Group Redmond

    WinHUGR.org - - - - - - - - - - - - - - - - - - @WinHUGR
    WinHUGR YouTube Channel -- live streamed meetings

  • edited June 2016

    Not sure I understand your problem fully. Are you trying to anchor the object when it collides with the mapping generated collider? Or pin it to the hit position where your raycast hits the collider?

    Is your snaptosurface conditional being triggered? If you're able to select the item but not unselect it I'd debug out all your bool conditionals and make sure they're in the right toggled state as you select/deselect....

  • @ConleyCW when moving objects that have world anchors we recommend:

    1. Removing the world anchor from that component.
    2. Move it to where you want it
    3. Add the world anchor back once you have placed it.
  • Thanks for your input guys, but my problem is that with the saving world anchors script the object that you're moving will go through real world surfaces even with spatial mapping on. I need to modify the existing script so that it uses colliders or maybe a rigid body for placement so that the object you are placing won't go through placement surfaces. Does that make sense?

  • edited June 2016

    Using the physics system for movement is probably the simplest bet. Or write a custom logic to offset from sphere/raycasting from the object, but the physics system has been the answer for us in the past with the vive, attaching an object to the controller would go through other geometry, changing it to follow the controller using physics allows the colliders to prevent intersection.

    https://docs.unity3d.com/ScriptReference/Rigidbody.MovePosition.html saves the trouble of calculating the move force but still interacts with the physics system and is easy to adapt to code that uses non physics based translations.

  • @ConleyCW

    Hey there. I think the relevant code is:

    if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, snapDistance, SpatialMappingManager.Instance.LayerMask))
                {
                    retval = hitInfo.point;
                }
                else
                {
                    // But if we don't have a ray that intersects the real world, just put the model 2m in
                    // front of the user.
                    retval = Camera.main.transform.position + Camera.main.transform.forward * placementDistance;
                }
    

    That's the code from the second script you need to morph into your update function in the first script. It will look like this:

    // Update is called once per frame
    void Update()
    {
        if (Placing)
        {
    // default to 2m in front of the user
            gameObject.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 2;
    RaycastHit hitInfo;
    // but check to see if there is a real world surface to place the object at instead
    if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, 10.0f, SpatialMappingManager.Instance.LayerMask))
                    {
                          gameObject.transform.position = hitInfo.point;
                    }
    
            // Rotate this object to face the user.
            toQuat = Camera.main.transform.localRotation;
            toQuat.x = 0;
            toQuat.z = 0;
            this.transform.rotation = toQuat;
        }
    }
    

    ===
    This post provided as-is with no warranties and confers no rights. Using information provided is done at own risk.

    (Daddy, what does 'now formatting drive C:' mean?)

  • @ConleyCW
    Have you figured this yet?

  • Anyone got an Idea how I can modify the TapToPlace Script in order to place Objects using their Collider ? ie. bounds.center or something like that?

  • @ConleyCW did you solve your issue?

Sign In or Register to comment.