void UpdateSelection() { //0.1 ms float fTimeSlice = 1.0f / (10000.0f); int iTimeSliceInTicks = (int)(fTimeSlice * System.Diagnostics.Stopwatch.Frequency); Transform rCanvas = App.ActiveCanvas.transform; int iNumCanvasChildren = rCanvas.childCount; //reset selection if we've moved or adjusted our size float fSelectionRadius = GetSize(); Vector3 vSelectionCenter = transform.position; Vector3 vSelectionCenterMovement = vSelectionCenter - m_SelectionPositionPrev; float fSelectionRadiusDiff = m_SelectionRadiusPrev - fSelectionRadius; if (vSelectionCenterMovement.sqrMagnitude > 0.0001f || Mathf.Abs(fSelectionRadiusDiff) > 0.001f) { ResetSelection(); m_SelectionPositionPrev = vSelectionCenter; m_SelectionRadiusPrev = fSelectionRadius; } m_SelectionInfoQueryWasComplete = m_SelectionInfoQueryComplete; float fObjectProgressPercent = 0.0f; //DebugDrawBounds(); //early out if there's nothing to look at if (iNumCanvasChildren > 0 && m_SelectionObjectIndex < iNumCanvasChildren) { m_SelectionStopwatch.Reset(); m_SelectionStopwatch.Start(); bool bDone = false; bool bComplexModel = false; //spin until we've taken up too much time while (!bDone) { //check child bounds Transform rChild = rCanvas.GetChild(m_SelectionObjectIndex); if (rChild.gameObject.activeSelf) { bComplexModel = false; MeshFilter rMeshFilter = rChild.GetComponent <MeshFilter>(); if (rMeshFilter == null) { //look for a complex model ObjModelScript rModelScript = rChild.GetComponent <ObjModelScript>(); if (rModelScript) { if (m_SelectionObjectChildIndex < rModelScript.m_MeshChildren.Length) { rMeshFilter = rModelScript.m_MeshChildren[m_SelectionObjectChildIndex]; bComplexModel = true; } } } if (rMeshFilter) { Bounds rMeshBounds = rMeshFilter.mesh.bounds; rMeshBounds.Expand(fSelectionRadius); Vector3 vTransformedCenter = rChild.InverseTransformPoint(vSelectionCenter); if (rMeshBounds.Contains(vTransformedCenter)) { //bounds valid, check vert intersection with sphere int iMeshVertCount = rMeshFilter.mesh.vertexCount; Vector3[] aVerts = rMeshFilter.mesh.vertices; Vector3[] aNorms = rMeshFilter.mesh.normals; while (m_SelectionVertIndex < iMeshVertCount - 2) { //check to see if we're within the sphere radius to the plane of this triangle Vector3 vVert = aVerts[m_SelectionVertIndex]; Vector3 vNorm = aNorms[m_SelectionVertIndex]; float fDistToPlane = SignedDistancePlanePoint(ref vNorm, ref vVert, ref vTransformedCenter); if (Mathf.Abs(fDistToPlane) < fSelectionRadius) { //we're within the radius to this triangle's plane, find the projected point fDistToPlane *= -1.0f; Vector3 vPlaneOffsetVector = vNorm * fDistToPlane; Vector3 vPlaneIntersection = vTransformedCenter + vPlaneOffsetVector; Vector3 vVert2 = aVerts[m_SelectionVertIndex + 1]; Vector3 vVert3 = aVerts[m_SelectionVertIndex + 2]; //walk the projected point toward the triangle center Vector3 vTriCenter = (vVert + vVert2 + vVert3) * 0.33333f; Vector3 vToTriCenter = vTriCenter - vPlaneIntersection; float fWalkDistance = Mathf.Min(vToTriCenter.magnitude, fSelectionRadius); vToTriCenter.Normalize(); vToTriCenter *= fWalkDistance; vPlaneIntersection += vToTriCenter; //see if this projected point is in the triangle if (PointInTriangle(ref vPlaneIntersection, ref vVert, ref vVert2, ref vVert3)) { //selected! SelectionObject rNewSelectedObject = new SelectionObject(); rNewSelectedObject.m_Object = rChild.gameObject; rNewSelectedObject.m_ComplexObject = bComplexModel; m_CurrentSelection.Add(rNewSelectedObject); //this will guarantee we'll move on from this model, complex or not bComplexModel = false; break; } } //after each triangle, check our time m_SelectionVertIndex += 3; bDone = m_SelectionStopwatch.ElapsedTicks > iTimeSliceInTicks; if (bDone) { fObjectProgressPercent = (float)m_SelectionVertIndex / (float)iMeshVertCount; break; } } } } } //if we're not flagged as done, we just finished this object, so move on to the next if (!bDone) { //if we're looking at a complex model, look at the next piece of the model if (bComplexModel) { ++m_SelectionObjectChildIndex; } else { //move to the next object ++m_SelectionObjectIndex; m_SelectionObjectChildIndex = 0; } m_SelectionVertIndex = 0; if (m_SelectionObjectIndex >= iNumCanvasChildren) { //if we reached the end of the line, we're done break; } //might as well check per object bDone = m_SelectionStopwatch.ElapsedTicks > iTimeSliceInTicks; } } m_SelectionStopwatch.Stop(); } //set progress float fProgressInterval = 1.0f; if (iNumCanvasChildren > 0) { fProgressInterval /= (float)iNumCanvasChildren; } float fCanvasProgress = fProgressInterval * (float)m_SelectionObjectIndex; float fBrushProgress = fObjectProgressPercent * fProgressInterval; SetToolProgress(fCanvasProgress + fBrushProgress + 0.001f); }
void LoadModel() { // Clean up existing model if (m_ModelInstance != null) { GameObject.Destroy(m_ModelInstance.gameObject); } // Early out if we don't have a model to clone. // This can happen if model loading is deferred. if (m_Model == null || m_Model.m_ModelParent == null) { return; } m_ModelInstance = Instantiate(m_Model.m_ModelParent); m_ModelInstance.gameObject.SetActive(true); m_ModelInstance.parent = this.transform; Coords.AsLocal[m_ModelInstance] = TrTransform.identity; float maxExtent = 2 * Mathf.Max(m_Model.m_MeshBounds.extents.x, Mathf.Max(m_Model.m_MeshBounds.extents.y, m_Model.m_MeshBounds.extents.z)); float size; if (maxExtent == 0.0f) { // If we created a widget with a model that doesn't have geo, we won't have calculated a // bounds worth much. In that case, give us a default size. size = 1.0f; } else { size = kInitialSizeMeters_RS * App.METERS_TO_UNITS / maxExtent; } m_InitSize_CS = size / Coords.CanvasPose.scale; // Models are created in the main canvas. Cache model layer in case it's overridden later. HierarchyUtils.RecursivelySetLayer(transform, App.Scene.MainCanvas.gameObject.layer); m_BackupLayer = m_ModelInstance.gameObject.layer; // Set a new batchId on this model so it can be picked up in GPU intersections. m_BatchId = GpuIntersector.GetNextBatchId(); HierarchyUtils.RecursivelySetMaterialBatchID(m_ModelInstance, m_BatchId); WidgetManager.m_Instance.AddWidgetToBatchMap(this, m_BatchId); Vector3 ratios = GetBoundsRatios(m_Model.m_MeshBounds); m_ContainerBloat.x = Mathf.Max(0, m_MinContainerRatio - ratios.x); m_ContainerBloat.y = Mathf.Max(0, m_MinContainerRatio - ratios.y); m_ContainerBloat.z = Mathf.Max(0, m_MinContainerRatio - ratios.z); m_ContainerBloat /= m_MinContainerRatio; // Normalize for the min ratio. m_ContainerBloat *= m_MaxBloat / App.Scene.Pose.scale; // Apply bloat to appropriate axes. m_BoxCollider.size = m_Model.m_MeshBounds.size + m_ContainerBloat; m_BoxCollider.transform.localPosition = m_Model.m_MeshBounds.center; InitSnapGhost(m_Model.m_ModelParent, m_ModelInstance); // Remove previous model vertex recording. WidgetManager.m_Instance.AdjustModelVertCount(-m_NumVertsTrackedByWidgetManager); m_NumVertsTrackedByWidgetManager = 0; m_ObjModelScript = GetComponentInChildren <ObjModelScript>(); m_ObjModelScript.Init(); if (m_ObjModelScript.NumMeshes == 0) { OutputWindowScript.Error("No usable geometry in model"); } else { m_NumVertsTrackedByWidgetManager = m_ObjModelScript.GetNumVertsInMeshes(); WidgetManager.m_Instance.AdjustModelVertCount(m_NumVertsTrackedByWidgetManager); } if (m_Model.IsCached()) { m_Model.RefreshCache(); } }