public static GameObject SpawnInFrontOfCamera(GameObject sourceObject, Camera camera, Config config) { float halfSize = config.ObjectSize * 0.5f; var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = Vector3Ex.FromValue(1.0f); Transform cameraTransform = camera.transform; AABB aabb = ObjectBounds.CalcHierarchyWorldAABB(sourceObject, boundsQConfig); if (!aabb.IsValid) return null; Sphere sphere = new Sphere(aabb); Vector3 fromCenterToPos = sourceObject.transform.position - sphere.Center; float zOffset = Mathf.Max(camera.nearClipPlane + sphere.Radius, sphere.Radius / halfSize); Vector3 spherePos = cameraTransform.position + cameraTransform.forward * zOffset; GameObject spawned = GameObject.Instantiate(sourceObject, spherePos + fromCenterToPos, sourceObject.transform.rotation) as GameObject; spawned.SetActive(true); OBB spawnedOBB = ObjectBounds.CalcHierarchyWorldOBB(spawned, boundsQConfig); Ray ray = new Ray(camera.transform.position, (spawnedOBB.Center - camera.transform.position).normalized); var raycastFilter = new SceneRaycastFilter(); raycastFilter.AllowedObjectTypes.Add(GameObjectType.Mesh); raycastFilter.AllowedObjectTypes.Add(GameObjectType.Terrain); raycastFilter.AllowedObjectTypes.Add(GameObjectType.Sprite); var rayHit = RTScene.Get.Raycast(ray, SceneRaycastPrecision.BestFit, raycastFilter); if (rayHit.WasAnObjectHit) { Vector3 oldCenter = spawnedOBB.Center; spawnedOBB.Center = rayHit.ObjectHit.HitPoint; Vector3 offsetVector = spawnedOBB.Center - oldCenter; offsetVector += ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(spawnedOBB, rayHit.ObjectHit.HitPlane, 0.0f); spawned.transform.position += offsetVector; } return spawned; }
public override void OnGizmoDragUpdate(int handleId) { if (OwnsHandle(handleId) && Gizmo.RelativeDragOffset.magnitude != 0.0f) { float extrAmount = Gizmo.RelativeDragOffset.magnitude; float boxSize = _boxSize[_handleDragExtrData.AxisIndex]; float fNumClones = boxSize != 0.0f ? (extrAmount / boxSize) : 0.0f; int iNumClones = (int)fNumClones; float absFractional = Mathf.Abs(fNumClones - (int)fNumClones); if (iNumClones == 0 && Mathf.Abs(absFractional - 1.0f) < 1e-5f) { ++iNumClones; } var createdClones = new List <GameObject>(10); var cloneConfig = ObjectCloning.DefaultConfig; var cloneOffset = _handleDragExtrData.ExtrudeDir * boxSize; for (int cloneIndex = 0; cloneIndex < iNumClones; ++cloneIndex) { foreach (var targetParent in _targetParents) { if (_ignoredParentObjects.Contains(targetParent)) { continue; } if (!Hotkeys.EnableOverlapTest.IsActive()) { cloneConfig.Parent = targetParent.transform.parent; var clonedHierarchy = ObjectCloning.CloneHierarchy(targetParent, cloneConfig); if (clonedHierarchy != null) { _sceneOverlapFilter.IgnoreObjects.AddRange(clonedHierarchy.GetAllChildrenAndSelf()); _dragEndAction.AddExtrudeClone(clonedHierarchy); createdClones.Add(clonedHierarchy); } clonedHierarchy.transform.position += cloneIndex * cloneOffset; } else { OBB targetOBB = ObjectBounds.CalcHierarchyWorldOBB(targetParent, _boundsQConfig); if (!targetOBB.IsValid) { continue; } targetOBB.Center += cloneIndex * cloneOffset; // Bring the size down a tad. Otherwise, we can get false positives when objects are really close to // each other even if they do not intersect. targetOBB.Inflate(-1e-2f); var overlappedObjects = RTScene.Get.OverlapBox(targetOBB, _sceneOverlapFilter); if (overlappedObjects.Count != 0) { continue; } cloneConfig.Parent = targetParent.transform.parent; var clonedHierarchy = ObjectCloning.CloneHierarchy(targetParent, cloneConfig); if (clonedHierarchy != null) { _sceneOverlapFilter.IgnoreObjects.AddRange(clonedHierarchy.GetAllChildrenAndSelf()); _dragEndAction.AddExtrudeClone(clonedHierarchy); createdClones.Add(clonedHierarchy); } clonedHierarchy.transform.position += cloneIndex * cloneOffset; } } } _handleDragExtrData.ExtrudeCenter += Gizmo.RelativeDragOffset; foreach (var targetParent in _targetParents) { if (!_ignoredParentObjects.Contains(targetParent)) { targetParent.transform.position += Gizmo.RelativeDragOffset; } } if (ExtrudeUpdate != null) { ExtrudeUpdate(createdClones); } } }
public void FitBoxToTargets() { if (NumTargetParents == 0) { _boxSize = Vector3.zero; return; } if (ExtrudeSpace == GizmoSpace.Global) { AABB worldAABB = AABB.GetInvalid(); foreach (var parent in _targetParents) { if (_ignoredParentObjects.Contains(parent)) { continue; } AABB aabb = ObjectBounds.CalcHierarchyWorldAABB(parent, _boundsQConfig); if (aabb.IsValid) { if (worldAABB.IsValid) { worldAABB.Encapsulate(aabb); } else { worldAABB = aabb; } } } SetAABB(worldAABB); UpdateSnapSteps(); } else if (ExtrudeSpace == GizmoSpace.Local) { int firstParentIndex = 0; while (firstParentIndex < NumTargetParents) { if (_ignoredParentObjects.Contains(_targetParents[firstParentIndex])) { ++firstParentIndex; } else { break; } } if (firstParentIndex == NumTargetParents) { SetOBB(OBB.GetInvalid()); UpdateSnapSteps(); return; } OBB worldOBB = ObjectBounds.CalcHierarchyWorldOBB(_targetParents[firstParentIndex], _boundsQConfig); for (int parentIndex = firstParentIndex; parentIndex < NumTargetParents; ++parentIndex) { GameObject parent = _targetParents[parentIndex]; if (_ignoredParentObjects.Contains(parent)) { continue; } OBB obb = ObjectBounds.CalcHierarchyWorldOBB(parent, _boundsQConfig); if (obb.IsValid) { if (worldOBB.IsValid) { worldOBB.Encapsulate(obb); } else { worldOBB = obb; } } } SetOBB(worldOBB); UpdateSnapSteps(); } }
public void Render() { if (SharedLookAndFeel == null) { return; } if (IsActive && _grabSurfaceInfo.SurfaceType != GrabSurfaceType.Invalid) { Material material = MaterialPool.Get.SimpleColor; if (SharedLookAndFeel.DrawAnchorLines) { List <Vector3> linePoints = new List <Vector3>(_grabTargets.Count * 2); foreach (GrabTarget grabTarget in _grabTargets) { linePoints.Add(grabTarget.Transform.position); linePoints.Add(_grabSurfaceInfo.AnchorPoint); } material.SetZTestAlways(); material.SetColor(_sharedLookAndFeel.AnchorLineColor); material.SetPass(0); GLRenderer.DrawLines3D(linePoints); } if (SharedLookAndFeel.DrawObjectBoxes) { material.SetZTestLess(); material.SetColor(SharedLookAndFeel.ObjectBoxWireColor); material.SetPass(0); ObjectBounds.QueryConfig boundsQConfig = GetObjectBoundsQConfig(); foreach (GrabTarget grabTarget in _grabTargets) { OBB obb = ObjectBounds.CalcHierarchyWorldOBB(grabTarget.GameObject, boundsQConfig); if (obb.IsValid) { GraphicsEx.DrawWireBox(obb); } } } if (SharedLookAndFeel.DrawObjectPosTicks) { material.SetColor(SharedLookAndFeel.ObjectPosTickColor); material.SetPass(0); foreach (GrabTarget grabTarget in _grabTargets) { Vector2 screenPos = Camera.current.WorldToScreenPoint(grabTarget.Transform.position); GLRenderer.DrawRect2D(RectEx.FromCenterAndSize(screenPos, Vector2Ex.FromValue(SharedLookAndFeel.ObjectPosTickSize)), Camera.current); } } if (SharedLookAndFeel.DrawAnchorPosTick) { material.SetColor(SharedLookAndFeel.AnchorPosTickColor); material.SetPass(0); Vector2 anchorScreenPos = Camera.current.WorldToScreenPoint(_grabSurfaceInfo.AnchorPoint); GLRenderer.DrawRect2D(RectEx.FromCenterAndSize(anchorScreenPos, Vector2Ex.FromValue(SharedLookAndFeel.AnchorPosTickSize)), Camera.current); } } }
public static List <Vector3> CollectHierarchyVerts(GameObject root, BoxFace collectFace, float collectBoxScale, float collectEps) { List <GameObject> meshObjects = root.GetMeshObjectsInHierarchy(); List <GameObject> spriteObjects = root.GetSpriteObjectsInHierarchy(); if (meshObjects.Count == 0 && spriteObjects.Count == 0) { return(new List <Vector3>()); } ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new List <Vector3>()); } int faceAxisIndex = BoxMath.GetFaceAxisIndex(collectFace); Vector3 faceCenter = BoxMath.CalcBoxFaceCenter(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, collectFace); Vector3 faceNormal = BoxMath.CalcBoxFaceNormal(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, collectFace); float sizeEps = collectEps * 2.0f; Vector3 collectAABBSize = hierarchyOBB.Size; collectAABBSize[faceAxisIndex] = (hierarchyOBB.Size[faceAxisIndex] * collectBoxScale) + sizeEps; collectAABBSize[(faceAxisIndex + 1) % 3] += sizeEps; collectAABBSize[(faceAxisIndex + 2) % 3] += sizeEps; OBB collectOBB = new OBB(faceCenter + faceNormal * (-collectAABBSize[faceAxisIndex] * 0.5f + collectEps), collectAABBSize); collectOBB.Rotation = hierarchyOBB.Rotation; List <Vector3> collectedVerts = new List <Vector3>(80); foreach (GameObject meshObject in meshObjects) { Mesh mesh = meshObject.GetMesh(); RTMesh rtMesh = RTMeshDb.Get.GetRTMesh(mesh); if (rtMesh == null) { continue; } List <Vector3> verts = rtMesh.OverlapVerts(collectOBB, meshObject.transform); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } foreach (GameObject spriteObject in spriteObjects) { List <Vector3> verts = CollectWorldSpriteVerts(spriteObject.GetSprite(), spriteObject.transform, collectOBB); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } return(collectedVerts); }
public static SnapResult SnapHierarchy(GameObject root, SnapConfig snapConfig) { const float collectEps = 1e-2f; const float collectBoxScale = 1e-3f; bool hierarchyHasMeshes = root.HierarchyHasMesh(); bool hierarchyHasSprites = root.HierarchyHasSprite(); if (!hierarchyHasMeshes && !hierarchyHasSprites) { Transform rootTransform = root.transform; rootTransform.position = snapConfig.SurfaceHitPlane.ProjectPoint(rootTransform.position) + snapConfig.OffsetFromSurface * snapConfig.SurfaceHitNormal; return(new SnapResult(snapConfig.SurfaceHitPlane, rootTransform.position)); } ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Sprite | GameObjectType.Mesh; bool isSurfaceSpherical = snapConfig.SurfaceType == Type.SphericalMesh; bool isSurfaceTerrain = snapConfig.SurfaceType == Type.UnityTerrain || snapConfig.SurfaceType == Type.TerrainMesh; bool isSurfaceUnityTerrain = snapConfig.SurfaceType == Type.UnityTerrain; SurfaceRaycaster raycaster = CreateSurfaceRaycaster(snapConfig.SurfaceType, snapConfig.SurfaceObject, true); if (snapConfig.SurfaceType != Type.SceneGrid) { Transform rootTransform = root.transform; if (snapConfig.AlignAxis) { if (isSurfaceTerrain) { rootTransform.Align(Vector3.up, snapConfig.AlignmentAxis); OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -Vector3.up); List <Vector3> collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); if (collectedVerts.Count != 0) { Vector3 vertsCenter = Vector3Ex.GetPointCloudCenter(collectedVerts); Ray ray = new Ray(vertsCenter + Vector3.up * 1e-3f, -Vector3.up); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 alignmentAxis = surfaceHit.HitNormal; if (isSurfaceUnityTerrain) { Terrain terrain = snapConfig.SurfaceObject.GetComponent <Terrain>(); alignmentAxis = terrain.GetInterpolatedNormal(surfaceHit.HitPoint); } Quaternion appliedRotation = rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); appliedRotation.RotatePoints(collectedVerts, rootTransform.position); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, new Plane(Vector3.up, surfaceHit.HitPoint), 0.1f); rootTransform.position += sitOnPlaneOffset; hierarchyOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); Vector3 embedVector = ObjectSurfaceSnap.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -Vector3.up, snapConfig.SurfaceType); rootTransform.position += (embedVector + alignmentAxis * snapConfig.OffsetFromSurface); return(new SnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } } } else { if (!isSurfaceSpherical) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -snapConfig.SurfaceHitNormal); List <Vector3> collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); if (collectedVerts.Count != 0) { Vector3 vertsCenter = Vector3Ex.GetPointCloudCenter(collectedVerts); // Note: Cast the ray from far away enough so that we don't cast from the interior of the mesh. // This can happen when the object is embedded inside the mesh surface. AABB surfaceAABB = ObjectBounds.CalcMeshWorldAABB(snapConfig.SurfaceObject); float sphereRadius = surfaceAABB.Extents.magnitude; Vector3 rayOrigin = vertsCenter + snapConfig.SurfaceHitNormal * sphereRadius; Ray ray = new Ray(rayOrigin, -snapConfig.SurfaceHitNormal); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 alignmentAxis = surfaceHit.HitNormal; rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; rootTransform.position += alignmentAxis * snapConfig.OffsetFromSurface; return(new SnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } else { Vector3 alignmentAxis = snapConfig.SurfaceHitNormal; rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, snapConfig.SurfaceHitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; rootTransform.position += alignmentAxis * snapConfig.OffsetFromSurface; return(new SnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(vertsCenter))); } } } else { Transform surfaceObjectTransform = snapConfig.SurfaceObject.transform; Vector3 sphereCenter = surfaceObjectTransform.position; Vector3 radiusDir = (rootTransform.position - sphereCenter).normalized; float sphereRadius = surfaceObjectTransform.lossyScale.GetMaxAbsComp() * 0.5f; rootTransform.Align(radiusDir, snapConfig.AlignmentAxis); OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -radiusDir); List <Vector3> collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); rootTransform.position += radiusDir * snapConfig.OffsetFromSurface; return(new SnapResult(sitPlane, sitPoint)); } } } else { OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } if (isSurfaceTerrain || (!isSurfaceSpherical && snapConfig.SurfaceType == Type.Mesh)) { Ray ray = new Ray(hierarchyOBB.Center, isSurfaceTerrain ? -Vector3.up : -snapConfig.SurfaceHitNormal); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; if (isSurfaceTerrain) { hierarchyOBB.Center += sitOnPlaneOffset; BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -surfaceHit.HitNormal); List <Vector3> collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 embedVector = ObjectSurfaceSnap.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -Vector3.up, snapConfig.SurfaceType); rootTransform.position += embedVector; } rootTransform.position += surfaceHit.HitNormal * snapConfig.OffsetFromSurface; return(new SnapResult(surfaceHit.HitPlane, surfaceHit.HitPoint)); } else if (!isSurfaceSpherical && snapConfig.SurfaceType == Type.Mesh) { Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, snapConfig.SurfaceHitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; rootTransform.position += snapConfig.SurfaceHitNormal * snapConfig.OffsetFromSurface; return(new SnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(hierarchyOBB.Center))); } } else if (isSurfaceSpherical) { Transform surfaceObjectTransform = snapConfig.SurfaceObject.transform; Vector3 sphereCenter = surfaceObjectTransform.position; Vector3 radiusDir = (rootTransform.position - sphereCenter).normalized; float sphereRadius = surfaceObjectTransform.lossyScale.GetMaxAbsComp() * 0.5f; BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.Rotation, -radiusDir); List <Vector3> collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); rootTransform.position += radiusDir * snapConfig.OffsetFromSurface; return(new SnapResult(sitPlane, sitPoint)); } } } if (snapConfig.SurfaceType == Type.SceneGrid) { OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } Transform rootTransform = root.transform; if (snapConfig.AlignAxis) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); } rootTransform.position += ObjectSurfaceSnap.CalculateSitOnSurfaceOffset(hierarchyOBB, snapConfig.SurfaceHitPlane, snapConfig.OffsetFromSurface); return(new SnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(hierarchyOBB.Center))); } return(new SnapResult()); }
private OBB CalcTargetRootOBB(GameObject targetRoot) { ObjectBounds.QueryConfig boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; return(ObjectBounds.CalcHierarchyWorldOBB(targetRoot, boundsQConfig)); }