public override OpStatus Revert() { if (space == CoordSpace.SceneCoords) { Frame3f localF = SceneTransforms.SceneToObject(Target, initialFrame); Frame3f setF = Target.GetLocalFrame(CoordSpace.ObjectCoords).FromFrame(localF); Target.RepositionPivot(setF); } else { Target.RepositionPivot(initialFrame); } return(OpStatus.Success); }
public void UpdateBrushStroke(Frame3f vFrameW, int nHitTID) { if (in_stroke == false) { throw new Exception("SurfaceBrushTool.UpdateBrushStroke: not in brush stroke!"); } Frame3f vFrameS = scene.ToSceneFrame(vFrameW); Frame3f vFrameL = SceneTransforms.SceneToObject(Target, vFrameS); update_stroke(vFrameL, nHitTID); lastBrushPosW = vFrameW; }
protected override void update_vertices(FScene s) { //if (Target.Timestamp == target_timestamp) // return; target_timestamp = Target.Timestamp; for (int i = 0; i < VertexCount; ++i) { LocalVertexRef r = SurfacePoints[i]; Vector3d vScene = SceneTransforms.ObjectToScene(Target, r.localPos); this[i] = vScene; } }
public override void AppendVertex(Vector3d v) { base.AppendVertex(v); // map v to local coords LocalVertexRef r = new LocalVertexRef(); r.localPos = SceneTransforms.SceneToObject(Target, v); SurfacePoints.Add(r); if (Curve.VertexCount != SurfacePoints.Count) { throw new Exception("SurfaceCurvePreview: counts are out of sync!!"); } }
public void BeginBrushStroke(Frame3f vFrameW, int nHitTID) { if (in_stroke) { throw new Exception("SurfaceBrushTool.BeginBrushStroke: already in brush stroke!"); } Frame3f vFrameS = scene.ToSceneFrame(vFrameW); Frame3f vFrameL = SceneTransforms.SceneToObject(Target, vFrameS); begin_stroke(vFrameL, nHitTID); in_stroke = true; lastBrushPosW = vFrameW; }
protected override void update_vertices(FScene s) { // [RMS] this was commented out...doesn't work? something? //if (Target.Timestamp == target_timestamp) // return; //target_timestamp = Target.Timestamp; for (int i = 0; i < VertexCount; ++i) { LocalVertexRef r = SurfacePoints[i]; Vector3d vScene = SceneTransforms.ObjectToSceneP(Target, r.localPos); this[i] = vScene; } }
virtual public AxisAlignedBox3f GetLocalBoundingBox() { if (vChildren.Count == 0) { return(new AxisAlignedBox3f(Vector3f.Zero, 0.5f)); } Box3d combine = vChildren[0].GetBoundingBox(CoordSpace.SceneCoords); for (int k = 1; k < vChildren.Count; ++k) { Box3d childbox = vChildren[k].GetBoundingBox(CoordSpace.SceneCoords); combine = Box3d.Merge(ref combine, ref childbox); } Box3f boxLocal = SceneTransforms.SceneToObject(this, (Box3f)combine); return(boxLocal.ToAABB()); }
public void EndStroke() { if (CurrentStroke.Count >= 2) { DMesh3 mesh = Target.Mesh; TransformSequence toScene = SceneTransforms.ObjectToSceneXForm(Target); List <int> tris1 = new List <int>(), tris2 = new List <int>(); Ray3f first = CurrentStroke[0], last = CurrentStroke[CurrentStroke.Count - 1]; Vector3f v0 = PlaneFrameS.RayPlaneIntersection(first.Origin, first.Direction, 2); Vector3f v1 = PlaneFrameS.RayPlaneIntersection(last.Origin, last.Direction, 2); Vector3f planeN = Vector3f.Cross(first.Direction, last.Direction); Frame3f planeF = new Frame3f((v0 + v1) / 2, planeN); foreach (int tid in mesh.TriangleIndices()) { Vector3f c = (Vector3f)mesh.GetTriCentroid(tid); c = toScene.TransformP(c); if (planeF.DistanceToPlaneSigned(c, 2) < 0) { tris1.Add(tid); } else { tris2.Add(tid); } } double area1 = MeshMeasurements.AreaT(mesh, tris1); double area2 = MeshMeasurements.AreaT(mesh, tris2); lastSelection = new MeshFaceSelection(mesh); lastSelection.Select((area1 > area2) ? tris2 : tris1); lastSelection.LocalOptimize(); if (OnStrokeCompletedF != null) { OnStrokeCompletedF(Target, lastSelection); } } CurrentStroke.Clear(); }
virtual public Box3f GetBoundingBox(CoordSpace eSpace) { Box3f box = new Box3f(GetLocalBoundingBox()); if (eSpace == CoordSpace.ObjectCoords) { return(box); } else if (eSpace == CoordSpace.SceneCoords) { return(SceneTransforms.ObjectToScene(this, box)); } else { box = SceneTransforms.ObjectToScene(this, box); return(GetScene().ToWorldBox(box)); } }
public virtual bool FindNearest(Vector3d point, double maxDist, out SORayHit nearest, CoordSpace eInCoords) { nearest = null; if (enable_spatial == false) { return(false); } if (spatial == null) { spatial = new DMeshAABBTree3(mesh); spatial.Build(); } // convert to local Vector3f local_pt = SceneTransforms.TransformTo((Vector3f)point, this, eInCoords, CoordSpace.ObjectCoords); if (mesh.CachedBounds.Distance(local_pt) > maxDist) { return(false); } int tid = spatial.FindNearestTriangle(local_pt); if (tid != DMesh3.InvalidID) { DistPoint3Triangle3 dist = MeshQueries.TriangleDistance(mesh, tid, local_pt); nearest = new SORayHit(); nearest.fHitDist = (float)Math.Sqrt(dist.DistanceSquared); Frame3f f_local = new Frame3f(dist.TriangleClosest, mesh.GetTriNormal(tid)); Frame3f f = SceneTransforms.TransformTo(f_local, this, CoordSpace.ObjectCoords, eInCoords); nearest.hitPos = f.Origin; nearest.hitNormal = f.Z; nearest.hitGO = RootGameObject; nearest.hitSO = this; return(true); } return(false); }
override public bool FindRayIntersection(Ray3f worldRay, out SORayHit hit) { hit = null; // project world ray into local coords FScene scene = GetScene(); Ray3f sceneRay = scene.ToSceneRay(worldRay); Ray3f localRay = SceneTransforms.SceneToObject(this, sceneRay); // also need width in local coords float sceneWidth = scene.ToSceneDimension(visibleWidth); float localWidth = SceneTransforms.SceneToObject(this, sceneWidth) * HitWidthMultiplier; // bounding-box hit test (would be nice to do w/o object allocation...) AxisAlignedBox3d hitBox = localBounds; hitBox.Expand(localWidth); IntrRay3AxisAlignedBox3 box_test = new IntrRay3AxisAlignedBox3(localRay, hitBox); if (box_test.Find() == false) { return(false); } // raycast against curve (todo: spatial data structure for this? like 2D polycurve bbox tree?) double rayHitT; if (CurveUtils.FindClosestRayIntersection(curve, localWidth, localRay, out rayHitT)) { hit = new SORayHit(); // transform local hit point back into world coords Vector3f rayPos = localRay.PointAt((float)rayHitT); Vector3f scenePos = SceneTransforms.ObjectToSceneP(this, rayPos); hit.hitPos = SceneTransforms.SceneToWorldP(scene, scenePos); hit.fHitDist = worldRay.Project(hit.hitPos); hit.hitNormal = Vector3f.Zero; hit.hitGO = root; hit.hitSO = this; return(true); } return(false); }
/// <summary> /// Find intersection of *WORLD* ray with Mesh /// </summary> override public bool FindRayIntersection(Ray3f rayW, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } if (spatial == null) { spatial = new DMeshAABBTree3(mesh); spatial.Build(); } // convert ray to local Frame3f f = new Frame3f(rayW.Origin, rayW.Direction); f = SceneTransforms.TransformTo(f, this, CoordSpace.WorldCoords, CoordSpace.ObjectCoords); Ray3d local_ray = new Ray3d(f.Origin, f.Z); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); Frame3f hitF = new Frame3f(local_ray.PointAt(intr.RayParameter), mesh.GetTriNormal(hit_tid)); hitF = SceneTransforms.TransformTo(hitF, this, CoordSpace.ObjectCoords, CoordSpace.WorldCoords); hit = new SORayHit(); hit.hitPos = hitF.Origin; hit.hitNormal = hitF.Z; hit.hitIndex = hit_tid; hit.fHitDist = hit.hitPos.Distance(rayW.Origin); // simpler than transforming! hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
/// <summary> /// Find intersection of *WORLD* ray with Mesh /// </summary> override public bool FindRayIntersection(Ray3f rayW, out SORayHit hit) { hit = null; if (enable_spatial == false) { return(false); } validate_spatial(); // convert ray to local FScene scene = this.GetScene(); Ray3f rayS = scene.ToSceneRay(rayW); Ray3d local_ray = SceneTransforms.SceneToObject(this, rayS); int hit_tid = spatial.FindNearestHitTriangle(local_ray); if (hit_tid != DMesh3.InvalidID) { IntrRay3Triangle3 intr = MeshQueries.TriangleIntersection(mesh, hit_tid, local_ray); Vector3f hitPos = (Vector3f)local_ray.PointAt(intr.RayParameter); hitPos = SceneTransforms.ObjectToSceneP(this, hitPos); hitPos = scene.ToWorldP(hitPos); Vector3f hitNormal = (Vector3f)mesh.GetTriNormal(hit_tid); hitNormal = SceneTransforms.ObjectToSceneN(this, hitNormal); hitNormal = scene.ToWorldN(hitNormal); hit = new SORayHit(); hit.hitPos = hitPos; hit.hitNormal = hitNormal; hit.hitIndex = hit_tid; hit.fHitDist = hit.hitPos.Distance(rayW.Origin); // simpler than transforming! hit.hitGO = RootGameObject; hit.hitSO = this; return(true); } return(false); }
// extracts MeshFilter object from input GameObject and passes it to a custom constructor // function MakeSOFunc (if null, creates basic MeshSO). Then optionally adds to Scene, // preserving existing 3D position if desired (default true) public static SceneObject ImportExistingUnityMesh(GameObject go, FScene scene, bool bAddToScene = true, bool bKeepWorldPosition = true, bool bRecenterFrame = true, Func <Mesh, SOMaterial, SceneObject> MakeSOFunc = null) { MeshFilter meshF = go.GetComponent <MeshFilter>(); if (meshF == null) { throw new Exception("SceneUtil.ImportExistingUnityMesh: gameObject is not a mesh!!"); } Vector3f scale = go.GetLocalScale(); // [RMS] why don't we bake transform into mesh ??! then we could handle non-uniform scaling... if (SceneTransforms.IsUniformScale(scale) == false) { throw new Exception("UnitySceneUtil.ImportExistingUnityMesh: nonuniform scaling is not supported..."); } Mesh useMesh = meshF.mesh; // makes a copy AxisAlignedBox3f bounds = useMesh.bounds; // bounds.Center is wrt local frame of input go // ie offset from origin in local coordinates // if we want to move frame to center of mesh, we have to re-center it at origin // in local coordinates if (bRecenterFrame) { UnityUtil.TranslateMesh(useMesh, -bounds.Center.x, -bounds.Center.y, -bounds.Center.z); useMesh.RecalculateBounds(); } SceneObject newSO = (MakeSOFunc != null) ? MakeSOFunc(useMesh, scene.DefaultMeshSOMaterial) : new MeshSO().Create(useMesh, scene.DefaultMeshSOMaterial); if (bAddToScene) { scene.AddSceneObject(newSO, false); } if (bKeepWorldPosition) { // compute world rotation/location. If we re-centered the mesh, we need // to offset by the transform we applied above in local coordinates // (hence we have to rotate & scale) if (go.transform.parent != null) { throw new Exception("UnitySceneUtil.ImportExistingUnityMesh: Not handling case where GO has a parent transform"); } Frame3f goFrameW = UnityUtil.GetGameObjectFrame(go, CoordSpace.WorldCoords); Vector3f originW = goFrameW.Origin; if (bRecenterFrame) { originW += goFrameW.Rotation * (scale * bounds.Center); // offset initial frame to be at center of mesh } // convert world frame and offset to scene coordinates Frame3f goFrameS = scene.ToSceneFrame(goFrameW); Vector3f boundsCenterS = scene.ToSceneP(originW); // translate new object to position in scene Frame3f curF = newSO.GetLocalFrame(CoordSpace.SceneCoords); curF.Origin += boundsCenterS; newSO.SetLocalFrame(curF, CoordSpace.SceneCoords); // apply rotation (around current origin) curF = newSO.GetLocalFrame(CoordSpace.SceneCoords); curF.RotateAround(curF.Origin, goFrameS.Rotation); newSO.SetLocalFrame(curF, CoordSpace.SceneCoords); // apply local scale newSO.SetLocalScale(scale); } return(newSO); }
public virtual ExportStatus Export(FScene scene, string filename) { int[] vertexMap = new int[2048]; // temp List <WriteMesh> vMeshes = new List <WriteMesh>(); if (WriteFaceGroups) { throw new Exception("SceneMeshExporter.Export: writing face groups has not yet been implemented!"); } // extract all the mesh data we want to export foreach (SceneObject so in scene.SceneObjects) { if (so.IsTemporary || so.IsSurface == false || SceneUtil.IsVisible(so) == false) { continue; } if (SOFilterF != null && SOFilterF(so) == false) { continue; } // if this SO has an internal mesh we can just copy, use it if (so is DMeshSO) { DMeshSO meshSO = so as DMeshSO; // todo: flags // make a copy of mesh DMesh3 m = new DMesh3(meshSO.Mesh, true); // transform to scene coords and swap left/right foreach (int vid in m.VertexIndices()) { Vector3f v = (Vector3f)m.GetVertex(vid); v = SceneTransforms.ObjectToScene(meshSO, v); v = UnityUtil.SwapLeftRight(v); m.SetVertex(vid, v); } m.ReverseOrientation(); vMeshes.Add(new WriteMesh(m, so.Name)); } // Look for lower-level fGameObject items to export. By default // this is anything with a MeshFilter, override CollectGOChildren // or use GOFilterF to add restrictions List <fGameObject> vExports = CollectGOChildren(so); if (vExports.Count > 0) { SimpleMesh m = new SimpleMesh(); m.Initialize(WriteNormals, WriteVertexColors, WriteUVs, WriteFaceGroups); int groupCounter = 1; foreach (fGameObject childgo in vExports) { if (GOFilterF != null && GOFilterF(so, childgo) == false) { continue; } if (AppendGOMesh(childgo, m, vertexMap, scene, groupCounter)) { groupCounter++; } } vMeshes.Add(new WriteMesh(m, so.Name)); } } // ok, we are independent of Scene now and can write in bg thread if (WriteInBackgroundThreads) { ExportStatus status = new ExportStatus() { Exporter = this, IsComputing = true }; WriteOptions useOptions = Options; useOptions.ProgressFunc = (cur, max) => { status.Progress = cur; status.MaxProgress = max; }; BackgroundWriteThread t = new BackgroundWriteThread() { Meshes = vMeshes, options = useOptions, Filename = filename, CompletionF = (result) => { LastWriteStatus = result.code; LastErrorMessage = result.message; status.LastErrorMessage = result.message; status.Ok = (result.code == IOCode.Ok); status.IsComputing = false; if (BackgroundWriteCompleteF != null) { BackgroundWriteCompleteF(this, status); } } }; t.Start(); return(status); } else { IOWriteResult result = StandardMeshWriter.WriteFile(filename, vMeshes, Options); LastWriteStatus = result.code; LastErrorMessage = result.message; return(new ExportStatus() { Exporter = this, IsComputing = false, Ok = (result.code == IOCode.Ok), LastErrorMessage = result.message }); } }
void update_source() { Frame3f FrameS = Source.GetLocalFrame(CoordSpace.SceneCoords); relativeF = SceneTransforms.SceneToObject(Target, FrameS); }