/// <summary> /// Projects the specified x and y, in normalized window coordinates, onto the grid, /// and snaps it to the nearest grid vertex if necessary. /// Normalized window coordinates are in the range [-0.5,0.5] with +x pointing to the /// right and +y pointing up.</summary> /// <param name="x">Window x in normalized window coords</param> /// <param name="y">Window y in normalized window coords</param> /// <param name="camera">Camera</param> /// <returns>Projection of x and y onto the grid, in world space.</returns> public Vec3F Project(float x, float y, Camera camera) { Ray3F ray = camera.CreateRay(x, y); Matrix4F V = new Matrix4F(camera.ViewMatrix); V.Mul(m_invAxisSystem, V); if (camera.Frustum.IsOrtho) { V = new Matrix4F(m_V); V.Translation = camera.ViewMatrix.Translation; } // origin Vec3F delta = new Vec3F(0, Height, 0); V.Transform(delta, out delta); Vec3F o = delta; // Up vec Vec3F axis = V.YAxis; Vec3F projPt = ray.IntersectPlane(axis, -Vec3F.Dot(o, axis)); // Transform back into world space Matrix4F Inv = new Matrix4F(); Inv.Invert(camera.ViewMatrix); Inv.Transform(projPt, out projPt); if (Snap) { projPt = SnapPoint(projPt); } return projPt; }
private DomNode CreatePrototype(IEnumerable <IGameObject> gobs) { DomNode[] originals = new DomNode[1]; List <IGameObject> copyList = new List <IGameObject>(); AABB bound = new AABB(); foreach (IGameObject gameObject in SelectedGobs) { IBoundable boundable = gameObject.As <IBoundable>(); bound.Extend(boundable.BoundingBox); Matrix4F world = TransformUtils.ComputeWorldTransform(gameObject); originals[0] = gameObject.As <DomNode>(); DomNode[] copies = DomNode.Copy(originals); IGameObject copy = copies[0].As <IGameObject>(); TransformUtils.SetTransform(copy, world); copyList.Add(copy); } DomNode gobchild = null; if (copyList.Count > 1) {// create group IGame game = m_contextRegistry.GetActiveContext <IGame>(); IGameObjectGroup gobgroup = game.CreateGameObjectGroup(); gobgroup.Translation = bound.Center; gobgroup.UpdateTransform(); Matrix4F worldInv = new Matrix4F(); worldInv.Invert(gobgroup.Transform); foreach (IGameObject gob in copyList) { Vec3F translate = gob.Translation; worldInv.Transform(ref translate); gob.Translation = translate; gob.UpdateTransform(); gobgroup.GameObjects.Add(gob); } gobchild = gobgroup.As <DomNode>(); } else { gobchild = copyList[0].As <DomNode>(); } gobchild.InitializeExtensions(); gobchild.As <IGameObject>().Translation = new Vec3F(0, 0, 0); DomNode prototype = null; if (gobchild != null) { prototype = new DomNode(Schema.prototypeType.Type, Schema.prototypeRootElement); prototype.SetChild(Schema.prototypeType.gameObjectChild, gobchild); } return(prototype); }
/// <summary> /// Groups the specified GameObjects</summary> /// <param name="gobs">GameObjects to be grouped</param> /// <remarks>Creates a new GameObjectGroup and moves all /// the GameObjects into it.</remarks> public IGameObjectGroup Group(IEnumerable <IGameObject> gobs) { // extra check. if (!CanGroup(gobs)) { return(null); } IGame game = null; AABB groupBox = new AABB(); List <IGameObject> gameObjects = new List <IGameObject>(); foreach (IGameObject gameObject in gobs) { if (game == null) { game = gameObject.As <DomNode>().GetRoot().As <IGame>(); } gameObjects.Add(gameObject); IBoundable boundable = gameObject.As <IBoundable>(); groupBox.Extend(boundable.BoundingBox); } IGameObjectGroup group = game.CreateGameObjectGroup(); DomNode node = group.As <DomNode>(); node.InitializeExtensions(); ITransformable transformable = node.As <ITransformable>(); transformable.Translation = groupBox.Center; Matrix4F invWorld = new Matrix4F(); invWorld.Invert(transformable.Transform); game.RootGameObjectFolder.GameObjects.Add(group); foreach (IGameObject gameObject in gameObjects) { ITransformable xformable = gameObject.As <ITransformable>(); Matrix4F world = ComputeWorldTransform(xformable); SetTransform(xformable, world); group.GameObjects.Add(gameObject); Vec3F trans = world.Translation; invWorld.Transform(ref trans); xformable.Translation = trans; } return(group); }
public override void OnBeginDrag() { if (m_hitRegion == HitRegion.None || !CanManipulate(m_node)) return; var transactionContext = DesignView.Context.As<ITransactionContext>(); transactionContext.Begin("Move".Localize()); m_originalPivot = m_node.Pivot; Path<DomNode> path = new Path<DomNode>(m_node.Cast<DomNode>().GetPath()); Matrix4F localToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1); m_worldToLocal = new Matrix4F(); m_worldToLocal.Invert(localToWorld); }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_hitRegion == HitRegion.None || m_activeOp == null || m_activeOp.NodeList.Count == 0) { return; } // create ray in view space. Ray3F rayV = vc.GetWorldRay(scrPt); using (var intersectionScene = GameEngine.GetEditorSceneManager().GetIntersectionScene()) { Vec3F intersectionPt; if (!CalculateTerrainIntersection(vc, rayV, intersectionScene, out intersectionPt)) { return; } if (m_pendingStartPt) { m_startPt = intersectionPt; m_pendingStartPt = false; } else { bool clampToSurface = Control.ModifierKeys == Keys.Shift; Vec3F translate = new Vec3F(intersectionPt.X - m_startPt.X, intersectionPt.Y - m_startPt.Y, 0.0f); for (int i = 0; i < m_activeOp.NodeList.Count; i++) { ITransformable node = m_activeOp.NodeList[i]; Path <DomNode> path = new Path <DomNode>(Adapters.Cast <DomNode>(node).GetPath()); Matrix4F parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2); Matrix4F parentWorldToLocal = new Matrix4F(); parentWorldToLocal.Invert(parentLocalToWorld); Vec3F newWorldPos = m_originalTranslations[i] + translate; float terrainHeight = 0.0f; if (GUILayer.EditorInterfaceUtils.GetTerrainHeight( out terrainHeight, intersectionScene, newWorldPos.X, newWorldPos.Y)) { newWorldPos.Z = terrainHeight + (clampToSurface ? 0.0f : m_originalHeights[i]); Vec3F localTranslation; parentWorldToLocal.TransformVector(newWorldPos, out localTranslation); node.Translation = localTranslation; } } } } }
public static void DrawCone(Matrix4F xform, Color color) { Matrix4F transposeOfInverse = new Matrix4F(xform); transposeOfInverse.Transpose(transposeOfInverse); transposeOfInverse.Invert(transposeOfInverse); GameEngine.DrawIndexedPrimitive(PrimitiveType.TriangleList, s_coneVertId, s_coneIndexId, 0, s_coneIndexCount, 0, color, xform, RenderFlag); }
public override void OnBeginDrag() { if (m_hitRegion == HitRegion.None || !CanManipulate(m_node)) { return; } var transactionContext = DesignView.Context.As <ITransactionContext>(); transactionContext.Begin("Move".Localize()); m_originalPivot = m_node.Pivot; Path <DomNode> path = new Path <DomNode>(m_node.Cast <DomNode>().GetPath()); Matrix4F localToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1); m_worldToLocal = new Matrix4F(); m_worldToLocal.Invert(localToWorld); }
/// <summary> /// unproject vector from screen space to object space. /// </summary> public Vec3F Unproject(Vec3F scrPt, Matrix4F wvp) { float width = ClientSize.Width; float height = ClientSize.Height; Matrix4F invWVP = new Matrix4F(); invWVP.Invert(wvp); Vec3F worldPt = new Vec3F(); worldPt.X = scrPt.X / width * 2.0f - 1f; worldPt.Y = -(scrPt.Y / height * 2.0f - 1f); worldPt.Z = scrPt.Z; float w = worldPt.X * invWVP.M14 + worldPt.Y * invWVP.M24 + worldPt.Z * invWVP.M34 + invWVP.M44; invWVP.Transform(ref worldPt); worldPt = worldPt / w; return(worldPt); }
public override bool Pick(ViewControl vc, Point scrPt) { m_hitRegion = HitRegion.None; if (base.Pick(vc, scrPt) == false) { return(false); } Camera camera = vc.Camera; Matrix4F view = camera.ViewMatrix; Matrix4F vp = view * camera.ProjectionMatrix; Matrix4F wvp = HitMatrix * vp; Ray3F rayL = vc.GetRay(scrPt, wvp); float s = Util.CalcAxisScale(vc.Camera, HitMatrix.Translation, AxisLength, vc.Height); // There's only one hot-spot for this manipulator: // a square at the manipulator origin. Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); float centerCubeScale = s * CenterCubeSize; Matrix4F centerCubeXform = new Matrix4F(); centerCubeXform.Scale(centerCubeScale); centerCubeXform.Invert(centerCubeXform); Ray3F ray = rayL; ray.Transform(centerCubeXform); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XYSquare; return(true); } m_hitRegion = HitRegion.None; return(false); }
public IControlPoint InsertPoint(uint index, float x, float y, float z) { IControlPoint cpt = CreateControlPoint(); int numSteps = GetAttribute<int>(Schema.curveType.stepsAttribute); int interpolationType = GetAttribute<int>(Schema.curveType.interpolationTypeAttribute); if (interpolationType != 0 && numSteps > 0) { index = index / (uint)numSteps; } Path<DomNode> path = new Path<DomNode>(DomNode.GetPath()); Matrix4F toworld = TransformUtils.CalcPathTransform(path, path.Count - 1); Matrix4F worldToLocal = new Matrix4F(); worldToLocal.Invert(toworld); Vec3F pos = new Vec3F(x, y, z); worldToLocal.Transform(ref pos); cpt.Translation = pos; ControlPoints.Insert((int)index + 1, cpt); return cpt; }
public override bool Pick(ViewControl vc, Point scrPt) { m_hitRegion = HitRegion.None; if (base.Pick(vc, scrPt) == false) return false; Camera camera = vc.Camera; Matrix4F view = camera.ViewMatrix; Matrix4F vp = view * camera.ProjectionMatrix; Matrix4F wvp = HitMatrix * vp; Ray3F rayL = vc.GetRay(scrPt,wvp); float s = Util.CalcAxisScale(vc.Camera, HitMatrix.Translation, AxisLength, vc.Height); // There's only one hot-spot for this manipulator: // a square at the manipulator origin. Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); float centerCubeScale = s * CenterCubeSize; Matrix4F centerCubeXform = new Matrix4F(); centerCubeXform.Scale(centerCubeScale); centerCubeXform.Invert(centerCubeXform); Ray3F ray = rayL; ray.Transform(centerCubeXform); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XYSquare; return true; } m_hitRegion = HitRegion.None; return false; }
public IControlPoint InsertPoint(uint index, float x, float y, float z) { IControlPoint cpt = CreateControlPoint(); int numSteps = GetAttribute <int>(Schema.curveType.stepsAttribute); int interpolationType = GetAttribute <int>(Schema.curveType.interpolationTypeAttribute); if (interpolationType != 0 && numSteps > 0) { index = index / (uint)numSteps; } Path <DomNode> path = new Path <DomNode>(DomNode.GetPath()); Matrix4F toworld = TransformUtils.CalcPathTransform(path, path.Count - 1); Matrix4F worldToLocal = new Matrix4F(); worldToLocal.Invert(toworld); Vec3F pos = new Vec3F(x, y, z); worldToLocal.Transform(ref pos); cpt.Translation = pos; ControlPoints.Insert((int)index + 1, cpt); return(cpt); }
public override bool Pick(ViewControl vc, Point scrPt) { m_hitRegion = HitRegion.None; if (base.Pick(vc, scrPt) == false) return false; Camera camera = vc.Camera; float s; Util.CalcAxisLengths(camera, HitMatrix.Translation, out s); Matrix4F vp = camera.ViewMatrix * camera.ProjectionMatrix; Matrix4F wvp = HitMatrix * vp; // get ray in object space space. Ray3F rayL = vc.GetRay(scrPt, wvp); m_scale = new Vec3F(1, 1, 1); m_hitScale = s; float rectScale = s*FreeRectRatio; Vec3F topRight = rectScale * (new Vec3F(1, 1, 0)); Vec3F topLeft = rectScale * (new Vec3F(-1, 1, 0)); Vec3F bottomLeft = rectScale * (new Vec3F(-1, -1, 0)); Vec3F bottomRight = rectScale * (new Vec3F(1, -1, 0)); Matrix4F planeXform = Util.CreateBillboard(HitMatrix.Translation, camera.WorldEye, camera.Up, camera.LookAt); Matrix4F wvpPlane = planeXform * vp; // create ray in plane's local space. Ray3F rayP = vc.GetRay(scrPt, wvpPlane); Plane3F plane = new Plane3F(topRight,topLeft,bottomLeft); Vec3F p; bool intersect = rayP.IntersectPlane(plane, out p); if(intersect) { bool inside = p.X > topLeft.X && p.X < topRight.X && p.Y > bottomLeft.Y && p.Y < topLeft.Y; if (inside) { m_hitRegion = HitRegion.FreeRect; return true; } } Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); float handleScale = s * HandleRatio; // X axis boxScale.Scale(new Vec3F(s, handleScale, handleScale)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; Ray3F ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return true; } // y axis boxScale.Scale(new Vec3F(handleScale, s, handleScale)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return true; } // z axis boxScale.Scale(new Vec3F(handleScale, handleScale, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; return true; } return false; }
public override bool Pick(ViewControl vc, Point scrPt) { m_hitRegion = HitRegion.None; if (base.Pick(vc, scrPt) == false) { return(false); } Camera camera = vc.Camera; float s = Util.CalcAxisScale(vc.Camera, HitMatrix.Translation, AxisLength, vc.Height); Matrix4F vp = camera.ViewMatrix * camera.ProjectionMatrix; Matrix4F wvp = HitMatrix * vp; // get ray in object space space. Ray3F rayL = vc.GetRay(scrPt, wvp); m_scale = new Vec3F(1, 1, 1); m_hitScale = s; Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); float centerCubeScale = s * CenterCubeSize; Matrix4F centerCubeXform = new Matrix4F(); centerCubeXform.Scale(centerCubeScale); centerCubeXform.Invert(centerCubeXform); Ray3F ray = rayL; ray.Transform(centerCubeXform); if (box.Intersect(ray)) { m_hitRegion = HitRegion.CenterCube; return(true); } Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); float handleScale = s * AxisHandle; // X axis boxScale.Scale(new Vec3F(s, handleScale, handleScale)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return(true); } // y axis boxScale.Scale(new Vec3F(handleScale, s, handleScale)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return(true); } // z axis boxScale.Scale(new Vec3F(handleScale, handleScale, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; return(true); } return(false); }
public override bool Pick(ViewControl vc, Point scrPt) { m_hitRegion = HitRegion.None; if (base.Pick(vc, scrPt) == false) { return(false); } Camera camera = vc.Camera; float s; Util.CalcAxisLengths(camera, HitMatrix.Translation, out s); Matrix4F vp = camera.ViewMatrix * camera.ProjectionMatrix; Matrix4F wvp = HitMatrix * vp; // get ray in object space space. Ray3F rayL = vc.GetRay(scrPt, wvp); m_scale = new Vec3F(1, 1, 1); m_hitScale = s; float rectScale = s * FreeRectRatio; Vec3F topRight = rectScale * (new Vec3F(1, 1, 0)); Vec3F topLeft = rectScale * (new Vec3F(-1, 1, 0)); Vec3F bottomLeft = rectScale * (new Vec3F(-1, -1, 0)); Vec3F bottomRight = rectScale * (new Vec3F(1, -1, 0)); Matrix4F planeXform = Util.CreateBillboard(HitMatrix.Translation, camera.WorldEye, camera.Up, camera.LookAt); Matrix4F wvpPlane = planeXform * vp; // create ray in plane's local space. Ray3F rayP = vc.GetRay(scrPt, wvpPlane); Plane3F plane = new Plane3F(topRight, topLeft, bottomLeft); Vec3F p; bool intersect = rayP.IntersectPlane(plane, out p); if (intersect) { bool inside = p.X > topLeft.X && p.X <topRight.X && p.Y> bottomLeft.Y && p.Y < topLeft.Y; if (inside) { m_hitRegion = HitRegion.FreeRect; return(true); } } Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); float handleScale = s * HandleRatio; // X axis boxScale.Scale(new Vec3F(s, handleScale, handleScale)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; Ray3F ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return(true); } // y axis boxScale.Scale(new Vec3F(handleScale, s, handleScale)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return(true); } // z axis boxScale.Scale(new Vec3F(handleScale, handleScale, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; return(true); } return(false); }
/// <summary> /// Groups the specified GameObjects</summary> /// <param name="gobs">GameObjects to be grouped</param> /// <remarks>Creates a new GameObjectGroup and moves all /// the GameObjects into it.</remarks> public ITransformableGroup Group(IEnumerable <object> gobs) { // extra check. if (!CanGroup(gobs)) { return(null); } IGameObjectFolder root = null; var gameObjects = new List <ITransformable>(); foreach (var gameObject in gobs) { ITransformable trans = gameObject.As <ITransformable>(); if (trans == null) { continue; } var node = gameObject.As <DomNode>(); if (node == null) { continue; } gameObjects.Add(trans); var root1 = GetObjectFolder(node); if (root != null && root != root1) { return(null); } root = root1; } // sort from shallowest in the tree to deepest. Then remove any nodes that // are already children of other nodes in the list gameObjects.Sort( (lhs, rhs) => { return(lhs.As <DomNode>().Lineage.Count().CompareTo(rhs.As <DomNode>().Lineage.Count())); }); // awkward iteration here... Maybe there's a better way to traverse this list..? for (int c = 0; c < gameObjects.Count;) { var n = gameObjects[c].As <DomNode>(); bool remove = false; for (int c2 = 0; c2 < c; ++c2) { if (n.IsDescendantOf(gameObjects[c2].As <DomNode>())) { remove = true; break; } } if (remove) { gameObjects.RemoveAt(c); } else { ++c; } } // finally, we must have at least 2 valid objects to perform the grouping operation if (gameObjects.Count < 2) { return(null); } AABB groupBox = new AABB(); foreach (var gameObject in gameObjects.AsIEnumerable <IBoundable>()) { groupBox.Extend(gameObject.BoundingBox); } var group = root.CreateGroup(); if (group == null) { return(null); } group.As <DomNode>().InitializeExtensions(); // try to add the group to the parent of the shallowest item var groupParent = gameObjects[0].As <DomNode>().Parent.AsAll <IHierarchical>(); bool addedToGroupParent = false; foreach (var h in groupParent) { if (h.AddChild(group)) { addedToGroupParent = true; break; } } if (!addedToGroupParent) { return(null); } // arrange the transform for the group so that it's origin is in the center of the objects var groupParentTransform = new Matrix4F(); if (groupParent.Is <ITransformable>()) { groupParentTransform = groupParent.As <ITransformable>().LocalToWorld; } Matrix4F invgroupParentTransform = new Matrix4F(); invgroupParentTransform.Invert(groupParentTransform); group.Transform = Matrix4F.Multiply(new Matrix4F(groupBox.Center), invgroupParentTransform); Matrix4F invWorld = new Matrix4F(); invWorld.Invert(group.Transform); // now try to actually add the objects to the group var hier = group.AsAll <IHierarchical>(); foreach (var gameObject in gameObjects) { Matrix4F oldWorld = gameObject.LocalToWorld; bool addedToGroup = false; foreach (var h in hier) { if (h.AddChild(gameObject)) { addedToGroup = true; break; } } if (addedToGroup) { gameObject.Transform = Matrix4F.Multiply(oldWorld, invWorld); } } return(group); }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_cancelDrag || m_hitRegion == HitRegion.None || NodeList.Count == 0) return; bool hitAxis = m_hitRegion == HitRegion.XAxis || m_hitRegion == HitRegion.YAxis || m_hitRegion == HitRegion.ZAxis; Matrix4F view = vc.Camera.ViewMatrix; Matrix4F proj = vc.Camera.ProjectionMatrix; Matrix4F vp = view * proj; // create ray in world space. Ray3F rayW = vc.GetRay(scrPt, vp); // create ray in view space. Ray3F rayV = vc.GetRay(scrPt, proj); Vec3F translate = m_translatorControl.OnDragging(rayV); ISnapSettings snapSettings = (ISnapSettings)DesignView; bool snapToGeom = Control.ModifierKeys == m_snapGeometryKey; if (snapToGeom) { Vec3F manipPos = HitMatrix.Translation; Vec3F manipMove; if (hitAxis) { //Make rayw to point toward moving axis and starting // from manipulator’s world position. rayW.Direction = Vec3F.Normalize(translate); rayW.Origin = manipPos; manipMove = Vec3F.ZeroVector; m_cancelDrag = true; //stop further snap-to's } else { manipMove = rayW.ProjectPoint(manipPos) - manipPos; } for (int i = 0; i < NodeList.Count; i++) { ITransformable node = NodeList[i]; Vec3F snapOffset = TransformUtils.CalcSnapFromOffset(node, snapSettings.SnapFrom); Path<DomNode> path = new Path<DomNode>(Adapters.Cast<DomNode>(node).GetPath()); Matrix4F parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2); Vec3F orgPosW; parentLocalToWorld.Transform(m_originalValues[i], out orgPosW); Matrix4F parentWorldToLocal = new Matrix4F(); parentWorldToLocal.Invert(parentLocalToWorld); rayW.MoveToIncludePoint(orgPosW + snapOffset + manipMove); HitRecord[] hits = GameEngine.RayPick(view, proj, rayW, true); bool cansnap = false; HitRecord target = new HitRecord(); if (hits.Length > 0) { // find hit record. foreach (var hit in hits) { if (m_snapFilter.CanSnapTo(node, GameEngine.GetAdapterFromId(hit.instanceId))) { target = hit; cansnap = true; break; } } } if (cansnap) { Vec3F pos; if (target.hasNearestVert && snapSettings.SnapVertex) { pos = target.nearestVertex; } else { pos = target.hitPt; } pos -= snapOffset; parentWorldToLocal.Transform(ref pos); Vec3F diff = pos - node.Transform.Translation; node.Translation += diff; bool rotateOnSnap = snapSettings.RotateOnSnap && target.hasNormal && (node.TransformationType & TransformationTypes.Rotation) != 0; if (rotateOnSnap) { Vec3F localSurfaceNormal; parentWorldToLocal.TransformNormal(target.normal, out localSurfaceNormal); node.Rotation = TransformUtils.RotateToVector( m_originalRotations[i], localSurfaceNormal, AxisSystemType.YIsUp); } } } } else { IGrid grid = DesignView.Context.Cast<IGame>().Grid; bool snapToGrid = Control.ModifierKeys == m_snapGridKey && grid.Visible && vc.Camera.ViewType == ViewTypes.Perspective; float gridHeight = grid.Height; // translate. for (int i = 0; i < NodeList.Count; i++) { ITransformable node = NodeList[i]; Path<DomNode> path = new Path<DomNode>(Adapters.Cast<DomNode>(node).GetPath()); Matrix4F parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2); Matrix4F parentWorldToLocal = new Matrix4F(); parentWorldToLocal.Invert(parentLocalToWorld); Vec3F localTranslation; parentWorldToLocal.TransformVector(translate, out localTranslation); Vec3F trans = m_originalValues[i] + localTranslation; if(snapToGrid) { if(grid.Snap) trans = grid.SnapPoint(trans); else trans.Y = gridHeight; } node.Translation = trans; } } }
public override bool Pick(ViewControl vc, Point scrPt) { m_hitRegion = HitRegion.None; if (base.Pick(vc, scrPt) == false) return false; Camera camera = vc.Camera; float s = Util.CalcAxisScale(vc.Camera, HitMatrix.Translation, AxisLength, vc.Height); Matrix4F vp = camera.ViewMatrix * camera.ProjectionMatrix; Matrix4F wvp = HitMatrix * vp; // get ray in object space space. Ray3F rayL = vc.GetRay(scrPt, wvp); m_scale = new Vec3F(1, 1, 1); m_hitScale = s; Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); float handleScale = s * AxisHandle; // +X axis boxScale.Scale(new Vec3F(s, handleScale, handleScale)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; Ray3F ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return true; } // -X boxTrans.Translation = new Vec3F(-s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.NegXAxis; return true; } // y axis boxScale.Scale(new Vec3F(handleScale, s, handleScale)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return true; } // -Y boxTrans.Translation = new Vec3F(0, -s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.NegYAxis; return true; } // z axis boxScale.Scale(new Vec3F(handleScale, handleScale, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; return true; } // -Z boxTrans.Translation = new Vec3F(0, 0, -s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.NegZAxis; return true; } return false; }
private DomNode CreatePrototype(IEnumerable<IGameObject> gobs) { DomNode[] originals = new DomNode[1]; List<IGameObject> copyList = new List<IGameObject>(); AABB bound = new AABB(); foreach (IGameObject gameObject in SelectedGobs) { IBoundable boundable = gameObject.As<IBoundable>(); bound.Extend(boundable.BoundingBox); Matrix4F world = TransformUtils.ComputeWorldTransform(gameObject); originals[0] = gameObject.As<DomNode>(); DomNode[] copies = DomNode.Copy(originals); IGameObject copy = copies[0].As<IGameObject>(); TransformUtils.SetTransform(copy, world); copyList.Add(copy); } DomNode gobchild = null; if (copyList.Count > 1) {// create group IGame game = m_contextRegistry.GetActiveContext<IGame>(); IGameObjectGroup gobgroup = game.CreateGameObjectGroup(); gobgroup.Translation = bound.Center; gobgroup.UpdateTransform(); Matrix4F worldInv = new Matrix4F(); worldInv.Invert(gobgroup.Transform); foreach (IGameObject gob in copyList) { Vec3F translate = gob.Translation; worldInv.Transform(ref translate); gob.Translation = translate; gob.UpdateTransform(); gobgroup.GameObjects.Add(gob); } gobchild = gobgroup.As<DomNode>(); } else { gobchild = copyList[0].As<DomNode>(); } gobchild.InitializeExtensions(); gobchild.As<IGameObject>().Translation = new Vec3F(0, 0, 0); DomNode prototype = null; if (gobchild != null) { prototype = new DomNode(Schema.prototypeType.Type, Schema.prototypeRootElement); prototype.SetChild(Schema.prototypeType.gameObjectChild, gobchild); } return prototype; }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_cancelDrag || m_hitRegion == HitRegion.None || NodeList.Count == 0) { return; } bool hitAxis = m_hitRegion == HitRegion.XAxis || m_hitRegion == HitRegion.YAxis || m_hitRegion == HitRegion.ZAxis; Matrix4F view = vc.Camera.ViewMatrix; Matrix4F proj = vc.Camera.ProjectionMatrix; Matrix4F vp = view * proj; // create ray in world space. Ray3F rayW = vc.GetRay(scrPt, vp); // create ray in view space. Ray3F rayV = vc.GetRay(scrPt, proj); Vec3F translate = m_translatorControl.OnDragging(rayV); ISnapSettings snapSettings = (ISnapSettings)DesignView; bool snapToGeom = Control.ModifierKeys == m_snapGeometryKey; if (snapToGeom) { Vec3F manipPos = HitMatrix.Translation; Vec3F manipMove; if (hitAxis) { //Make rayw to point toward moving axis and starting // from manipulator’s world position. rayW.Direction = Vec3F.Normalize(translate); rayW.Origin = manipPos; manipMove = Vec3F.ZeroVector; m_cancelDrag = true; //stop further snap-to's } else { manipMove = rayW.ProjectPoint(manipPos) - manipPos; } for (int i = 0; i < NodeList.Count; i++) { ITransformable node = NodeList[i]; Vec3F snapOffset = TransformUtils.CalcSnapFromOffset(node, snapSettings.SnapFrom); Path <DomNode> path = new Path <DomNode>(Adapters.Cast <DomNode>(node).GetPath()); Matrix4F parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2); Vec3F orgPosW; parentLocalToWorld.Transform(m_originalValues[i], out orgPosW); Matrix4F parentWorldToLocal = new Matrix4F(); parentWorldToLocal.Invert(parentLocalToWorld); rayW.MoveToIncludePoint(orgPosW + snapOffset + manipMove); HitRecord[] hits = GameEngine.RayPick(view, proj, rayW, true); bool cansnap = false; HitRecord target = new HitRecord(); if (hits.Length > 0) { // find hit record. foreach (var hit in hits) { if (m_snapFilter.CanSnapTo(node, GameEngine.GetAdapterFromId(hit.instanceId))) { target = hit; cansnap = true; break; } } } if (cansnap) { Vec3F pos; if (target.hasNearestVert && snapSettings.SnapVertex) { pos = target.nearestVertex; } else { pos = target.hitPt; } pos -= snapOffset; parentWorldToLocal.Transform(ref pos); Vec3F diff = pos - node.Transform.Translation; node.Translation += diff; bool rotateOnSnap = snapSettings.RotateOnSnap && target.hasNormal && (node.TransformationType & TransformationTypes.Rotation) != 0; if (rotateOnSnap) { Vec3F localSurfaceNormal; parentWorldToLocal.TransformNormal(target.normal, out localSurfaceNormal); node.Rotation = TransformUtils.RotateToVector( m_originalRotations[i], localSurfaceNormal, AxisSystemType.YIsUp); } } } } else { IGrid grid = DesignView.Context.Cast <IGame>().Grid; bool snapToGrid = Control.ModifierKeys == m_snapGridKey && grid.Visible && vc.Camera.ViewType == ViewTypes.Perspective; float gridHeight = grid.Height; // translate. for (int i = 0; i < NodeList.Count; i++) { ITransformable node = NodeList[i]; Path <DomNode> path = new Path <DomNode>(Adapters.Cast <DomNode>(node).GetPath()); Matrix4F parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2); Matrix4F parentWorldToLocal = new Matrix4F(); parentWorldToLocal.Invert(parentLocalToWorld); Vec3F localTranslation; parentWorldToLocal.TransformVector(translate, out localTranslation); Vec3F trans = m_originalValues[i] + localTranslation; if (snapToGrid) { if (grid.Snap) { trans = grid.SnapPoint(trans); } else { trans.Y = gridHeight; } } node.Translation = trans; } } }
public HitRegion Pick(Matrix4F world, Matrix4F view, Ray3F rayL, Ray3F rayV, float s) { m_hitRegion = HitRegion.None; m_hitRayV = rayV; m_hitMatrix.Set(world); m_hitWorldView = world * view; float sl = s * SquareLength; // test xy square. Vec3F p1 = new Vec3F(0, 0, 0); Vec3F p2 = new Vec3F(sl, 0, 0); Vec3F p3 = new Vec3F(sl, sl, 0); Vec3F p4 = new Vec3F(0, sl, 0); Plane3F plane = new Plane3F(p1, p2, p3); Vec3F p; if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.X > p1.X && p.X < p2.X && p.Y > p1.Y && p.Y < p4.Y) { m_hitRegion = HitRegion.XYSquare; return m_hitRegion; } } // test xz square p1 = new Vec3F(0, 0, 0); p2 = new Vec3F(sl, 0, 0); p3 = new Vec3F(sl, 0, sl); p4 = new Vec3F(0, 0, sl); plane = new Plane3F(p1, p2, p3); if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.X > p1.X && p.X < p2.X && p.Z > p1.Z && p.Z < p4.Z) { m_hitRegion = HitRegion.XZSquare; return m_hitRegion; } } // test yz square p1 = new Vec3F(0, 0, 0); p2 = new Vec3F(0, 0, sl); p3 = new Vec3F(0, sl, sl); p4 = new Vec3F(0, sl, 0); plane = new Plane3F(p1, p2, p3); if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.Z > p1.Z && p.Z < p2.Z && p.Y > p1.Z && p.Y < p4.Y) { m_hitRegion = HitRegion.YZSquare; return m_hitRegion; } } Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); // X axis boxScale.Scale(new Vec3F(s, s * br, s * br)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; Ray3F ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return m_hitRegion; } // y axis boxScale.Scale(new Vec3F(s * br, s, s * br)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return m_hitRegion; } // z axis boxScale.Scale(new Vec3F(s * br, s * br, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; } return m_hitRegion; }
/// <summary> /// Transforms this frustum by the given matrix</summary> /// <param name="m">Transformation matrix. Can be a nearly-general transform and include non-uniform /// scaling and shearing.</param> public void Transform(Matrix4F m) { Matrix4F transposeOfInverse = new Matrix4F(m); transposeOfInverse.Invert(transposeOfInverse); transposeOfInverse.Transpose(transposeOfInverse); for (int i = 0; i < 6; i++) { m.Transform(m_planes[i], transposeOfInverse, out m_planes[i]); } }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_hitRegion == HitRegion.None || m_activeOp == null || m_activeOp.NodeList.Count == 0) { return; } // create ray in view space. Ray3F rayV = vc.GetWorldRay(scrPt); using (var intersectionScene = GameEngine.GetEditorSceneManager().GetIntersectionScene()) { PickResult intersectionPt; if (!CalculateTerrainIntersection(vc, rayV, intersectionScene, out intersectionPt)) { return; } if (m_pendingStartPt) { m_startPt = intersectionPt._pt.Value; m_pendingStartPt = false; } else { ISnapSettings snapSettings = (ISnapSettings)DesignView; bool clampToSurface = Control.ModifierKeys == Keys.Shift; var pt = intersectionPt._pt.Value; Vec3F translate = new Vec3F(pt.X - m_startPt.X, pt.Y - m_startPt.Y, 0.0f); for (int i = 0; i < m_activeOp.NodeList.Count; i++) { ITransformable node = m_activeOp.NodeList[i]; Path <DomNode> path = new Path <DomNode>(Adapters.Cast <DomNode>(node).GetPath()); Matrix4F parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2); Matrix4F parentWorldToLocal = new Matrix4F(); parentWorldToLocal.Invert(parentLocalToWorld); Vec3F newWorldPos = m_originalTranslations[i] + translate; float terrainHeight = 0.0f; GUILayer.Vector3 terrainNormal; if (GUILayer.EditorInterfaceUtils.GetTerrainHeightAndNormal( out terrainHeight, out terrainNormal, intersectionScene, newWorldPos.X, newWorldPos.Y)) { newWorldPos.Z = terrainHeight + (clampToSurface ? 0.0f : m_originalHeights[i]); Vec3F localTranslation; parentWorldToLocal.TransformVector(newWorldPos, out localTranslation); node.Translation = localTranslation; // There are two ways to orient the "up" vector of the object. // One way is to decompose the 3x3 rotation matrix into a up vector + a rotation around // that vector. Then we retain the rotation, and just move the up vector. // Another way is to take the 3x3 matrix, and adjust it's up vector. Then just perform // the Gram–Schmidt algorithm to re-orthogonalize it. // We'll use the code from the SCEE level editor. This isn't the ideal math (there's a // lot of room for floating point creep) but it should work. var currentUp = node.Transform.ZAxis; if (snapSettings.TerrainAlignment == TerrainAlignmentMode.TerrainUp) { node.Rotation = TransformUtils.RotateToVector( node.Rotation, new Vec3F(terrainNormal.X, terrainNormal.Y, terrainNormal.Z), AxisSystemType.ZIsUp); } else if (snapSettings.TerrainAlignment == TerrainAlignmentMode.WorldUp) { // Prevent the change if the normal is already very close to straight up if (Math.Abs(currentUp.X - 0.0f) > 1e-4f || Math.Abs(currentUp.Y - 0.0f) > 1e-4f || Math.Abs(currentUp.Z - 1.0f) > 1e-4f) { node.Rotation = TransformUtils.RotateToVector( node.Rotation, new Vec3F(0.0f, 0.0f, 1.0f), AxisSystemType.ZIsUp); } } node.UpdateTransform(); } } } } }
public override ManipulatorPickResult Pick(ViewControl vc, Point scrPt) { m_hitRegion = HitRegion.None; if (base.Pick(vc, scrPt) == ManipulatorPickResult.Miss) { return(ManipulatorPickResult.Miss); } Camera camera = vc.Camera; float s = Util.CalcAxisScale(vc.Camera, HitMatrix.Translation, AxisLength, vc.Height); Matrix4F vp = camera.ViewMatrix * camera.ProjectionMatrix; Matrix4F wvp = HitMatrix * vp; // get ray in object space space. Ray3F rayL = vc.GetRay(scrPt, wvp); m_scale = new Vec3F(1, 1, 1); m_hitScale = s; Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); float handleScale = s * AxisHandle; // +X axis boxScale.Scale(new Vec3F(s, handleScale, handleScale)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; Ray3F ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return(ManipulatorPickResult.DeferredBeginDrag); } // -X boxTrans.Translation = new Vec3F(-s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.NegXAxis; return(ManipulatorPickResult.DeferredBeginDrag); } // y axis boxScale.Scale(new Vec3F(handleScale, s, handleScale)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return(ManipulatorPickResult.DeferredBeginDrag); } // -Y boxTrans.Translation = new Vec3F(0, -s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.NegYAxis; return(ManipulatorPickResult.DeferredBeginDrag); } // z axis boxScale.Scale(new Vec3F(handleScale, handleScale, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; return(ManipulatorPickResult.DeferredBeginDrag); } // -Z boxTrans.Translation = new Vec3F(0, 0, -s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.NegZAxis; return(ManipulatorPickResult.DeferredBeginDrag); } return(ManipulatorPickResult.Miss); }
/// <summary> /// unproject vector from screen space to object space. /// </summary> public Vec3F Unproject(Vec3F scrPt, Matrix4F wvp) { float width = ClientSize.Width; float height = ClientSize.Height; Matrix4F invWVP = new Matrix4F(); invWVP.Invert(wvp); Vec3F worldPt = new Vec3F(); worldPt.X = scrPt.X / width * 2.0f - 1f; worldPt.Y = -(scrPt.Y / height * 2.0f - 1f); worldPt.Z = scrPt.Z; float w = worldPt.X * invWVP.M14 + worldPt.Y * invWVP.M24 + worldPt.Z * invWVP.M34 + invWVP.M44; invWVP.Transform(ref worldPt); worldPt = worldPt / w; return worldPt; }
/// <summary> /// Dispatches untyped items. Replaces DispatchNotTyped(). To get the same behavior as /// the old DispatchNotTyped(), set the TypeFilter property to null prior to calling.</summary> /// <param name="traverseList">The traverse list</param> /// <param name="camera">The camera</param> protected void DispatchTraverseList(ICollection<TraverseNode> traverseList, Camera camera) { // Prepare for geometric picking -- create the ray in world space and reset geometric hit-list. // First create the ray in viewing coordinates and transform to world coordinates. float nx = (m_x / (float)m_width) - 0.5f;//normalized x float ny = 0.5f - (m_y / (float)m_height);//normalized y Ray3F rayWorld = camera.CreateRay(nx, ny); Matrix4F worldToView = camera.ViewMatrix; Matrix4F viewToWorld = new Matrix4F(); viewToWorld.Invert(worldToView); rayWorld.Transform(viewToWorld); ClearHitList(); // for geometric picking. will be cleared for each HitRecord. List<uint> userData = new List<uint>(1); // Dispatch traverse list int index = 0; foreach (TraverseNode node in traverseList) { // First test for filtering. IRenderObject renderObject = node.RenderObject; if (FilterByType(renderObject)) { IIntersectable intersectable = renderObject.GetIntersectable(); IGeometricPick geometricPick = intersectable as IGeometricPick; if (geometricPick != null) { // Picking by geometry. Matrix4F objToWorld = new Matrix4F(node.Transform); Matrix4F worldToObj = new Matrix4F(); worldToObj.Invert(objToWorld); Matrix4F viewToObj = Matrix4F.Multiply(viewToWorld, worldToObj); if (m_frustumPick) { //The pick frustum is in view space. Transform to world space then object space. Frustum frustumObj = new Frustum(m_viewFrust0); frustumObj.Transform(viewToObj); //Multi-pick. Get everything in the pick frustum (m_viewFrust0). Vec3F eyeObj; worldToObj.Transform(camera.Eye, out eyeObj); userData.Clear(); if (geometricPick.IntersectFrustum(frustumObj, eyeObj, node.RenderState, userData)) { // Prepare a multi-pick HitRecord, as if OpenGL had calculated this. HitRecord hit = new HitRecord( node.GraphPath, renderObject, objToWorld, userData.ToArray()); m_geoHitList.Add(hit); } } else { //Single pick. We care about distance from camera eye. //Make a copy of the ray in world-space and tranform it to object space. Ray3F rayObj = rayWorld; //remember, Ray3F is a value type, not a reference type. rayObj.Transform(worldToObj); // Do the intersection test in object space. userData.Clear(); Vec3F intersectionPt, surfaceNormal; Vec3F nearestVert; bool intersected; intersected = geometricPick.IntersectRay( rayObj, camera, node.RenderState, objToWorld, this, out intersectionPt, out nearestVert, out surfaceNormal, userData); if (intersected) { // Transform to world space and then to screen space. objToWorld.Transform(intersectionPt, out intersectionPt); objToWorld.Transform(nearestVert, out nearestVert); // Prepare a single-pick HitRecord, as if OpenGL had calculated this. HitRecord hit = new HitRecord( node.GraphPath, renderObject, objToWorld, userData.ToArray()); // This is the one difference from OpenGL pick. We have the world pt already. hit.WorldIntersection = intersectionPt; hit.NearestVert = nearestVert; // Another difference is that it's possible to get the surface normal. if (surfaceNormal != Vec3F.ZeroVector) { objToWorld.TransformNormal(surfaceNormal, out surfaceNormal); surfaceNormal.Normalize(); hit.Normal = surfaceNormal; } m_geoHitList.Add(hit); } } } else { // Picking by "rendering", using OpenGL pick. PushMatrix(node.Transform, false); Gl.glPushName(index); IRenderPick pickInterface = renderObject as IRenderPick; if (pickInterface != null) { pickInterface.PickDispatch(node.GraphPath, node.RenderState, this, camera); } else { renderObject.Dispatch(node.GraphPath, node.RenderState, this, camera); } Gl.glPopName(); PopMatrix(); } } index++; } }
/// <summary> /// Dispatches untyped items. Replaces DispatchNotTyped(). To get the same behavior as /// the old DispatchNotTyped(), set the TypeFilter property to null prior to calling.</summary> /// <param name="traverseList">The traverse list</param> /// <param name="camera">The camera</param> protected void DispatchTraverseList(ICollection <TraverseNode> traverseList, Camera camera) { // Prepare for geometric picking -- create the ray in world space and reset geometric hit-list. // First create the ray in viewing coordinates and transform to world coordinates. float nx = (m_x / (float)m_width) - 0.5f; //normalized x float ny = 0.5f - (m_y / (float)m_height); //normalized y Ray3F rayWorld = camera.CreateRay(nx, ny); Matrix4F worldToView = camera.ViewMatrix; Matrix4F viewToWorld = new Matrix4F(); viewToWorld.Invert(worldToView); rayWorld.Transform(viewToWorld); ClearHitList(); // for geometric picking. will be cleared for each HitRecord. List <uint> userData = new List <uint>(1); // Dispatch traverse list int index = 0; foreach (TraverseNode node in traverseList) { // First test for filtering. IRenderObject renderObject = node.RenderObject; if (FilterByType(renderObject)) { IIntersectable intersectable = renderObject.GetIntersectable(); IGeometricPick geometricPick = intersectable as IGeometricPick; if (geometricPick != null) { // Picking by geometry. Matrix4F objToWorld = new Matrix4F(node.Transform); Matrix4F worldToObj = new Matrix4F(); worldToObj.Invert(objToWorld); Matrix4F viewToObj = Matrix4F.Multiply(viewToWorld, worldToObj); if (m_frustumPick) { //The pick frustum is in view space. Transform to world space then object space. Frustum frustumObj = new Frustum(m_viewFrust0); frustumObj.Transform(viewToObj); //Multi-pick. Get everything in the pick frustum (m_viewFrust0). Vec3F eyeObj; worldToObj.Transform(camera.Eye, out eyeObj); userData.Clear(); if (geometricPick.IntersectFrustum(frustumObj, eyeObj, node.RenderState, userData)) { // Prepare a multi-pick HitRecord, as if OpenGL had calculated this. HitRecord hit = new HitRecord( node.GraphPath, renderObject, objToWorld, userData.ToArray()); m_geoHitList.Add(hit); } } else { //Single pick. We care about distance from camera eye. //Make a copy of the ray in world-space and tranform it to object space. Ray3F rayObj = rayWorld; //remember, Ray3F is a value type, not a reference type. rayObj.Transform(worldToObj); // Do the intersection test in object space. userData.Clear(); Vec3F intersectionPt, surfaceNormal; Vec3F nearestVert; bool intersected; intersected = geometricPick.IntersectRay( rayObj, camera, node.RenderState, objToWorld, this, out intersectionPt, out nearestVert, out surfaceNormal, userData); if (intersected) { // Transform to world space and then to screen space. objToWorld.Transform(intersectionPt, out intersectionPt); objToWorld.Transform(nearestVert, out nearestVert); // Prepare a single-pick HitRecord, as if OpenGL had calculated this. HitRecord hit = new HitRecord( node.GraphPath, renderObject, objToWorld, userData.ToArray()); // This is the one difference from OpenGL pick. We have the world pt already. hit.WorldIntersection = intersectionPt; hit.NearestVert = nearestVert; // Another difference is that it's possible to get the surface normal. if (surfaceNormal != Vec3F.ZeroVector) { objToWorld.TransformNormal(surfaceNormal, out surfaceNormal); surfaceNormal.Normalize(); hit.Normal = surfaceNormal; } m_geoHitList.Add(hit); } } } else { // Picking by "rendering", using OpenGL pick. PushMatrix(node.Transform, false); Gl.glPushName(index); IRenderPick pickInterface = renderObject as IRenderPick; if (pickInterface != null) { pickInterface.PickDispatch(node.GraphPath, node.RenderState, this, camera); } else { renderObject.Dispatch(node.GraphPath, node.RenderState, this, camera); } Gl.glPopName(); PopMatrix(); } } index++; } }
/// <summary> /// Groups the specified GameObjects</summary> /// <param name="gobs">GameObjects to be grouped</param> /// <remarks>Creates a new GameObjectGroup and moves all /// the GameObjects into it.</remarks> public IGameObjectGroup Group(IEnumerable<IGameObject> gobs) { // extra check. if (!CanGroup(gobs)) return null; IGame game = null; AABB groupBox = new AABB(); List<IGameObject> gameObjects = new List<IGameObject>(); foreach (IGameObject gameObject in gobs) { if (game == null) { game = gameObject.As<DomNode>().GetRoot().As<IGame>(); } gameObjects.Add(gameObject); IBoundable boundable = gameObject.As<IBoundable>(); groupBox.Extend(boundable.BoundingBox); } IGameObjectGroup group = game.CreateGameObjectGroup(); DomNode node = group.As<DomNode>(); node.InitializeExtensions(); ITransformable transformable = node.As<ITransformable>(); transformable.Translation = groupBox.Center; Matrix4F invWorld = new Matrix4F(); invWorld.Invert(transformable.Transform); game.RootGameObjectFolder.GameObjects.Add(group); foreach (IGameObject gameObject in gameObjects) { ITransformable xformable = gameObject.As<ITransformable>(); Matrix4F world = ComputeWorldTransform(xformable); SetTransform(xformable, world); group.GameObjects.Add(gameObject); Vec3F trans = world.Translation; invWorld.Transform(ref trans); xformable.Translation = trans; } return group; }
/// <summary> /// Adjusts child transform, making it relative to new parent node's transform. /// Is recursive, looking for parents that also implement IRenderableNode.</summary> /// <param name="parent">Parent node</param> /// <param name="child">Child node</param> public static void AddChild(ITransformable parent, ITransformable child) { Path<DomNode> path = new Path<DomNode>(parent.Cast<DomNode>().GetPath()); Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1); // We want 'child' to appear in the same place in the world after adding to 'parent'. // local-point * original-local-to-world = world-point // new-local-point * new-local-to-parent * parent-to-world = world-point // ==> new-local-to-parent * parent-to-world = original-local-to-world // (multiply both sides by inverse of parent-to-world; call it world-to-parent) // ==> new-local-to-parent = original-local-to-world * world-to-parent Matrix4F worldToParent = new Matrix4F(); worldToParent.Invert(parentToWorld); Matrix4F originalLocalToWorld = child.Transform; Matrix4F newLocalToParent = Matrix4F.Multiply(originalLocalToWorld, worldToParent); // The translation component of newLocalToParent consists of pivot translation // as well as the child.Translation. So, start with the original child.Translation // and transform it into our new space. Vec3F newTranslation = child.Translation; worldToParent.Transform(ref newTranslation); // There's only one way of getting rotation info, so get it straight from matrix. Vec3F newRotation = new Vec3F(); newLocalToParent.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z); child.Rotation = newRotation; // Likewise with scale. Vec3F newScale = newLocalToParent.GetScale(); child.Scale = newScale; // We can compose together all of the separate transformations now. Matrix4F newTransform = CalcTransform( newTranslation, newRotation, newScale, child.ScalePivot, child.ScalePivotTranslation, child.RotatePivot, child.RotatePivotTranslation); // However, the composed matrix may not equal newLocalToParent due to rotating // or scaling around a pivot. In the general case, it may be impossible to // decompose newLocalToParent into all of these separate components. For example, // a sheer transformation cannot be reproduced by a single rotation and scale. // But for common cases, only the translation is out-of-sync now, so apply a fix. Vec3F desiredTranslation = newLocalToParent.Translation; Vec3F currentTranslation = newTransform.Translation; Vec3F fixupTranslation = desiredTranslation - currentTranslation; Matrix4F fixupTransform = new Matrix4F(fixupTranslation); newTransform.Mul(newTransform, fixupTransform); // Save the fix and the final transform. Storing the fix in RotatePivotTranslation // is done elsewhere, as well. child.Translation = newTranslation + fixupTranslation; child.Transform = newTransform; }
public HitRegion Pick(ViewControl vc, Matrix4F world, Matrix4F view, Ray3F rayL, Ray3F rayV) { float s = Util.CalcAxisScale(vc.Camera, world.Translation, Manipulator.AxisLength, vc.Height); m_hitRegion = HitRegion.None; m_hitRayV = rayV; m_hitMatrix.Set(world); m_hitWorldView = world * view; float sl = s * SquareLength; // test xy square. Vec3F p1 = new Vec3F(0, 0, 0); Vec3F p2 = new Vec3F(sl, 0, 0); Vec3F p3 = new Vec3F(sl, sl, 0); Vec3F p4 = new Vec3F(0, sl, 0); Plane3F plane = new Plane3F(p1, p2, p3); Vec3F p; if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.X > p1.X && p.X < p2.X && p.Y > p1.Y && p.Y < p4.Y) { m_hitRegion = HitRegion.XYSquare; return(m_hitRegion); } } // test xz square p1 = new Vec3F(0, 0, 0); p2 = new Vec3F(sl, 0, 0); p3 = new Vec3F(sl, 0, sl); p4 = new Vec3F(0, 0, sl); plane = new Plane3F(p1, p2, p3); if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.X > p1.X && p.X < p2.X && p.Z > p1.Z && p.Z < p4.Z) { m_hitRegion = HitRegion.XZSquare; return(m_hitRegion); } } // test yz square p1 = new Vec3F(0, 0, 0); p2 = new Vec3F(0, 0, sl); p3 = new Vec3F(0, sl, sl); p4 = new Vec3F(0, sl, 0); plane = new Plane3F(p1, p2, p3); if (rayL.IntersectPlane(plane, out p)) { // test point in 2d rectangle. if (p.Z > p1.Z && p.Z < p2.Z && p.Y > p1.Z && p.Y < p4.Y) { m_hitRegion = HitRegion.YZSquare; return(m_hitRegion); } } Vec3F min = new Vec3F(-0.5f, -0.5f, -0.5f); Vec3F max = new Vec3F(0.5f, 0.5f, 0.5f); AABB box = new AABB(min, max); Matrix4F boxScale = new Matrix4F(); Matrix4F boxTrans = new Matrix4F(); Matrix4F BoxMtrx = new Matrix4F(); // X axis boxScale.Scale(new Vec3F(s, s * ConeDiameter, s * ConeDiameter)); boxTrans.Translation = new Vec3F(s / 2, 0, 0); BoxMtrx = boxScale * boxTrans; Ray3F ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.XAxis; return(m_hitRegion); } // y axis boxScale.Scale(new Vec3F(s * ConeDiameter, s, s * ConeDiameter)); boxTrans.Translation = new Vec3F(0, s / 2, 0); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.YAxis; return(m_hitRegion); } // z axis boxScale.Scale(new Vec3F(s * ConeDiameter, s * ConeDiameter, s)); boxTrans.Translation = new Vec3F(0, 0, s / 2); BoxMtrx = boxScale * boxTrans; ray = rayL; BoxMtrx.Invert(BoxMtrx); ray.Transform(BoxMtrx); if (box.Intersect(ray)) { m_hitRegion = HitRegion.ZAxis; } return(m_hitRegion); }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_hitRegion == HitRegion.None || m_activeOp == null || m_activeOp.NodeList.Count == 0) return; // create ray in view space. Ray3F rayV = vc.GetWorldRay(scrPt); using (var intersectionScene = GameEngine.GetEditorSceneManager().GetIntersectionScene()) { Vec3F intersectionPt; if (!CalculateTerrainIntersection(vc, rayV, intersectionScene, out intersectionPt)) return; if (m_pendingStartPt) { m_startPt = intersectionPt; m_pendingStartPt = false; } else { bool clampToSurface = Control.ModifierKeys == Keys.Shift; Vec3F translate = new Vec3F(intersectionPt.X - m_startPt.X, intersectionPt.Y - m_startPt.Y, 0.0f); for (int i = 0; i < m_activeOp.NodeList.Count; i++) { ITransformable node = m_activeOp.NodeList[i]; Path<DomNode> path = new Path<DomNode>(Adapters.Cast<DomNode>(node).GetPath()); Matrix4F parentLocalToWorld = TransformUtils.CalcPathTransform(path, path.Count - 2); Matrix4F parentWorldToLocal = new Matrix4F(); parentWorldToLocal.Invert(parentLocalToWorld); Vec3F newWorldPos = m_originalTranslations[i] + translate; float terrainHeight = 0.0f; if (GUILayer.EditorInterfaceUtils.GetTerrainHeight( out terrainHeight, intersectionScene, newWorldPos.X, newWorldPos.Y)) { newWorldPos.Z = terrainHeight + (clampToSurface ? 0.0f : m_originalHeights[i]); Vec3F localTranslation; parentWorldToLocal.TransformVector(newWorldPos, out localTranslation); node.Translation = localTranslation; } } } } }
/// <summary> /// Adjusts child transform, making it relative to new parent node's transform. /// Is recursive, looking for parents that also implement IRenderableNode.</summary> /// <param name="parent">Parent node</param> /// <param name="child">Child node</param> public static void AddChild(ITransformable parent, ITransformable child) { Path <DomNode> path = new Path <DomNode>(parent.Cast <DomNode>().GetPath()); Matrix4F parentToWorld = TransformUtils.CalcPathTransform(path, path.Count - 1); // We want 'child' to appear in the same place in the world after adding to 'parent'. // local-point * original-local-to-world = world-point // new-local-point * new-local-to-parent * parent-to-world = world-point // ==> new-local-to-parent * parent-to-world = original-local-to-world // (multiply both sides by inverse of parent-to-world; call it world-to-parent) // ==> new-local-to-parent = original-local-to-world * world-to-parent Matrix4F worldToParent = new Matrix4F(); worldToParent.Invert(parentToWorld); Matrix4F originalLocalToWorld = child.Transform; Matrix4F newLocalToParent = Matrix4F.Multiply(originalLocalToWorld, worldToParent); // The translation component of newLocalToParent consists of pivot translation // as well as the child.Translation. So, start with the original child.Translation // and transform it into our new space. Vec3F newTranslation = child.Translation; worldToParent.Transform(ref newTranslation); // There's only one way of getting rotation info, so get it straight from matrix. Vec3F newRotation = new Vec3F(); newLocalToParent.GetEulerAngles(out newRotation.X, out newRotation.Y, out newRotation.Z); child.Rotation = newRotation; // Likewise with scale. Vec3F newScale = newLocalToParent.GetScale(); child.Scale = newScale; // We can compose together all of the separate transformations now. Matrix4F newTransform = CalcTransform( newTranslation, newRotation, newScale, child.ScalePivot, child.ScalePivotTranslation, child.RotatePivot, child.RotatePivotTranslation); // However, the composed matrix may not equal newLocalToParent due to rotating // or scaling around a pivot. In the general case, it may be impossible to // decompose newLocalToParent into all of these separate components. For example, // a sheer transformation cannot be reproduced by a single rotation and scale. // But for common cases, only the translation is out-of-sync now, so apply a fix. Vec3F desiredTranslation = newLocalToParent.Translation; Vec3F currentTranslation = newTransform.Translation; Vec3F fixupTranslation = desiredTranslation - currentTranslation; Matrix4F fixupTransform = new Matrix4F(fixupTranslation); newTransform.Mul(newTransform, fixupTransform); // Save the fix and the final transform. Storing the fix in RotatePivotTranslation // is done elsewhere, as well. child.Translation = newTranslation + fixupTranslation; child.Transform = newTransform; }