in IndoorSceneSynthesis/ConstraintStochasticIndoorSceneGeneration/Custom/CustomScripts/CObjectPlacerTool.cs [616:836]
public bool CustomPlaceObj(SimObjPhysics sop, CustomReceptacleSpawnPoint crsp, bool PlaceStationary, int degreeIncrement, bool alwaysPlaceUpright) {
if (crsp.ParentSimObjPhys == sop) {
#if UNITY_EDITOR
Debug.Log("Can't place object inside itself!");
#endif
return false;
}
//remember the original rotation of the sim object if we need to reset it
//Quaternion originalRot = sop.transform.rotation;
Vector3 originalPos = sop.transform.position;
Quaternion originalRot = sop.transform.rotation;
//get the bounding box of the sim object we are trying to place
BoxCollider oabb = sop.BoundingBox.GetComponent<BoxCollider>();
oabb.enabled = true;
//zero out rotation and velocity/angular velocity, then match the target receptacle's rotation
//?????????
sop.transform.rotation = crsp.ReceptacleBox.transform.rotation;
Rigidbody sopRB = sop.GetComponent<Rigidbody>();
sopRB.velocity = Vector3.zero;
sopRB.angularVelocity = Vector3.zero;
Plane BoxBottom;
float DistanceFromBoxBottomTosop;
InstantiatePrefabTest.RotationAndDistanceValues quat;
//Vector3 Offset = oabb.ClosestPoint(oabb.transform.TransformPoint(oabb.center) + -crsp.ReceptacleBox.transform.up * 5); //was using rsp.point
Vector3 target_location = oabb.transform.TransformPoint(oabb.center) + -crsp.ReceptacleBox.transform.up * 5;
Vector3 Offset = oabb.ClosestPoint(target_location);
//Debug.Log(oabb.center + " box: " + oabb.bounds.extents.ToString() + " oabb 2 global: " + oabb.transform.TransformPoint(oabb.center) + "offset: " + Offset.ToString());
BoxBottom = new Plane(crsp.ReceptacleBox.transform.up, Offset);
DistanceFromBoxBottomTosop = BoxBottom.GetDistanceToPoint(sop.transform.position);
//quat = new InstantiatePrefabTest.RotationAndDistanceValues(DistanceFromBoxBottomTosop,
// Quaternion.Euler(0, -crsp.rotationRad * Mathf.Rad2Deg + 90, 0));
quat = new InstantiatePrefabTest.RotationAndDistanceValues(DistanceFromBoxBottomTosop,
Quaternion.Euler(0, crsp.rotationRad * Mathf.Rad2Deg, 0));
Vector3 newPosition = crsp.Point + crsp.ParentSimObjPhys.transform.up * (quat.distance + this.yoffset);
//Debug.Log("spawner: " + spawner.gameObject.name + " " + crsp.Point.ToString());
//Debug.Log("quat: " + quat.distance + " " + quat.rotation + " -crsp.rotateDegree " + -crsp.rotateDegree);
//if spawn area is clear, spawn it and return true that we spawned it
//bool noCollison = spawner.CheckSpawnArea(sop, newPosition, quat.rotation, false);
//track colliders
List<Collider> colsToDisable = new List<Collider>();
foreach (Collider g in sop.MyColliders) {
//only track this collider if it's enabled by default
//some objects, like houseplants, might have colliders in their simObj.MyColliders that are disabled
if (g.enabled) {
colsToDisable.Add(g);
}
}
//GameObject parentObject = crsp.ParentSimObjPhys.gameObject;
//foreach (Collider c in parentObject.GetComponentsInChildren<Collider>()) {
// colsToDisable.Add(c);
//}
//disable collision before moving to check the spawn area
foreach (Collider c in colsToDisable) {
c.enabled = false;
}
//move it into place so the bouding box is in the right spot to generate the overlap box later
sop.transform.position = newPosition;
sop.transform.rotation = quat.rotation;
//now let's get the BoundingBox of the simObj as reference cause we need it to create the overlapbox
GameObject bb = sop.BoundingBox.transform.gameObject;
//Debug.Log("sop: " + sop.Type + " layer: " + bb.layer);
//bb.layer = 8;
BoxCollider bbcol = bb.GetComponent<BoxCollider>();
Vector3 bbCenter = bbcol.center;
Vector3 bbCenterTransformPoint = bb.transform.TransformPoint(bbCenter);
//move sim object back to it's original spot back so the overlap box doesn't hit it
sop.transform.position = originalPos;
sop.transform.rotation = originalRot;
//re-enable the collision after returning in place
foreach (Collider c in colsToDisable) {
c.enabled = true;
}
//spawn overlap box
Collider[] hitColliders = Physics.OverlapBox(
bbCenterTransformPoint,
bbcol.size / 2.0f,
quat.rotation,
1 << 8 | 1 << 10, //simObjVisible, agent
QueryTriggerInteraction.Collide
);
bool noCollison = hitColliders.Length == 0;
//Debug.Log("spawner: " + spawner.gameObject.name + " " + crsp.Point.ToString());
//Debug.Log("quat: " + quat.distance + " " + quat.rotation + " -crsp.rotateDegree " + -crsp.rotateDegree);
//if spawn area is clear, spawn it and return true that we spawned it
//bool noCollison = spawner.CheckSpawnArea(sop, crsp.Point + crsp.ParentSimObjPhys.transform.up * (quat.distance + this.yoffset), quat.rotation, false);
//oabb.enabled = false;
//Debug.Log(sop.Type + " no collision??????? " + noCollison + " pos " + bbCenterTransformPoint + " size " + bbcol.size / 2.0f);
if (noCollison) {
//translate position of the target sim object to the rsp.Point and offset in local y up
sop.transform.position = crsp.Point + crsp.ReceptacleBox.transform.up * (quat.distance + yoffset);//rsp.Point + sop.transform.up * DistanceFromBottomOfBoxToTransform;
sop.transform.rotation = quat.rotation;
//Check the ReceptacleBox's Sim Object component to see what Type it is. Then check to
//see if the type is the kind where the Object placed must be completely contained or just the bottom 4 corners contained
int HowManyCornersToCheck = 0;
if (ReceptacleRestrictions.OnReceptacles.Contains(crsp.ParentSimObjPhys.ObjType)) {
//check that only the bottom 4 corners are in bounds
HowManyCornersToCheck = 4;
}
if (ReceptacleRestrictions.InReceptacles.Contains(crsp.ParentSimObjPhys.ObjType)) {
//check that all 8 corners are within bounds
HowManyCornersToCheck = 8;
}
if (ReceptacleRestrictions.InReceptaclesThatOnlyCheckBottomFourCorners.Contains(crsp.ParentSimObjPhys.ObjType)) {
//only check bottom 4 corners even though the action is PlaceIn
HowManyCornersToCheck = 4;
}
//Debug.Log("HowManyCornersToCheck: " + HowManyCornersToCheck);
//Special cases
if (crsp.ParentSimObjPhys.ObjType == SimObjType.StoveBurner) {
HowManyCornersToCheck = 0;
}
int CornerCount = 0;
List<Vector3> spawnCorners = GetSimObjCorners(sop);
spawnCorners.Sort(delegate (Vector3 p1, Vector3 p2) {
return Vector3.Distance(p1, crsp.Point).CompareTo(Vector3.Distance(p2, crsp.Point));
});
for (int i = 0; i < 8; i++) {
if (crsp.Script.CheckIfPointIsInsideReceptacleTriggerBox(spawnCorners[i])) {
CornerCount++;
}
}
//if not enough corners are inside the receptacle, abort
if (CornerCount < HowManyCornersToCheck) {
sop.transform.rotation = originalRot;
sop.transform.position = originalPos;
return false;
}
//set true if we want objects to be stationary when placed. (if placed on uneven surface, object remains stationary)
//if false, once placed the object will resolve with physics (if placed on uneven surface object might slide or roll)
if (PlaceStationary == true) {
//make object being placed kinematic true
sop.GetComponent<Rigidbody>().collisionDetectionMode = CollisionDetectionMode.Discrete;
sop.GetComponent<Rigidbody>().isKinematic = true;
//check if the parent sim object is one that moves like a drawer - and would require this to be parented
//if(rsp.ParentSimObjPhys.DoesThisObjectHaveThisSecondaryProperty(SimObjSecondaryProperty.CanOpen))
sop.transform.SetParent(crsp.ParentSimObjPhys.transform);
//GameObject topObject = GameObject.Find("Objects");
//parent to the Objects transform
//sop.transform.SetParent(topObject.transform);
//if this object is a receptacle and it has other objects inside it, drop them all together
if (sop.DoesThisObjectHaveThisSecondaryProperty(SimObjSecondaryProperty.Receptacle)) {
PhysicsRemoteFPSAgentController agent = GameObject.Find("FPSController").GetComponent<PhysicsRemoteFPSAgentController>();
agent.DropContainedObjectsStationary(sop); //use stationary version so that colliders are turned back on, but kinematics remain true
}
//if the target receptacle is a pickupable receptacle, set it to kinematic true as will sence we are placing stationary
if (crsp.ParentSimObjPhys.PrimaryProperty == SimObjPrimaryProperty.CanPickup) {
crsp.ParentSimObjPhys.GetComponent<Rigidbody>().isKinematic = true;
}
}
//place stationary false, let physics drop everything too
else {
//if not placing stationary, put all objects under Objects game object
GameObject topObject = GameObject.Find("Objects");
//parent to the Objects transform
sop.transform.SetParent(topObject.transform);
Rigidbody rb = sop.GetComponent<Rigidbody>();
rb.isKinematic = false;
rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic;
//if this object is a receptacle and it has other objects inside it, drop them all together
if (sop.DoesThisObjectHaveThisSecondaryProperty(SimObjSecondaryProperty.Receptacle)) {
PhysicsRemoteFPSAgentController agent = GameObject.Find("FPSController").GetComponent<PhysicsRemoteFPSAgentController>();
agent.DropContainedObjects(target: sop, reparentContainedObjects: true, forceKinematic: false);
}
}
sop.isInAgentHand = false;//set agent hand flag
objectPool.generatedObjects.Add(sop.gameObject);
// #if UNITY_EDITOR
// Debug.Log(sop.name + " succesfully spawned in " +rsp.ParentSimObjPhys.name + " at coordinate " + rsp.Point);
// #endif
return true;
}
return false;
}