Search Unity

Unable to change an instantiated prefab's position more than one time

Discussion in 'VR' started by trzy, Nov 12, 2016.

  1. trzy

    trzy

    Joined:
    Jul 2, 2016
    Posts:
    128
    This is a bit of a head scratcher and seems to be HoloLens-specific. It works just fine when running in the Unity editor. Basically, I have a fixed array of instantiated prefabs, initially disabled, and I "place" them by enabling them and updating their transform.

    The idea is to have a circular fixed buffer of objects that are reused (limiting the maximum number that can be present at any given time). Once we wrap from the end of the array to 0, the first object should be moved.

    Code (csharp):
    1.  
    2. class PopulationLimitingBuffer
    3.   {
    4.     private GameObject[] m_array;
    5.     private int m_idx = 0;
    6.     private GameObject m_parent;
    7.  
    8.     public void Insert(Vector3 position, Vector3 normal)
    9.     {
    10.       // Object we want to try to place
    11.       GameObject obj = m_array[m_idx];
    12.       obj.transform.position = position;
    13.       obj.transform.rotation = Quaternion.LookRotation(normal);
    14.       obj.SetActive(true);
    15.       m_idx = (m_idx + 1) % m_array.Length;
    16.     }
    17.  
    18.     public PopulationLimitingBuffer(GameObject bullet_hole_prefab, int max_population, GameObject parent)
    19.     {
    20.       m_array = new GameObject[max_population];
    21.       m_parent = parent;
    22.       for (int i = 0; i < m_array.Length; i++)
    23.       {
    24.         m_array[i] = Instantiate(bullet_hole_prefab) as GameObject;
    25.         //m_array[i].AddComponent<WorldAnchor>(); //TODO: disable these?
    26.         //m_array[i].transform.parent = m_parent.transform;
    27.         m_array[i].SetActive(false);
    28.       }
    29.     }
    30.   }
    31.  
    Very simple, right?

    Except that once max_population objects have been instantiated (set active for the first time), their position cannot be changed a second time. They can be enabled/disabled still (e.g., if I change obj.SetActive(true) to obj.SetActive(!obj.activeSelf)).

    As I said, it works as expected in the Unity editor on Windows. But deployed on HoloLens, the objects will be placed once and cannot be moved. Note that I am placing them inside of a spatial mesh. The objects are not Rigidbodies and have a disabled sphere collider.
     
  2. Gizmoi

    Gizmoi

    Joined:
    Jan 9, 2013
    Posts:
    327
    Well you aren't setting the position anywhere. You should also be using transform.SetParent to reparent transforms.
    If you want to reparent and set the local position to zero then I suggest you do that.

    Code (CSharp):
    1. m_array[i].transform.SetParent(m_parent.transform, false);
    2. m_array[i].transform.localPosition = Vector3.zero;
     
    guetta18 and Hodgson_SDAS like this.
  3. trzy

    trzy

    Joined:
    Jul 2, 2016
    Posts:
    128
    Thanks for the reply, Gizmoi. I believe I am setting the position. Look at line 12 of my code above:

    obj.transform.position = position;

    The initial position when the object is first created doesn't matter much because the object is actually positioned on the call to Insert(). This is where the next object is grabbed from the cache and its (absolute, world) position and transform are reset.

    Note that the first call to Insert() works fine. Subsequent calls (which will reuse an existing object and should have the effect of simply repositioning it) do not cause any change in position, however.
     
  4. Gizmoi

    Gizmoi

    Joined:
    Jan 9, 2013
    Posts:
    327
    I see, yes you are, my mistake. Possibly some correlation between HoloLens space being decided for you?
    What happens in the Editor if you move your world and camera way away from (0,0,0) do you get a similar issue?

    What calls Insert? And how does it get it's "position" value?
     
  5. trzy

    trzy

    Joined:
    Jul 2, 2016
    Posts:
    128
    Not sure -- but I don't understand why this would be any different than updating the position of any other object. I'll give your suggestion re: camera a try when I get home but I think it will continue to work.

    Just a little background: the object cache was intended to be used for fungible things that are frequently created/destroyed (bullets, bullet holes, etc.) and for which there should never be more than some small number N. It's just a circular buffer. Once N have been created, N+1 ends up reusing the first one (in the case of a bullet hole on the wall, this would cause the very first bullet hole to disappear and reappear in the new position).

    An example of how it was to be called is shown below. This code is called from the collision handler of a bullet when an impact with a wall is detected. The commented-out stuff is the old way of doing it (which works):

    Code (csharp):
    1.  
    2. public void CreateBulletHole(Vector3 position, Vector3 normal)
    3. {
    4. m_bullet_hole_buffer.Insert(position + normal * .005f, normal);
    5. /*
    6. GameObject bullet_hole = Instantiate(m_bullet_hole_prefab, position + normal * .005f, Quaternion.LookRotation(normal)) as GameObject;
    7. bullet_hole.AddComponent<WorldAnchor>();
    8. bullet_hole.transform.parent = this.transform;
    9. PlayspaceManager.Instance.Embed(bullet_hole);
    10. m_bullet_holes.Enqueue(bullet_hole);
    11. while (m_bullet_holes.Count > maxBulletHoles)
    12. {
    13. GameObject old_bullet_hole = m_bullet_holes.Dequeue();
    14. if (old_bullet_hole) // if hasn't destroyed itself already
    15. Destroy(old_bullet_hole);
    16. }
    17. */
    18. }
    19.  
    I hope this makes sense.
     
  6. trzy

    trzy

    Joined:
    Jul 2, 2016
    Posts:
    128
    Nope -- I positioned the camera at (0,0,-1) and it still worked fine as expected.
     
  7. Gizmoi

    Gizmoi

    Joined:
    Jan 9, 2013
    Posts:
    327
    It's difficult to say based on those code snippets, you're setting the position and rotation in a similar way that shouldn't be affected by re-use. If you could send me your project, or a cut down version I'd be willing to take a look?
     
  8. trzy

    trzy

    Joined:
    Jul 2, 2016
    Posts:
    128
    I played around with it some more and was about to package up a zip file for you when I noticed it is working! At least in the minimalistic version I boiled it down to. That should be enough for me to progress. My suspicion is that the world anchors were causing the problem (to be honest, I don't completely understand them yet). In the current version of the code, I am not using them, and everything works fine.

    Sorry about that. Now to try to lick the problem of the spatial mesh bounding boxes... :/
     
  9. pfreese

    pfreese

    Unity Technologies

    Joined:
    Feb 23, 2015
    Posts:
    85
    If you have a WorldAnchor component on an object, you will not be able to move its position, as the transform will be controlled by the WorldAnchor.
     
    trzy likes this.
  10. trzy

    trzy

    Joined:
    Jul 2, 2016
    Posts:
    128
    Thanks, pfreese! That makes sense.