diff --git a/ai2thor/tests/data/arm-metadata-schema.json b/ai2thor/tests/data/arm-metadata-schema.json index 46367cf552..7a922be331 100644 --- a/ai2thor/tests/data/arm-metadata-schema.json +++ b/ai2thor/tests/data/arm-metadata-schema.json @@ -179,7 +179,7 @@ "visible": { "type": "boolean" }, - "obstructed": { + "isInteractable": { "type": "boolean" }, "receptacle": { @@ -404,7 +404,7 @@ "objectId", "objectOrientedBoundingBox", "objectType", - "obstructed", + "isInteractable", "openable", "parentReceptacles", "pickupable", diff --git a/ai2thor/tests/data/metadata-schema.json b/ai2thor/tests/data/metadata-schema.json index b2c714c09a..fe12678ce9 100644 --- a/ai2thor/tests/data/metadata-schema.json +++ b/ai2thor/tests/data/metadata-schema.json @@ -43,7 +43,7 @@ "visible": { "type": "boolean" }, - "obstructed": { + "isInteractable": { "type": "boolean" }, "receptacle": { @@ -268,7 +268,7 @@ "objectId", "objectOrientedBoundingBox", "objectType", - "obstructed", + "isInteractable", "openable", "parentReceptacles", "pickupable", diff --git a/unity/Assets/Scripts/AgentManager.cs b/unity/Assets/Scripts/AgentManager.cs index 47fdd24f1b..c1c758abdb 100644 --- a/unity/Assets/Scripts/AgentManager.cs +++ b/unity/Assets/Scripts/AgentManager.cs @@ -1295,9 +1295,9 @@ public class ObjectMetadata { // public float cameraHorizon; moved to AgentMetadata, objects don't have a camerahorizon public bool visible; - // If true, object is obstructed by something and actions cannot be performed on it. + // If true, object is obstructed by something and actions cannot be performed on it unless forced. // This means an object behind glass will be obstructed=True and visible=True - public bool obstructed; + public bool isInteractable; // is this object a receptacle? public bool receptacle; diff --git a/unity/Assets/Scripts/BaseFPSAgentController.cs b/unity/Assets/Scripts/BaseFPSAgentController.cs index 400dd817a4..76a5e25156 100644 --- a/unity/Assets/Scripts/BaseFPSAgentController.cs +++ b/unity/Assets/Scripts/BaseFPSAgentController.cs @@ -1581,11 +1581,15 @@ public virtual ObjectMetadata[] generateObjectMetadata() { simObjects = GameObject.FindObjectsOfType(); } + SimObjPhysics[] interactable; HashSet visibleSimObjsHash = new HashSet(GetAllVisibleSimObjPhysics( this.m_Camera, this.maxVisibleDistance, + out interactable, this.simObjFilter)); + HashSet interactableSimObjsHash = new HashSet(interactable); + int numObj = simObjects.Length; List metadata = new List(); Dictionary> parentReceptacles = new Dictionary>(); @@ -1597,7 +1601,7 @@ public virtual ObjectMetadata[] generateObjectMetadata() { for (int k = 0; k < numObj; k++) { SimObjPhysics simObj = simObjects[k]; - ObjectMetadata meta = ObjectMetadataFromSimObjPhysics(simObj, visibleSimObjsHash.Contains(simObj)); + ObjectMetadata meta = ObjectMetadataFromSimObjPhysics(simObj, visibleSimObjsHash.Contains(simObj), interactableSimObjsHash.Contains(simObj)); if (meta.toggleable) { SimObjPhysics[] controlled = simObj.GetComponent().ReturnControlledSimObjects(); List controlledList = new List(); @@ -1634,7 +1638,7 @@ public virtual ObjectMetadata[] generateObjectMetadata() { } // generates object metatada based on sim object's properties - public virtual ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics simObj, bool isVisible) { + public virtual ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics simObj, bool isVisible, bool isInteractable) { ObjectMetadata objMeta = new ObjectMetadata(); GameObject o = simObj.gameObject; objMeta.name = o.name; @@ -1728,11 +1732,12 @@ public virtual ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics simO // in the multiagent setting, explicitly giving this information for now. objMeta.visible = isVisible; // simObj.isVisible; - objMeta.obstructed = !isVisible;// if object is not interactable, it means it is obstructed + //determines if the objects is unobstructed and interactable. Objects visible behind see-through geometry like glass will be isInteractable=False even if visible + //note using forceAction=True will ignore the isInteractable requirement + objMeta.isInteractable = isInteractable; objMeta.isMoving = simObj.inMotion;// keep track of if this object is actively moving - objMeta.objectOrientedBoundingBox = simObj.ObjectOrientedBoundingBox; objMeta.axisAlignedBoundingBox = simObj.AxisAlignedBoundingBox; @@ -2026,26 +2031,35 @@ public void Done() { // Helper method that parses objectId parameter to return the sim object that it target. // The action is halted if the objectId does not appear in the scene. - protected SimObjPhysics getTargetObject(string objectId, bool forceAction = false) { + protected SimObjPhysics getInteractableSimObjectFromId(string objectId, bool forceAction = false) { // an objectId was given, so find that target in the scene if it exists if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(objectId)) { throw new ArgumentException($"objectId: {objectId} is not the objectId on any object in the scene!"); } - - // if object is in the scene and visible, assign it to 'target' - SimObjPhysics target = getInteractableSimObjectFromId(objectId: objectId, forceVisible: forceAction); + + SimObjPhysics sop = getSimObjectFromId(objectId); + if (sop == null) { + throw new NullReferenceException($"Object with id '{objectId}' is null"); + } + + SimObjPhysics[] interactable; + bool visible = GetAllVisibleSimObjPhysics(camera: this.m_Camera, maxDistance: this.maxVisibleDistance, out interactable, filterSimObjs: new List { sop }).Length == 1; // target not found! - if (target == null) { + if (!visible && !forceAction) { throw new NullReferenceException("Target object not found within the specified visibility."); } + + if(interactable.Length == 0 && !forceAction) { + throw new NullReferenceException("Target object is visible but not interactable. It is likely obstructed by some clear object like glass."); + } - return target; + return sop; } // Helper method that parses (x and y) parameters to return the // sim object that they target. - protected SimObjPhysics getTargetObject(float x, float y, bool forceAction) { + protected SimObjPhysics getInteractableSimObjectFromId(float x, float y, bool forceAction) { if (x < 0 || x > 1 || y < 0 || y > 1) { throw new ArgumentOutOfRangeException("x/y must be in [0:1]"); } @@ -2687,12 +2701,11 @@ protected bool objectIsWithinViewport(SimObjPhysics sop) { return false; } - public bool isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance) { - bool visible = false; + public VisibilityCheck isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance) { + VisibilityCheck visCheck = new VisibilityCheck(); // check against all visibility points, accumulate count. If at least one point is visible, set object to visible if (sop.VisibilityPoints != null && sop.VisibilityPoints.Length > 0) { Transform[] visPoints = sop.VisibilityPoints; - int visPointCount = 0; float maxDistanceSquared = maxDistance * maxDistance; foreach (Transform point in visPoints) { @@ -2718,8 +2731,8 @@ public bool isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance) } // if this particular point is in view... - if (CheckIfVisibilityPointInViewport(sop, point, camera, sop.IsReceptacle)) { - visPointCount++; + visCheck |= CheckIfVisibilityPointInViewport(sop, point, camera, sop.IsReceptacle); + if (visCheck.visible && visCheck.interactable){ #if !UNITY_EDITOR // If we're in the unity editor then don't break on finding a visible // point as we want to draw lines to each visible point. @@ -2729,25 +2742,21 @@ public bool isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance) } // if we see at least one vis point, the object is "visible" - if (visPointCount > 0) { #if UNITY_EDITOR - sop.debugIsVisible = true; + sop.debugIsVisible = visCheck.visible; + sop.debugIsInteractable = visCheck.interactable; #endif - visible = true; - } } else { Debug.Log("Error! Set at least 1 visibility point on SimObjPhysics " + sop + "."); } - return visible; + return visCheck; } - public bool isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance, Plane[] planes) { - bool visible = false; + public VisibilityCheck isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance, Plane[] planes) { // check against all visibility points, accumulate count. If at least one point is visible, set object to visible + VisibilityCheck visCheck = new VisibilityCheck(); if (sop.VisibilityPoints != null && sop.VisibilityPoints.Length > 0) { Transform[] visPoints = sop.VisibilityPoints; - int visPointCount = 0; - float maxDistanceSquared = maxDistance * maxDistance; foreach (Transform point in visPoints) { bool outsidePlane = false; @@ -2785,9 +2794,9 @@ public bool isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance, } // if this particular point is in view... - if (CheckIfVisibilityPointRaycast(sop, point, camera, false) || - CheckIfVisibilityPointRaycast(sop, point, camera, true)) { - visPointCount++; + visCheck |= (CheckIfVisibilityPointRaycast(sop, point, camera, false) | CheckIfVisibilityPointRaycast(sop, point, camera, true)); + if (visCheck.visible && visCheck.interactable){ + #if !UNITY_EDITOR // If we're in the unity editor then don't break on finding a visible // point as we want to draw lines to each visible point. @@ -2797,16 +2806,14 @@ public bool isSimObjVisible(Camera camera, SimObjPhysics sop, float maxDistance, } // if we see at least one vis point, the object is "visible" - if (visPointCount > 0) { #if UNITY_EDITOR - sop.debugIsVisible = true; -#endif - visible = true; - } + sop.debugIsVisible = visCheck.visible; + sop.debugIsInteractable = visCheck.interactable; +#endif } else { Debug.Log("Error! Set at least 1 visibility point on SimObjPhysics " + sop + "."); } - return visible; + return visCheck; } // pass in forceVisible bool to force grab all objects of type sim obj @@ -2823,11 +2830,25 @@ protected SimObjPhysics[] GetAllVisibleSimObjPhysics( float maxDistance, IEnumerable filterSimObjs = null ) { + SimObjPhysics[] interactable; + + if (this.visibilityScheme == VisibilityScheme.Collider) { + return GetAllVisibleSimObjPhysicsCollider(camera, maxDistance, filterSimObjs, out interactable); + } else { + return GetAllVisibleSimObjPhysicsDistance(camera, maxDistance, filterSimObjs, out interactable); + } + } + protected SimObjPhysics[] GetAllVisibleSimObjPhysics( + Camera camera, + float maxDistance, + out SimObjPhysics[] interactable, + IEnumerable filterSimObjs = null + ) { if (this.visibilityScheme == VisibilityScheme.Collider) { - return GetAllVisibleSimObjPhysicsCollider(camera, maxDistance, filterSimObjs); + return GetAllVisibleSimObjPhysicsCollider(camera, maxDistance, filterSimObjs, out interactable); } else { - return GetAllVisibleSimObjPhysicsDistance(camera, maxDistance, filterSimObjs); + return GetAllVisibleSimObjPhysicsDistance(camera, maxDistance, filterSimObjs, out interactable); } } @@ -2837,29 +2858,39 @@ protected SimObjPhysics[] GetAllVisibleSimObjPhysics( // range and is visibile outside of the range, it will get reported as invisible // by the new scheme, but visible in the current scheme. protected SimObjPhysics[] GetAllVisibleSimObjPhysicsDistance( - Camera camera, float maxDistance, IEnumerable filterSimObjs + Camera camera, float maxDistance, IEnumerable filterSimObjs, out SimObjPhysics[] interactable ) { if (filterSimObjs == null) { filterSimObjs = physicsSceneManager.ObjectIdToSimObjPhysics.Values; } List visible = new List(); + List interactableItems = new List(); Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera); foreach (var sop in filterSimObjs) { - if (isSimObjVisible(camera, sop, this.maxVisibleDistance, planes)) { + VisibilityCheck visCheck = isSimObjVisible(camera, sop, this.maxVisibleDistance, planes); + if (visCheck.visible) { visible.Add(sop); } + + if (visCheck.interactable) { + interactableItems.Add(sop); + } } + + interactable = interactableItems.ToArray(); return visible.ToArray(); } - private SimObjPhysics[] GetAllVisibleSimObjPhysicsCollider(Camera camera, float maxDistance, IEnumerable filterSimObjs) { - List currentlyVisibleItems = new List(); + private SimObjPhysics[] GetAllVisibleSimObjPhysicsCollider(Camera camera, float maxDistance, IEnumerable filterSimObjs, out SimObjPhysics[] interactable) { + HashSet currentlyVisibleItems = new HashSet(); + HashSet interactableItems = new HashSet(); #if UNITY_EDITOR foreach (KeyValuePair pair in physicsSceneManager.ObjectIdToSimObjPhysics) { // Set all objects to not be visible pair.Value.debugIsVisible = false; + pair.Value.debugIsInteractable = false; } #endif @@ -2867,6 +2898,7 @@ private SimObjPhysics[] GetAllVisibleSimObjPhysicsCollider(Camera camera, float if (filterSimObjs != null) { filter = new HashSet(filterSimObjs); if (filter.Count == 0) { + interactable = interactableItems.ToArray(); return currentlyVisibleItems.ToArray(); } } @@ -2939,14 +2971,13 @@ private SimObjPhysics[] GetAllVisibleSimObjPhysicsCollider(Camera camera, float // check against all visibility points, accumulate count. If at least one point is visible, set object to visible if (sop.VisibilityPoints != null && sop.VisibilityPoints.Length > 0) { Transform[] visPoints = sop.VisibilityPoints; - int visPointCount = 0; + VisibilityCheck visCheck = new VisibilityCheck(); foreach (Transform point in visPoints) { // if this particular point is in view... - if (CheckIfVisibilityPointInViewport( - sop, point, camera, includeInvisible - )) { - visPointCount++; + // if we see at least one vis point, the object is "visible" + visCheck |= CheckIfVisibilityPointInViewport(sop, point, camera, includeInvisible); + if (visCheck.visible && visCheck.interactable) { #if !UNITY_EDITOR // If we're in the unity editor then don't break on finding a visible // point as we want to draw lines to each visible point. @@ -2955,14 +2986,16 @@ private SimObjPhysics[] GetAllVisibleSimObjPhysicsCollider(Camera camera, float } } - // if we see at least one vis point, the object is "visible" - if (visPointCount > 0) { #if UNITY_EDITOR - sop.debugIsVisible = true; -#endif - if (!currentlyVisibleItems.Contains(sop)) { - currentlyVisibleItems.Add(sop); - } + sop.debugIsVisible = visCheck.visible; + sop.debugIsInteractable = visCheck.interactable; +#endif + if (visCheck.visible && !currentlyVisibleItems.Contains(sop)) { + currentlyVisibleItems.Add(sop); + } + + if (visCheck.interactable && !interactableItems.Contains(sop)) { + interactableItems.Add(sop); } } else { Debug.Log("Error! Set at least 1 visibility point on SimObjPhysics " + sop + "."); @@ -2975,19 +3008,25 @@ private SimObjPhysics[] GetAllVisibleSimObjPhysicsCollider(Camera camera, float updateAllAgentCollidersForVisibilityCheck(true); // populate array of visible items in order by distance - currentlyVisibleItems.Sort((x, y) => Vector3.Distance(x.transform.position, agentCameraPos).CompareTo(Vector3.Distance(y.transform.position, agentCameraPos))); - return currentlyVisibleItems.ToArray(); + List currentlyVisibleItemsToList = currentlyVisibleItems.ToList(); + List interactableItemsToList = interactableItems.ToList(); + + interactableItemsToList.Sort((x, y) => Vector3.Distance(x.transform.position, agentCameraPos).CompareTo(Vector3.Distance(y.transform.position, agentCameraPos))); + currentlyVisibleItemsToList.Sort((x, y) => Vector3.Distance(x.transform.position, agentCameraPos).CompareTo(Vector3.Distance(y.transform.position, agentCameraPos))); + + interactable = interactableItemsToList.ToArray(); + return currentlyVisibleItemsToList.ToArray(); } // check if the visibility point on a sim object, sop, is within the viewport // has a inclueInvisible bool to check against triggerboxes as well, to check for visibility with things like Cabinets/Drawers - protected bool CheckIfVisibilityPointRaycast( + protected VisibilityCheck CheckIfVisibilityPointRaycast( SimObjPhysics sop, Transform point, Camera camera, bool includeInvisible ) { - bool result = false; + VisibilityCheck visCheck = new VisibilityCheck(); // now cast a ray out toward the point, if anything occludes this point, that point is not visible RaycastHit hit; @@ -3013,14 +3052,12 @@ bool includeInvisible hit.transform == sop.transform || (isSopHeldByArm && Arm.heldObjects[sop].Contains(hit.collider)) ) { - result = true; - sop.debugIsInteractable = true; + visCheck.visible = true; + visCheck.interactable = true; #if UNITY_EDITOR Debug.DrawLine(camera.transform.position, point.position, Color.cyan); #endif - } else { - result = false; - } + } } } @@ -3034,8 +3071,8 @@ bool includeInvisible ) { // if this line is drawn, then this visibility point is in camera frame and not occluded // might want to use this for a targeting check as well at some point.... - result = true; - sop.debugIsInteractable = true; + visCheck.visible = true; + visCheck.interactable = true; } else { // we didn't directly hit the sop we are checking for with this cast, // check if it's because we hit something see-through @@ -3066,7 +3103,9 @@ bool includeInvisible || (isSopHeldByArm && Arm.heldObjects[sop].Contains(hit.collider)) ) { // found the object we are looking for, great! - result = true; + //set it to visible via 'result' but the object is not interactable because it is behind some transparent object + visCheck.visible = true; + visCheck.interactable = false; break; } else { // Didn't find it, continue on only if the hit object was translucent @@ -3081,23 +3120,23 @@ bool includeInvisible } #if UNITY_EDITOR - if (result) { + if (visCheck.visible) { Debug.DrawLine(camera.transform.position, point.position, Color.cyan); } #endif } } - return result; + return visCheck; } - protected bool CheckIfVisibilityPointInViewport( + protected VisibilityCheck CheckIfVisibilityPointInViewport( SimObjPhysics sop, Transform point, Camera camera, bool includeInvisible ) { - bool result = false; + VisibilityCheck visCheck = new VisibilityCheck(); Vector3 viewPoint = camera.WorldToViewportPoint(point.position); @@ -3110,16 +3149,16 @@ bool includeInvisible && viewPoint.y < ViewPointRangeHigh && viewPoint.y > ViewPointRangeLow) // within y bounds of viewport { - result = CheckIfVisibilityPointRaycast(sop, point, camera, includeInvisible); + visCheck = CheckIfVisibilityPointRaycast(sop, point, camera, includeInvisible); } #if UNITY_EDITOR - if (result == true) { + if (visCheck.visible) { Debug.DrawLine(camera.transform.position, point.position, Color.cyan); } #endif - return result; + return visCheck; } public void DefaultAgentHand() { @@ -3580,20 +3619,6 @@ public void ObjectTypeToObjectIds(string objectType) { } } - protected SimObjPhysics getInteractableSimObjectFromId(string objectId, bool forceVisible = false) { - SimObjPhysics sop = getSimObjectFromId(objectId); - if (sop == null) { - errorMessage = "Object with id '" + objectId + "' is null"; - return null; - } - - if (forceVisible || IsInteractable(sop)) { - return sop; - } - - return null; - } - protected SimObjPhysics getSimObjectFromId(string objectId) { if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(objectId)) { errorMessage = "Cannot find sim object with id '" + objectId + "'"; @@ -4501,4 +4526,17 @@ public void Destroy(GameObject targetObject) { } } + + public class VisibilityCheck { + public bool visible; + public bool interactable; + + public static VisibilityCheck operator |(VisibilityCheck a, VisibilityCheck b) { + VisibilityCheck c = new VisibilityCheck(); + c.interactable = a.interactable || b.interactable; + c.visible = a.visible || b.visible; + return c; + } + } + } diff --git a/unity/Assets/Scripts/DebugInputField.cs b/unity/Assets/Scripts/DebugInputField.cs index 9e37abb4e6..748458cb3d 100644 --- a/unity/Assets/Scripts/DebugInputField.cs +++ b/unity/Assets/Scripts/DebugInputField.cs @@ -1722,16 +1722,6 @@ IEnumerator executeBatch(JArray jActions) { break; } - // Force pickup object - case "fpu": { - ServerAction action = new ServerAction(); - action.action = "PickupObject"; - action.objectId = splitcommand[1]; - action.forceAction = true; - CurrentActiveController().ProcessControlCommand(action); - break; - } - // Get objects in box case "oib": { Dictionary action = new Dictionary(); @@ -2060,6 +2050,17 @@ IEnumerator executeBatch(JArray jActions) { break; } + // Force pickup object + case "fpu": { + Dictionary action = new Dictionary(); + action["action"] = "PickupObject"; + if (splitcommand.Length > 1) { + action["objectId"] = splitcommand[1]; + } + action["forceAction"] = true; + CurrentActiveController().ProcessControlCommand(action); + break; + } // pickup using screen coordinates case "puxy": { Dictionary action = new Dictionary(); diff --git a/unity/Assets/Scripts/DroneFPSAgentController.cs b/unity/Assets/Scripts/DroneFPSAgentController.cs index bcff02373f..acb80a906a 100644 --- a/unity/Assets/Scripts/DroneFPSAgentController.cs +++ b/unity/Assets/Scripts/DroneFPSAgentController.cs @@ -116,7 +116,7 @@ public override void FixedUpdate() { } // generates object metadata based on sim object's properties - public override ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics simObj, bool isVisible) { + public override ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics simObj, bool isVisible, bool isInteractable) { DroneObjectMetadata objMeta = new DroneObjectMetadata(); objMeta.isCaught = this.isObjectCaught(simObj); objMeta.numSimObjHits = simObj.numSimObjHit; @@ -181,8 +181,6 @@ public override ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics sim } } - - // can this object change others to hot? objMeta.isHeatSource = simObj.isHeatSource; @@ -213,6 +211,10 @@ public override ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics sim // in the multiagent setting, explicitly giving this information for now. objMeta.visible = isVisible; // simObj.isVisible; + //determines if the objects is unobstructed and interactable. Objects visible behind see-through geometry like glass will be isInteractable=False even if visible + //note using forceAction=True will ignore the isInteractable requirement + objMeta.isInteractable = isInteractable; + objMeta.isMoving = simObj.inMotion;// keep track of if this object is actively moving objMeta.objectOrientedBoundingBox = simObj.ObjectOrientedBoundingBox; diff --git a/unity/Assets/Scripts/ExpRoom/PhysicsRemoteFPSAgentController_partial_ExpRoom.cs b/unity/Assets/Scripts/ExpRoom/PhysicsRemoteFPSAgentController_partial_ExpRoom.cs index 0b8d5f7bde..92c53f61bb 100644 --- a/unity/Assets/Scripts/ExpRoom/PhysicsRemoteFPSAgentController_partial_ExpRoom.cs +++ b/unity/Assets/Scripts/ExpRoom/PhysicsRemoteFPSAgentController_partial_ExpRoom.cs @@ -180,7 +180,7 @@ SimObjPhysics cover in availableExpRoomContainersDict.OrderBy( return false; } if (i == 0) { - if (isSimObjVisible(visibilityCheckCamera, toCover, 10f)) { + if (isSimObjVisible(visibilityCheckCamera, toCover, 10f).visible) { return false; } } @@ -415,9 +415,11 @@ public void ObjectsVisibleFromThirdPartyCamera(int thirdPartyCameraIndex, float? if (!maxDistance.HasValue) { maxDistance = maxVisibleDistance; } + + SimObjPhysics[] interactable; actionFinishedEmit(true, GetAllVisibleSimObjPhysicsDistance( - agentManager.thirdPartyCameras[thirdPartyCameraIndex], maxDistance.Value, null + agentManager.thirdPartyCameras[thirdPartyCameraIndex], maxDistance.Value, null, out interactable ).Select(sop => sop.ObjectID).ToList() ); } @@ -441,9 +443,8 @@ public void ProportionOfObjectVisible( Camera camera = thirdPartyCameraIndex.HasValue ? agentManager.thirdPartyCameras[thirdPartyCameraIndex.Value] : m_Camera; foreach (Transform point in visPoints) { // if this particular point is in view... - if (CheckIfVisibilityPointInViewport( - target, point, camera, false - )) { + + if (CheckIfVisibilityPointInViewport(target, point, camera, false).visible) { visPointCount++; } } diff --git a/unity/Assets/Scripts/PhysicsRemoteFPSAgentController.cs b/unity/Assets/Scripts/PhysicsRemoteFPSAgentController.cs index 5d0178a2a3..457446c947 100644 --- a/unity/Assets/Scripts/PhysicsRemoteFPSAgentController.cs +++ b/unity/Assets/Scripts/PhysicsRemoteFPSAgentController.cs @@ -70,7 +70,7 @@ public void SetTemperatureDecayTime(string objectId, float decayTime) { if (decayTime < 0) { throw new ArgumentOutOfRangeException("decayTime must be >= 0. You gave " + decayTime); } - SimObjPhysics sop = getTargetObject(objectId: objectId, forceAction: true); + SimObjPhysics sop = getInteractableSimObjectFromId(objectId: objectId, forceAction: true); sop.SetHowManySecondsUntilRoomTemp(decayTime); actionFinished(true); } @@ -134,8 +134,8 @@ public override MetadataWrapper generateMetadataWrapper() { return metaWrapper; } - public override ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics simObj, bool isVisible) { - return base.ObjectMetadataFromSimObjPhysics(simObj, isVisible); + public override ObjectMetadata ObjectMetadataFromSimObjPhysics(SimObjPhysics simObj, bool isVisible, bool isInteractable) { + return base.ObjectMetadataFromSimObjPhysics(simObj, isVisible, isInteractable); } // change the radius of the agent's capsule on the char controller component, and the capsule collider component @@ -2048,16 +2048,6 @@ public void ApplyForceObject(ServerAction action) { target = getSimObjectFromId(action.objectId); } - // SimObjPhysics[] simObjPhysicsArray = VisibleSimObjs(action); - - // foreach (SimObjPhysics sop in simObjPhysicsArray) { - // if (action.objectId == sop.ObjectID) { - // target = sop; - // } - // } - // print(target.objectID); - // print(target.isInteractable); - if (target == null) { errorMessage = "No valid target!"; Debug.Log(errorMessage); @@ -3018,14 +3008,9 @@ public void ScaleObject( float scaleOverSeconds = 1.0f, bool forceAction = false ) { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } // if object is in the scene and visible, assign it to 'target' - SimObjPhysics target = getInteractableSimObjectFromId(objectId, forceAction); + SimObjPhysics target = getInteractableSimObjectFromId(objectId: objectId, forceAction: forceAction); // neither objectId nor coordinates found an object if (target == null) { @@ -4037,14 +4022,8 @@ public void PlaceHeldObject(string objectId, float maxDistance, bool forceAction // get the target receptacle based on the action object ID SimObjPhysics targetReceptacle = null; - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - targetReceptacle = getInteractableSimObjectFromId(objectId: objectId, forceVisible: forceAction); + targetReceptacle = getInteractableSimObjectFromId(objectId: objectId, forceAction: forceAction); placeHeldObject( targetReceptacle: targetReceptacle, @@ -4322,12 +4301,12 @@ bool markActionFinished } public virtual void PickupObject(float x, float y, bool forceAction = false, bool manualInteract = false) { - SimObjPhysics target = getTargetObject(x: x, y: y, forceAction: forceAction); + SimObjPhysics target = getInteractableSimObjectFromId(x: x, y: y, forceAction: forceAction); pickupObject(target: target, forceAction: forceAction, manualInteract: manualInteract, markActionFinished: true); } public virtual void PickupObject(string objectId, bool forceAction = false, bool manualInteract = false) { - SimObjPhysics target = getTargetObject(objectId: objectId, forceAction: forceAction); + SimObjPhysics target = getInteractableSimObjectFromId(objectId: objectId, forceAction: forceAction); pickupObject(target: target, forceAction: forceAction, manualInteract: manualInteract, markActionFinished: true); } @@ -4829,14 +4808,8 @@ public void CookObject(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } @@ -4950,16 +4923,10 @@ private void toggleObject(float x, float y, bool toggleOn, bool forceAction) { private void toggleObject(string objectId, bool toggleOn, bool forceAction) { SimObjPhysics target = null; - bool forceVisible = forceAction; - - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(objectId: objectId, forceVisible: forceVisible); + target = getInteractableSimObjectFromId(objectId: objectId, forceAction: forceAction); + if (!target) { // target not found in currently visible objects, report not found @@ -5150,7 +5117,7 @@ public void OpenObjectImmediate( string objectId, float openness = 1.0f ) { - SimObjPhysics target = getTargetObject(objectId: objectId, forceAction: true); + SimObjPhysics target = getInteractableSimObjectFromId(objectId: objectId, forceAction: true); target.GetComponent().SetOpennessImmediate(openness); actionFinished(true); } @@ -5161,7 +5128,7 @@ public void OpenObject( float openness = 1, float? moveMagnitude = null // moveMagnitude is supported for backwards compatibility. It's new name is 'openness'. ) { - SimObjPhysics target = getTargetObject(objectId: objectId, forceAction: forceAction); + SimObjPhysics target = getInteractableSimObjectFromId(objectId: objectId, forceAction: forceAction); openObject( target: target, openness: openness, @@ -5197,8 +5164,7 @@ public void OpenObject( ); } - // XXX: To get all objects contained in a receptacle, target it with this Function and it will return a list of strings, each being the - // object ID of an object in this receptacle + // XXX: This will return contained objects, but should not be used. Likely depracate this later public void Contains(ServerAction action) { if (action.objectId == null) { errorMessage = "Hey, actually give me an object ID check containment for, yeah?"; @@ -5206,7 +5172,7 @@ public void Contains(ServerAction action) { return; } - SimObjPhysics target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + SimObjPhysics target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); if (target) { List ids = target.GetAllSimObjectsInReceptacleTriggersByObjectID(); @@ -5910,8 +5876,8 @@ public bool objectIsCurrentlyVisible(SimObjPhysics sop, float maxDistance) { // Debug.Log(Vector3.Distance(tmp, transform.position)); if (Vector3.Distance(tmp, transform.position) < maxDistance) { // if this particular point is in view... - if (CheckIfVisibilityPointInViewport(sop, point, m_Camera, false) || - CheckIfVisibilityPointInViewport(sop, point, m_Camera, true)) { + if ((CheckIfVisibilityPointInViewport(sop, point, m_Camera, false).visible || + CheckIfVisibilityPointInViewport(sop, point, m_Camera, true).visible)) { updateAllAgentCollidersForVisibilityCheck(true); return true; } @@ -6120,7 +6086,7 @@ private List> getInteractablePoses( maxDistanceFloat = (float)maxDistance; } - SimObjPhysics theObject = getTargetObject(objectId: objectId, forceAction: true); + SimObjPhysics theObject = getInteractableSimObjectFromId(objectId: objectId, forceAction: true); // Populate default standings. Note that these are boolean because that's // the most natural integration with Teleport @@ -6897,7 +6863,7 @@ protected float approxPercentScreenObjectOccupies(SimObjPhysics sop, bool update foreach (Transform point in sop.VisibilityPoints) { Vector3 viewPoint = m_Camera.WorldToViewportPoint(point.position); - if (CheckIfVisibilityPointInViewport(sop, point, m_Camera, false)) { + if (CheckIfVisibilityPointInViewport(sop, point, m_Camera, false).visible) { minX = Math.Min(viewPoint.x, minX); maxX = Math.Max(viewPoint.x, maxX); minY = Math.Min(viewPoint.y, minY); @@ -7982,14 +7948,8 @@ public void SliceObject(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } // we found it! @@ -8044,14 +8004,8 @@ public void BreakObject(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } // we found it! @@ -8112,14 +8066,8 @@ public void DirtyObject(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } if (target) { @@ -8168,14 +8116,8 @@ public void CleanObject(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } if (target) { @@ -8225,14 +8167,8 @@ public void FillObjectWithLiquid(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } if (action.fillLiquid == null) { @@ -8288,14 +8224,8 @@ public void EmptyLiquidFromObject(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } if (target) { @@ -8346,14 +8276,7 @@ public void UseUpObject(ServerAction action) { // an objectId was given, so find that target in the scene if it exists else { - if (!physicsSceneManager.ObjectIdToSimObjPhysics.ContainsKey(action.objectId)) { - errorMessage = "Object ID appears to be invalid."; - actionFinished(false); - return; - } - - // if object is in the scene and visible, assign it to 'target' - target = getInteractableSimObjectFromId(action.objectId, action.forceVisible); + target = getInteractableSimObjectFromId(objectId: action.objectId, forceAction: action.forceAction); } if (target) { diff --git a/unity/Assets/Scripts/SimObjPhysics.cs b/unity/Assets/Scripts/SimObjPhysics.cs index a5c9dc2f93..d9149819a5 100644 --- a/unity/Assets/Scripts/SimObjPhysics.cs +++ b/unity/Assets/Scripts/SimObjPhysics.cs @@ -47,8 +47,8 @@ public class SimObjPhysics : MonoBehaviour, SimpleSimObj { [Header("State information Bools here")] #if UNITY_EDITOR public bool debugIsVisible = false; -#endif public bool debugIsInteractable = false; +#endif public bool isInAgentHand = false; public DroneFPSAgentController droneFPSAgent; @@ -952,8 +952,6 @@ public bool DoesThisObjectHaveThisSecondaryProperty(SimObjSecondaryProperty prop } // Update is called once per frame void Update() { - debugIsInteractable = false; - if (sceneManager.AllowDecayTemperature)// only do this if the scene is initialized to use Temperature decay over time { // if this object is either hot or col, begin a timer that counts until the object becomes room temperature again @@ -977,9 +975,6 @@ void LateUpdate() { lastVelocity = Math.Abs(myRigidbody.angularVelocity.sqrMagnitude + myRigidbody.velocity.sqrMagnitude); } } - private void FixedUpdate() { - // isInteractable = false; - } // used for throwing the sim object, or anything that requires adding force for some reason public void ApplyForce(ServerAction action) { @@ -1120,7 +1115,7 @@ void OnDrawGizmos() { } // interactable drawn in magenta - if (debugIsInteractable == true && gameObject.GetComponentInChildren()) { + if (debugIsInteractable && gameObject.GetComponentInChildren()) { MeshFilter mf = gameObject.GetComponentInChildren(false); Gizmos.color = Color.magenta; Gizmos.DrawWireMesh(mf.sharedMesh, -1, mf.transform.position, mf.transform.rotation, mf.transform.lossyScale); diff --git a/unity/Assets/UnitTests/TestObstructed.cs b/unity/Assets/UnitTests/TestObstructed.cs new file mode 100644 index 0000000000..cdcfdf66aa --- /dev/null +++ b/unity/Assets/UnitTests/TestObstructed.cs @@ -0,0 +1,75 @@ +using System.Collections; +using System.Collections.Generic; +using NUnit.Framework; +using System; +using UnityEngine; +using UnityEngine.TestTools; +using UnityStandardAssets.Characters.FirstPerson; + +namespace Tests { + public class TestObstructed : TestBase { + + [SetUp] + public override void Setup() { + UnityEngine.SceneManagement.SceneManager.LoadScene("FloorPlan402_physics"); + } + + [UnityTest] + public IEnumerator TestBehindGlassThenOpenDoor() { + Debug.Log("what is the current scene? " + UnityEngine.SceneManagement.SceneManager.GetActiveScene().name); + + Dictionary action = new Dictionary(); + + action["action"] = "Initialize"; + action["fieldOfView"] = 90f; + action["snapToGrid"] = true; + //action["scene"] = "FloorPlan402_physics"; + yield return step(action); + + action.Clear(); + + //teleport to position + action["action"] = "Teleport"; + action["position"] = new Vector3(-1.25f, 0.9006702f, 2.75f); + action["horizon"] = 30f; + action["rotation"] = new Vector3(0, -180f, 0); + yield return step(action); + + action.Clear(); + + action["action"] = "SetObjectPoses"; + ObjectPose pose = new ObjectPose() { + objectName = "SoapBottle_445f0dcf", + position = new Vector3(-1.022f, 0f, 1.456f), + rotation = new Vector3(0, -180f, 0) + }; + ObjectPose[] poses = new ObjectPose[1]; + poses[0] = pose; + action["objectPoses"] = poses; + yield return step(action); + + action.Clear(); + + GameObject bottle = GameObject.Find("SoapBottle_445f0dcf"); + + action["action"] = "PickupObject"; + action["objectId"] = bottle.GetComponent().objectID; + yield return step(action); + + Assert.AreEqual(lastActionSuccess, false); + + action.Clear(); + + //note normal OpenObject doesn't seem to work as the next action executes before door is fully open? + action["action"] = "OpenObjectImmediate"; + action["objectId"] = "ShowerDoor|-00.28|+01.23|+01.73"; + yield return step(action); + + action["action"] = "PickupObject"; + action["objectId"] = bottle.GetComponent().objectID; + yield return step(action); + + Assert.AreEqual(lastActionSuccess, true); + } + } +} diff --git a/unity/Assets/UnitTests/TestObstructed.cs.meta b/unity/Assets/UnitTests/TestObstructed.cs.meta new file mode 100644 index 0000000000..13840004c4 --- /dev/null +++ b/unity/Assets/UnitTests/TestObstructed.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 63923a38901f69041808ac09761aa015 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: