public bool Initialize(GameObject gameObject) { if (gameObject == null || _gameObject != null) { return(false); } Mesh mesh = gameObject.GetMesh(); Sprite sprite = gameObject.GetSprite(); if (mesh == null && sprite == null) { return(false); } bool useMesh = true; if (mesh == null) { useMesh = false; } RTMesh rtMesh = null; if (useMesh) { Renderer meshRenderer = gameObject.GetMeshRenderer(); if (meshRenderer == null || !meshRenderer.enabled) { useMesh = false; } rtMesh = RTMeshDb.Get.GetRTMesh(mesh); if (rtMesh == null) { useMesh = false; } } if (rtMesh == null && sprite == null) { return(false); } List <AABB> vertOverlapAABBs = BuildVertOverlapAABBs(gameObject, useMesh ? null : sprite, useMesh ? rtMesh : null); if (vertOverlapAABBs.Count == 0) { return(false); } AABB modelAABB = useMesh ? rtMesh.AABB : ObjectBounds.CalcSpriteModelAABB(gameObject); var aabbFaces = BoxMath.AllBoxFaces; _gameObject = gameObject; if (useMesh) { foreach (var aabbFace in aabbFaces) { AABB overlapAABB = vertOverlapAABBs[(int)aabbFace]; List <Vector3> overlappedVerts = rtMesh.OverlapModelVerts(overlapAABB); Plane facePlane = BoxMath.CalcBoxFacePlane(modelAABB.Center, modelAABB.Size, Quaternion.identity, aabbFace); overlappedVerts = facePlane.ProjectAllPoints(overlappedVerts); _snapAreaBounds[(int)aabbFace] = new AABB(overlappedVerts); _snapAreaDesc[(int)aabbFace] = BoxMath.GetBoxFaceAreaDesc(_snapAreaBounds[(int)aabbFace].Size, aabbFace); } } else { foreach (var aabbFace in aabbFaces) { if (aabbFace != BoxFace.Front && aabbFace != BoxFace.Back) { AABB overlapAABB = vertOverlapAABBs[(int)aabbFace]; List <Vector3> overlappedVerts = ObjectVertexCollect.CollectModelSpriteVerts(sprite, overlapAABB); Plane facePlane = BoxMath.CalcBoxFacePlane(modelAABB.Center, modelAABB.Size, Quaternion.identity, aabbFace); overlappedVerts = facePlane.ProjectAllPoints(overlappedVerts); _snapAreaBounds[(int)aabbFace] = new AABB(overlappedVerts); _snapAreaDesc[(int)aabbFace] = BoxMath.GetBoxFaceAreaDesc(_snapAreaBounds[(int)aabbFace].Size, aabbFace); } else { _snapAreaBounds[(int)aabbFace] = AABB.GetInvalid(); _snapAreaDesc[(int)aabbFace] = BoxFaceAreaDesc.GetInvalid(); } } } return(true); }
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)); } 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); OBB hierarchyOBB = ObjectBounds.CalcHierarchyWorldOBB(root, boundsQConfig); if (!hierarchyOBB.IsValid) { return(new SnapResult()); } BoxFace pivotFace = BoxMath.GetMostAlignedFace(hierarchyOBB.Center, hierarchyOBB.Size, hierarchyOBB.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); 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); 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; 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); var 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); var 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); var 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()); }