/// <summary> /// Handles key-down events</summary> /// <param name="sender">Control that raised original event</param> /// <param name="e">Event args</param> /// <returns>true, if controller handled the event</returns> public override bool KeyDown(object sender, KeyEventArgs e) { m_keyMap[e.KeyValue] = true; ControlScheme controlSchm = InputScheme.ActiveControlScheme; // W A S D for forward, strafe left, backward, strafe right, is the default Vec3F dir = new Vec3F(); if (m_keyMap[(int)controlSchm.Left1] || m_keyMap[(int)controlSchm.Left2]) dir = dir - Camera.Right; if (m_keyMap[(int)controlSchm.Right1] || m_keyMap[(int)controlSchm.Right2]) dir = dir + Camera.Right; if (m_keyMap[(int)controlSchm.Forward1] || m_keyMap[(int)controlSchm.Forward2]) dir = dir + Camera.LookAt; if (m_keyMap[(int)controlSchm.Back1] || m_keyMap[(int)controlSchm.Back2]) dir = dir - Camera.LookAt; bool handled = controlSchm.IsControllingCamera(Control.ModifierKeys, e); if (handled) { dir.Normalize(); Camera.Set(Camera.Eye + dir * m_scale); } return handled; }
private Vec3F ProjectToArcball(Point point) { float x = (float)point.X / (m_width / 2); // Scale so bounds map to [0,0] - [2,2] float y = (float)point.Y / (m_height / 2); x = x - 1; // Translate 0,0 to the center y = 1 - y; // Flip so +Y is up if (x < -1) { x = -1; } else if (x > 1) { x = 1; } if (y < -1) { y = -1; } else if (y > 1) { y = 1; } float z2 = 1 - x * x - y * y; // z^2 = 1 - x^2 - y^2 float z = z2 > 0 ? (float)Math.Sqrt(z2) : 0; Vec3F p = new Vec3F(x, y, z); p.Normalize(); return(p); }
/// <summary> /// Gets the view matrix corresponding to a "look at" point</summary> /// <param name="azimuth">Camera pan, in radians</param> /// <param name="elevation">Camera tilt, in radians</param> /// <param name="lookAt">"Look at" direction</param> /// <returns>View matrix corresponding to the "look at" point</returns> public static Matrix4F LookAtRotationMatrix(float azimuth, float elevation, Vec3F lookAt) { double sy = Math.Sin(azimuth); double cy = Math.Cos(azimuth); double sx = Math.Sin(elevation); double cx = Math.Cos(elevation); // Calc eye vector as the rotation matrix * (0,0,1) Vec3F eye = new Vec3F((float)sy, (float)(-cy * sx), (float)(cy * cx)); eye = eye + lookAt; // Calc up vector as the rotation matrix * (0,1,0) Vec3F up = new Vec3F(0, (float)cx, (float)sx); Vec3F fvec = lookAt - eye; Vec3F f = Vec3F.Normalize(fvec); Vec3F s = Vec3F.Cross(f, up); Vec3F u = Vec3F.Cross(s, f); return(new Matrix4F ( s.X, s.Y, s.Z, 0, u.X, u.Y, u.Z, 0, -f.X, -f.Y, -f.Z, 0, 0, 0, 0, 1 )); }
private void TestToStringWithCulture(CultureInfo culture) { CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = culture; try { string listSeparator = culture.TextInfo.ListSeparator; string decimalSeparator = culture.NumberFormat.NumberDecimalSeparator; var normal = new Vec3F(1.1f, 2.2f, 3.3f); normal.Normalize(); var o = new Plane3F(normal, 4.4f); string s = o.ToString(null, null); TestToStringResults(o, s, listSeparator, decimalSeparator); string s2 = o.ToString(); Assert.AreEqual(s, s2); s = o.ToString("G", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); s = o.ToString("R", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; } }
/// <summary> /// Handles key-down events</summary> /// <param name="sender">Control that raised original event</param> /// <param name="e">Event args</param> /// <returns>True if controller handled the event</returns> public override bool KeyDown(object sender, KeyEventArgs e) { m_keyMap[e.KeyValue] = true; // W A S D for forward, strafe left, backward, strafe right, is the default Vec3F dir = new Vec3F(); if (m_keyMap[(int)CanvasControl3D.ControlScheme.Left1] || m_keyMap[(int)CanvasControl3D.ControlScheme.Left2]) dir = dir - Camera.Right; if (m_keyMap[(int)CanvasControl3D.ControlScheme.Right1] || m_keyMap[(int)CanvasControl3D.ControlScheme.Right2]) dir = dir + Camera.Right; if (m_keyMap[(int)CanvasControl3D.ControlScheme.Forward1] || m_keyMap[(int)CanvasControl3D.ControlScheme.Forward2]) dir = dir + Camera.LookAt; if (m_keyMap[(int)CanvasControl3D.ControlScheme.Back1] || m_keyMap[(int)CanvasControl3D.ControlScheme.Back2]) dir = dir - Camera.LookAt; bool handled = CanvasControl3D.ControlScheme.IsControllingCamera(Control.ModifierKeys, e); if (handled) { dir.Normalize(); Vec3F p = Camera.Eye; float y = p.Y; p += dir * m_scale; p.Y = y; Camera.Set(p); } return handled; }
private void TestToStringWithCulture(CultureInfo culture) { CultureInfo originalCulture = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = culture; try { string listSeparator = culture.TextInfo.ListSeparator; string decimalSeparator = culture.NumberFormat.NumberDecimalSeparator; var normal = new Vec3F(1.1f, 2.2f, 3.3f); normal.Normalize(); var o = new Plane3F(normal, 4.4f); string s = o.ToString(null, null); TestToStringResults(o, s, listSeparator, decimalSeparator); string s2 = o.ToString(); Assert.AreEqual(s, s2); s = o.ToString("G", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); s = o.ToString("R", culture); TestToStringResults(o, s, listSeparator, decimalSeparator); } finally { Thread.CurrentThread.CurrentCulture = originalCulture; } }
/// <summary> /// compute ray in given space starting from /// screen space x,y. /// The space of the computed ray depends on the value of mtrx: /// world * view * projection // ray in local space (object space). /// view * projection // ray in world space. /// projection // ray in view space. /// </summary> public Ray3F GetRay(Point scrPt, Matrix4F mtrx) { Vec3F min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), mtrx); Vec3F max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), mtrx); Vec3F dir = Vec3F.Normalize(max - min); Ray3F ray = new Ray3F(min, dir); return(ray); }
public static Ray3F GetRay(this Point scrPt, Matrix4F mtrx, Size controlSize) { Vec3F min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), mtrx, controlSize); Vec3F max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), mtrx, controlSize); Vec3F dir = Vec3F.Normalize(max - min); Ray3F ray = new Ray3F(min, dir); return(ray); }
/// <summary> /// compute ray in world space starting from /// screen space x,y. /// </summary> public Ray3F GetWorldRay(Point scrPt) { Matrix4F vp = Camera.ViewMatrix * Camera.ProjectionMatrix; Vec3F min = Unproject(new Vec3F(scrPt.X, scrPt.Y, 0), vp); Vec3F max = Unproject(new Vec3F(scrPt.X, scrPt.Y, 1), vp); Vec3F dir = Vec3F.Normalize(max - min); Ray3F ray = new Ray3F(min, dir); return(ray); }
public override bool MouseMove(object sender, MouseEventArgs e) { if (m_dragging && InputScheme.ActiveControlScheme.IsControllingCamera(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e))) { Control c = sender as Control; float dx = e.X - m_lastMousePointX; float dy = e.Y - m_lastMousePointY; if (InputScheme.ActiveControlScheme.IsRotating(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e)) && (Camera.ViewType == ViewTypes.Perspective || LockOrthographic == false)) { var orbitRotationSpeed = .0005f * (float)Math.PI; // just do this orbitting calculation in spherical coords... // it's much easier than any other method var orbitCenter = Camera.LookAtPoint; var spherical = CartesianToSphericalYUp(orbitCenter - Camera.Eye); spherical[0] += dy * orbitRotationSpeed; spherical[0] = Clamp(spherical[0], (float)Math.PI * 0.02f, (float)Math.PI * 0.98f); spherical[1] += dx * orbitRotationSpeed; var defaultUp = new Vec3F(0.0f, 1.0f, 0.0f); // (geometry gets hopelessly unnormalized if we don't reset default-up here) Camera.Set(orbitCenter - SphericalToCartesianYUp(spherical), orbitCenter, defaultUp); if (Camera.ViewType != ViewTypes.Perspective) { Camera.ViewType = ViewTypes.Perspective; } } else if (InputScheme.ActiveControlScheme.IsZooming(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e))) { float zoom = (-dy - dx); float adj = Camera.DistanceFromLookAt; var zoomSpeed = 0.01f * adj; var lookAtDir = Vec3F.Normalize(Camera.LookAt); var movement = Math.Min(zoom * zoomSpeed, Camera.DistanceFromLookAt - 0.1f); Camera.Set(Camera.Eye + lookAtDir * movement, Camera.LookAtPoint, Camera.Up); } else if (InputScheme.ActiveControlScheme.IsPanning(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e))) { float adj = Camera.DistanceFromLookAt; var panSpeed = 0.001f * adj; var lookAtPoint = Camera.LookAtPoint; var translation = (Camera.Up * dy * panSpeed) + (Camera.Right * -dx * panSpeed); Camera.Set(Camera.Eye + translation, lookAtPoint + translation, Camera.Up); } m_lastMousePointX = e.Location.X; m_lastMousePointY = e.Location.Y; return(true); } return(base.MouseMove(sender, e)); }
private static float CalcAngle(Vec3F origin, Plane3F plane, Ray3F ray0, Ray3F ray1, float snapAngle) { float theta = 0; Vec3F p0; Vec3F p1; if (ray0.IntersectPlane(plane, out p0) && ray1.IntersectPlane(plane, out p1)) { Vec3F v0 = Vec3F.Normalize(p0 - origin); Vec3F v1 = Vec3F.Normalize(p1 - origin); theta = CalcAngle(v0, v1, plane.Normal, snapAngle); } return(theta); }
public override bool MouseWheel(object sender, MouseEventArgs e) { if (!InputScheme.ActiveControlScheme.IsZooming(KeysInterop.ToAtf(Control.ModifierKeys), MouseEventArgsInterop.ToAtf(e))) { return(true); } float adj = Camera.DistanceFromLookAt; var zoomSpeed = .1f / 120.0f * adj; var lookAtDir = Vec3F.Normalize(Camera.LookAt); var movement = Math.Min(e.Delta * zoomSpeed, Camera.DistanceFromLookAt - 0.1f); Camera.Set(Camera.Eye + lookAtDir * movement, Camera.LookAtPoint, Camera.Up); return(true); }
/// <summary> /// Handles key-down events</summary> /// <param name="sender">Control that raised original event</param> /// <param name="e">Event args</param> /// <returns>true, if controller handled the event</returns> public override bool KeyDown(object sender, KeyEventArgs e) { m_keyMap[e.KeyValue] = true; // W A S D for forward, strafe left, backward, strafe right, is the default Vec3F dir = new Vec3F(); if (m_keyMap[(int)InputScheme.ActiveControlScheme.Left1] || m_keyMap[(int)InputScheme.ActiveControlScheme.Left2]) { dir = dir - Camera.Right; } if (m_keyMap[(int)InputScheme.ActiveControlScheme.Right1] || m_keyMap[(int)InputScheme.ActiveControlScheme.Right2]) { dir = dir + Camera.Right; } if (m_keyMap[(int)InputScheme.ActiveControlScheme.Forward1] || m_keyMap[(int)InputScheme.ActiveControlScheme.Forward2]) { dir = dir + Camera.LookAt; } if (m_keyMap[(int)InputScheme.ActiveControlScheme.Back1] || m_keyMap[(int)InputScheme.ActiveControlScheme.Back2]) { dir = dir - Camera.LookAt; } bool handled = InputScheme.ActiveControlScheme.IsControllingCamera(Control.ModifierKeys, e); if (handled) { dir.Normalize(); Vec3F p = Camera.Eye; float y = p.Y; p += dir * m_scale; p.Y = y; Camera.Set(p); } return(handled); }
private Vec3F ProjectToArcball(Point point) { float x = (float)point.X / (m_width / 2); // Scale so bounds map to [0,0] - [2,2] float y = (float)point.Y / (m_height / 2); x = x - 1; // Translate 0,0 to the center y = 1 - y; // Flip so +Y is up if (x < -1) x = -1; else if (x > 1) x = 1; if (y < -1) y = -1; else if (y > 1) y = 1; float z2 = 1 - x * x - y * y; // z^2 = 1 - x^2 - y^2 float z = z2 > 0 ? (float)Math.Sqrt(z2) : 0; Vec3F p = new Vec3F(x, y, z); p.Normalize(); return p; }
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 bool Intersect(Ray3F r, out float out_tmin, out float out_tmax, out Vec3F out_pos, out Vec3F out_nor) { out_pos = Vec3F.ZeroVector; out_nor = Vec3F.ZeroVector; out_tmin = 0.0f; out_tmax = 0.0f; Vec3F p = r.Origin; Vec3F d = r.Direction; float tmin = float.MinValue; float tmax = float.MaxValue; // check vs. all three 'slabs' of the aabb for (int i = 0; i < 3; ++i) { if (Math.Abs(d[i]) < float.Epsilon) { // ray is parallel to slab, no hit if origin not within slab if (p[i] < Min[i] || p[i] > Max[i]) { return(false); } } else { // compute intersection t values of ray with near and far plane of slab float ood = 1.0f / d[i]; float t1 = (Min[i] - p[i]) * ood; float t2 = (Max[i] - p[i]) * ood; tmin = Math.Max(tmin, Math.Min(t1, t2)); tmax = Math.Min(tmax, Math.Max(t1, t2)); // exit with no collision as soon as slab intersection becomes empty if (tmin > tmax) { return(false); } } } if (tmax < 0.0f) { // entire bounding box is behind us return(false); } else if (tmin < 0.0f) { // we are inside the bounding box out_tmin = 0.0f; out_tmax = tmax; out_pos = p + d * tmax; out_nor = Vec3F.Normalize(Center - out_pos); // use 'sphere' type normal calculation to approximate. return(true); } else { // ray intersects all 3 slabs. return point and normal of intersection out_tmin = tmin; out_pos = p + d * tmin; out_nor = Vec3F.Normalize(Center - out_pos); // use 'sphere' type normal calculation to approximate. return(true); } }
public override void OnDragging(ViewControl vc, Point scrPt) { if (m_hitRegion == HitRegion.None || NodeList.Count == 0) { return; } Camera cam = vc.Camera; Matrix4F view = cam.ViewMatrix; Matrix4F proj = cam.ProjectionMatrix; Matrix4F axisMtrx = HitMatrix * view; Ray3F hitRay = HitRayV; Ray3F dragRay = vc.GetRay(scrPt, proj); Vec3F xAxis = axisMtrx.XAxis; Vec3F yAxis = axisMtrx.YAxis; Vec3F zAxis = axisMtrx.ZAxis; Vec3F origin = axisMtrx.Translation; Vec3F rotAxis = new Vec3F(); float theta = 0; float snapAngle = ((ISnapSettings)DesignView).SnapAngle; switch (m_hitRegion) { case HitRegion.XAxis: { Plane3F xplane = new Plane3F(xAxis, origin); theta = CalcAngle(origin, xplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.XAxis; } break; case HitRegion.YAxis: { Plane3F yplane = new Plane3F(yAxis, origin); theta = CalcAngle(origin, yplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.YAxis; } break; case HitRegion.ZAxis: { Plane3F zplane = new Plane3F(zAxis, origin); theta = CalcAngle(origin, zplane, hitRay, dragRay, snapAngle); rotAxis = HitMatrix.ZAxis; } break; case HitRegion.LookAxis: { // for billboard objects the look vector is object's negative position in viewspace. Vec3F lookAxis = Vec3F.Normalize(-origin); Plane3F plane = new Plane3F(lookAxis, origin); theta = CalcAngle(origin, plane, hitRay, dragRay, snapAngle); rotAxis = m_lookAxisHitMtrx.ZAxis; } break; default: throw new ArgumentOutOfRangeException(); } AngleAxisF axf = new AngleAxisF(-theta, rotAxis); Matrix4F deltaMtrx = new Matrix4F(axf); Matrix4F rotMtrx = new Matrix4F(); for (int i = 0; i < NodeList.Count; i++) { ITransformable node = NodeList[i]; rotMtrx.Mul(m_rotations[i], deltaMtrx); float ax, ay, az; rotMtrx.GetEulerAngles(out ax, out ay, out az); node.Rotation = new Vec3F(ax, ay, az); } }