private void RegisterObject(GameObject gameObject) { var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = EditorScene.Get.NoVolumeObjectSize; AABB worldAABB = ObjectBounds.CalcWorldAABB(gameObject, boundsQConfig); Sphere worldSphere = new Sphere(worldAABB); SphereTreeNode <GameObject> objectNode = _objectTree.AddNode(gameObject, worldSphere); _objectToNode.Add(gameObject, objectNode); var objectTransformData = new ObjectTransformData(); objectTransformData.Sync(gameObject.transform); //_objectToTransformData.Add(gameObject, objectTransformData); }
public static ObjectSnapResult SnapHierarchy(GameObject root, ObjectSnapConfig snapConfig) { const float collectEps = 1e-2f; const float collectBoxScale = 1e-3f; bool hierarchyHasMeshes = root.HierarchyHasMesh(); bool hierarchyHasSprites = root.HierarchyHasSprite(); if (!hierarchyHasMeshes && !hierarchyHasSprites) { return(new ObjectSnapResult()); } var 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; var 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); OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -Vector3.up); var 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); hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); appliedRotation.RotatePoints(collectedVerts, rootTransform.position); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, new Plane(Vector3.up, surfaceHit.HitPoint), 0.1f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); Vector3 embedVector = Surface.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -Vector3.up, snapConfig.SurfaceType); rootTransform.position += (embedVector + alignmentAxis * snapConfig.OffsetFromSurface); return(new ObjectSnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } } } else { if (!isSurfaceSpherical) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -snapConfig.SurfaceHitNormal); var 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; Quaternion appliedRotation = rootTransform.Align(alignmentAxis, snapConfig.AlignmentAxis); hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); appliedRotation.RotatePoints(collectedVerts, rootTransform.position); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); return(new ObjectSnapResult(new Plane(alignmentAxis, surfaceHit.HitPoint), surfaceHit.HitPoint)); } } } 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); OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -radiusDir); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); return(new ObjectSnapResult(sitPlane, sitPoint)); } } } else { OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } if (isSurfaceTerrain || (!isSurfaceSpherical && snapConfig.SurfaceType == Type.Mesh)) { Ray ray = new Ray(hierarchyOOBB.Center, isSurfaceTerrain ? -Vector3.up : -snapConfig.SurfaceHitNormal); GameObjectRayHit surfaceHit = raycaster.Raycast(ray); if (surfaceHit != null) { Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, surfaceHit.HitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; if (isSurfaceTerrain) { BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -surfaceHit.HitNormal); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 embedVector = Surface.CalculateEmbedVector(collectedVerts, snapConfig.SurfaceObject, -surfaceHit.HitNormal, snapConfig.SurfaceType); rootTransform.position += (embedVector + surfaceHit.HitNormal * snapConfig.OffsetFromSurface); } return(new ObjectSnapResult(surfaceHit.HitPlane, surfaceHit.HitPoint)); } } 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(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, -radiusDir); var collectedVerts = ObjectVertexCollect.CollectHierarchyVerts(root, pivotFace, collectBoxScale, collectEps); Vector3 sitPoint = sphereCenter + radiusDir * sphereRadius; Plane sitPlane = new Plane(radiusDir, sitPoint); Vector3 sitOnPlaneOffset = Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, sitPlane, 0.0f); rootTransform.position += sitOnPlaneOffset; hierarchyOOBB.Center += sitOnPlaneOffset; Vector3Ex.OffsetPoints(collectedVerts, sitOnPlaneOffset); return(new ObjectSnapResult(sitPlane, sitPoint)); } } } if (snapConfig.SurfaceType == Type.SceneGrid) { OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new ObjectSnapResult()); } Transform rootTransform = root.transform; if (snapConfig.AlignAxis) { rootTransform.Align(snapConfig.SurfaceHitNormal, snapConfig.AlignmentAxis); hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); } rootTransform.position += Surface.CalculateSitOnSurfaceOffset(hierarchyOOBB, snapConfig.SurfaceHitPlane, snapConfig.OffsetFromSurface); return(new ObjectSnapResult(snapConfig.SurfaceHitPlane, snapConfig.SurfaceHitPlane.ProjectPoint(hierarchyOOBB.Center))); } return(new ObjectSnapResult()); }
public List <GameObjectRayHit> RaycastAll(Ray ray, SceneRaycastPrecision raycastPresicion) { var nodeHits = _objectTree.RaycastAll(ray); if (nodeHits.Count == 0) { return(new List <GameObjectRayHit>()); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectTypeHelper.AllCombined; boundsQConfig.NoVolumeSize = EditorScene.Get.NoVolumeObjectSize; if (raycastPresicion == SceneRaycastPrecision.BestFit) { var hitList = new List <GameObjectRayHit>(10); foreach (var nodeHit in nodeHits) { GameObject sceneObject = nodeHit.HitNode.Data; if (sceneObject == null || !sceneObject.activeInHierarchy) { continue; } Renderer renderer = sceneObject.GetComponent <Renderer>(); if (renderer != null && !renderer.isVisible) { continue; } GameObjectType objectType = sceneObject.GetGameObjectType(); if (objectType == GameObjectType.Mesh) { GameObjectRayHit objectHit = RaycastMeshObject(ray, sceneObject); if (objectHit != null) { hitList.Add(objectHit); } } else if (objectType == GameObjectType.Terrain) { TerrainCollider terrainCollider = sceneObject.GetComponent <TerrainCollider>(); if (terrainCollider != null) { RaycastHit hitInfo; if (terrainCollider.Raycast(ray, out hitInfo, float.MaxValue)) { hitList.Add(new GameObjectRayHit(ray, hitInfo)); } } } else if (objectType == GameObjectType.Sprite) { GameObjectRayHit objectHit = RaycastSpriteObject(ray, sceneObject); if (objectHit != null) { hitList.Add(objectHit); } } else { OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig); if (worldOOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation)) { var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation); var hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hitList.Add(hit); } } } } return(hitList); } else if (raycastPresicion == SceneRaycastPrecision.Box) { var hitList = new List <GameObjectRayHit>(10); foreach (var nodeHit in nodeHits) { GameObject sceneObject = nodeHit.HitNode.Data; if (sceneObject == null || !sceneObject.activeInHierarchy) { continue; } Renderer renderer = sceneObject.GetComponent <Renderer>(); if (renderer != null && !renderer.isVisible) { continue; } OOBB worldOOBB = ObjectBounds.CalcWorldOOBB(sceneObject, boundsQConfig); if (worldOOBB.IsValid) { float t; if (BoxMath.Raycast(ray, out t, worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation)) { var faceDesc = BoxMath.GetFaceClosestToPoint(ray.GetPoint(t), worldOOBB.Center, worldOOBB.Size, worldOOBB.Rotation); var hit = new GameObjectRayHit(ray, sceneObject, faceDesc.Plane.normal, t); hitList.Add(hit); } } } return(hitList); } return(new List <GameObjectRayHit>()); }
public static List <Vector3> CollectHierarchyVerts(GameObject root, BoxFace collectFace, float collectBoxScale, float collectEps) { var meshObjects = root.GetMeshObjectsInHierarchy(); var spriteObjects = root.GetSpriteObjectsInHierarchy(); if (meshObjects.Count == 0 && spriteObjects.Count == 0) { return(new List <Vector3>()); } var boundsQConfig = new ObjectBounds.QueryConfig(); boundsQConfig.ObjectTypes = GameObjectType.Mesh | GameObjectType.Sprite; OOBB hierarchyOOBB = ObjectBounds.CalcHierarchyWorldOOBB(root, boundsQConfig); if (!hierarchyOOBB.IsValid) { return(new List <Vector3>()); } int faceAxisIndex = BoxMath.GetFaceAxisIndex(collectFace); Vector3 faceCenter = BoxMath.CalcBoxFaceCenter(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, collectFace); Vector3 faceNormal = BoxMath.CalcBoxFaceNormal(hierarchyOOBB.Center, hierarchyOOBB.Size, hierarchyOOBB.Rotation, collectFace); float sizeEps = collectEps * 2.0f; Vector3 collectAABBSize = hierarchyOOBB.Size; collectAABBSize[faceAxisIndex] = (hierarchyOOBB.Size[faceAxisIndex] * collectBoxScale) + sizeEps; collectAABBSize[(faceAxisIndex + 1) % 3] += sizeEps; collectAABBSize[(faceAxisIndex + 2) % 3] += sizeEps; OOBB collectOOBB = new OOBB(faceCenter + faceNormal * (-collectAABBSize[faceAxisIndex] * 0.5f + collectEps), collectAABBSize); collectOOBB.Rotation = hierarchyOOBB.Rotation; var collectedVerts = new List <Vector3>(80); foreach (var meshObject in meshObjects) { Mesh mesh = meshObject.GetMesh(); EditorMesh editorMesh = EditorMeshDb.Get.GetEditorMesh(mesh); if (editorMesh == null) { continue; } var verts = editorMesh.OverlapVerts(collectOOBB, meshObject.transform); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } foreach (var spriteObject in spriteObjects) { var verts = CollectWorldSpriteVerts(spriteObject.GetSprite(), spriteObject.transform, collectOOBB); if (verts.Count != 0) { collectedVerts.AddRange(verts); } } return(collectedVerts); }