/// <summary> /// Gets the projection matrix for the specified camera. /// </summary> /// <param name="camera">The camera.</param> /// <param name="aspectRatio">The aspect ratio.</param> /// <returns>The projection matrix.</returns> public static Matrix GetProjectionMatrix(this Camera camera, double aspectRatio) { if (camera == null) { throw new ArgumentNullException("camera"); } var perspectiveCamera = camera as PerspectiveCamera; if (perspectiveCamera != null) { return(Matrix.PerspectiveFovRH( (float)perspectiveCamera.FieldOfView, (float)(aspectRatio), (float)perspectiveCamera.NearPlaneDistance, (float)perspectiveCamera.FarPlaneDistance)); } var orthographicCamera = camera as OrthographicCamera; if (orthographicCamera != null) { return(Matrix.OrthoRH( (float)orthographicCamera.Width, (float)(orthographicCamera.Width / aspectRatio), (float)orthographicCamera.NearPlaneDistance, (float)orthographicCamera.FarPlaneDistance)); } throw new HelixToolkitException("Unknown camera type."); }
// http://en.wikipedia.org/wiki/Polygon_triangulation // http://en.wikipedia.org/wiki/Monotone_polygon // http://www.codeproject.com/KB/recipes/hgrd.aspx LGPL // http://www.springerlink.com/content/g805787811vr1v9v/ /// <summary> /// Flattens this polygon. /// </summary> /// <returns> /// The 2D polygon. /// </returns> public Polygon Flatten() { // http://forums.xna.com/forums/p/16529/86802.aspx // http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane var up = this.GetNormal(); up.Normalize(); var right = Vector3D.Cross( up, Math.Abs(up.X) > Math.Abs(up.Z) ? new Vector3D(0, 0, 1) : new Vector3D(1, 0, 0)); var backward = Vector3D.Cross(right, up); var m = new Matrix3D( backward.X, right.X, up.X, 0, backward.Y, right.Y, up.Y, 0, backward.Z, right.Z, up.Z, 0, 0, 0, 0, 1); // make first point origin var offs = Vector3D.TransformCoordinate(Points[0], m); m.M41 = -offs.X; m.M42 = -offs.Y; var polygon = new Polygon { Points = new PointCollection(this.Points.Count) }; foreach (var p in this.Points) { var pp = Vector3D.TransformCoordinate(p, m); polygon.Points.Add(new Point(pp.X, pp.Y)); } return polygon; }
// http://en.wikipedia.org/wiki/Polygon_triangulation // http://en.wikipedia.org/wiki/Monotone_polygon // http://www.codeproject.com/KB/recipes/hgrd.aspx LGPL // http://www.springerlink.com/content/g805787811vr1v9v/ /// <summary> /// Flattens this polygon. /// </summary> /// <returns> /// The 2D polygon. /// </returns> public Polygon Flatten() { // http://forums.xna.com/forums/p/16529/86802.aspx // http://stackoverflow.com/questions/1023948/rotate-normal-vector-onto-axis-plane var up = this.GetNormal(); up.Normalize(); var right = Vector3D.Cross( up, Math.Abs(up.X) > Math.Abs(up.Z) ? new Vector3D(0, 0, 1) : new Vector3D(1, 0, 0)); var backward = Vector3D.Cross(right, up); var m = new Matrix3D( backward.X, right.X, up.X, 0, backward.Y, right.Y, up.Y, 0, backward.Z, right.Z, up.Z, 0, 0, 0, 0, 1); // make first point origin var offs = Vector3D.TransformCoordinate(Points[0], m); m.M41 = -offs.X; m.M42 = -offs.Y; var polygon = new Polygon { Points = new PointCollection(this.Points.Count) }; foreach (var p in this.Points) { var pp = Vector3D.TransformCoordinate(p, m); polygon.Points.Add(new Point(pp.X, pp.Y)); } return(polygon); }
/// <summary> /// Un-projects a 2D screen point. /// </summary> /// <param name="viewport">The viewport.</param> /// <param name="pointIn">The input point.</param> /// <param name="pointNear">The point at the near clipping plane.</param> /// <param name="pointFar">The point at the far clipping plane.</param> /// <returns>The ray.</returns> public static Ray UnProject(this Viewport3DX viewport, Vector2 point2d)//, out Vector3 pointNear, out Vector3 pointFar) { var camera = viewport.Camera as ProjectionCamera; if (camera != null) { var p = new Vector3((float)point2d.X, (float)point2d.Y, 1); //var wvp = GetViewProjectionMatrix(viewport); //Vector3 r = Vector3.Unproject(p, 0f, 0f, (float)viewport.ActualWidth, (float)viewport.ActualHeight, 0f, 1f, wvp); //r.Normalize(); var vp = GetScreenViewProjectionMatrix(viewport); var vpi = Matrix.Invert(vp); Vector3 zn, zf; p.Z = 0; Vector3.TransformCoordinate(ref p, ref vpi, out zn); p.Z = 1; Vector3.TransformCoordinate(ref p, ref vpi, out zf); Vector3 r = zf - zn; r.Normalize(); if (camera is PerspectiveCamera) { return(new Ray(camera.Position.ToVector3(), r)); } else if (camera is OrthographicCamera) { return(new Ray(zn, r)); } } throw new HelixToolkitException("Unproject camera error."); }
/// <summary> /// To the assimp matrix. Already transposed after this function /// </summary> /// <param name="m">The m.</param> /// <param name="toColumnMajor"></param> /// <returns></returns> public static Matrix4x4 ToAssimpMatrix(this global::SharpDX.Matrix m, bool toColumnMajor) { var matrix = new Matrix4x4(m.M11, m.M12, m.M13, m.M14, m.M21, m.M22, m.M23, m.M24, m.M31, m.M32, m.M33, m.M34, m.M41, m.M42, m.M43, m.M44); if (toColumnMajor) { matrix.Transpose(); } return(matrix); }
/// <summary> /// To the sharp dx matrix. Already transposed after this function /// </summary> /// <param name="m">The m.</param> /// <param name="isColumnMajor"></param> /// <returns></returns> public static global::SharpDX.Matrix ToSharpDXMatrix(this Matrix4x4 m, bool isColumnMajor) { var matrix = new global::SharpDX.Matrix(m.A1, m.A2, m.A3, m.A4, m.B1, m.B2, m.B3, m.B4, m.C1, m.C2, m.C3, m.C4, m.D1, m.D2, m.D3, m.D4); if (isColumnMajor) { matrix.Transpose(); } return(matrix); }
/// <summary> /// The rotate trackball. /// </summary> /// <param name="p1"> /// The previous mouse position. /// </param> /// <param name="p2"> /// The current mouse position. /// </param> /// <param name="rotateAround"> /// The point to rotate around. /// </param> private void RotateTrackball(Vector2 p1, Vector2 p2, Vector3 rotateAround) { // http://viewport3d.com/trackball.htm // http://www.codeplex.com/3DTools/Thread/View.aspx?ThreadId=22310 var v1 = ProjectToTrackball(p1, this.Viewport.ActualWidth, this.Viewport.ActualHeight); var v2 = ProjectToTrackball(p2, this.Viewport.ActualWidth, this.Viewport.ActualHeight); var cUP = Camera.CameraInternal.UpDirection; // transform the trackball coordinates to view space var viewZ = Vector3.Normalize(Camera.CameraInternal.LookDirection * Inv); var viewX = Vector3.Normalize(Vector3.Cross(cUP, viewZ) * Inv); var viewY = Vector3.Normalize(Vector3.Cross(viewX, viewZ)); var u1 = (viewZ * v1.Z) + (viewX * v1.X) + (viewY * v1.Y); var u2 = (viewZ * v2.Z) + (viewX * v2.X) + (viewY * v2.Y); // Could also use the Camera ViewMatrix // var vm = Viewport3DHelper.GetViewMatrix(this.ActualCamera); // vm.Invert(); // var ct = new MatrixTransform3D(vm); // var u1 = ct.Transform(v1); // var u2 = ct.Transform(v2); // Find the rotation axis and angle var axis = Vector3.Cross(u1, u2); if (axis.LengthSquared() < 1e-8) { return; } var angle = VectorExtensions.AngleBetween(u1, u2); // Create the transform var rotate = Matrix.RotationAxis(Vector3.Normalize(axis), -angle * (float)RotationSensitivity * 5); // Find vectors relative to the rotate-around point var relativeTarget = rotateAround - this.Camera.CameraInternal.Target; var relativePosition = rotateAround - this.Camera.CameraInternal.Position; // Rotate the relative vectors var newRelativeTarget = Vector3.TransformCoordinate(relativeTarget, rotate); var newRelativePosition = Vector3.TransformCoordinate(relativePosition, rotate); var newUpDirection = Vector3.TransformCoordinate(cUP, rotate); // Find new camera position var newTarget = rotateAround - newRelativeTarget; var newPosition = rotateAround - newRelativePosition; this.Camera.LookDirection = (newTarget - newPosition).ToVector3D(); if (this.CameraMode == CameraMode.Inspect) { this.Camera.Position = newPosition.ToPoint3D(); } this.Camera.UpDirection = newUpDirection.ToVector3D(); }
private void Timer_Tick() { double angle = (0.05f * frame) * Math.PI / 180; var xAxis = new Vector3(1, 0, 0); var zAxis = new Vector3(0, 0, 1); var yAxis = new Vector3(0, 1, 0); var rotation = Matrix.RotationAxis(xAxis, 0); double angleEach = 0; int counter = 0; for (int i = 0; i < NumSegments && i < numBonesInModel; ++i, counter += numSegmentPerBone) { if (i == 0) { boneInternal[0] = rotation; } else { var vp = Vector3.Transform(path[counter - numSegmentPerBone], Matrix.RotationAxis(xAxis, (float)angleEach)).ToVector3(); angleEach += angle; var v = Vector3.Transform(path[counter], Matrix.RotationAxis(xAxis, (float)angleEach)).ToVector3(); var rad = Math.Acos(Vector3.Dot(yAxis, (v - vp).Normalized())); if (angleEach < 0) { rad = -rad; } var rot = Matrix.RotationAxis(xAxis, (float)rad); var trans = Matrix.Translation(v); boneInternal[i] = rot * trans; } } var newBone = new BoneMatricesStruct() { Bones = boneInternal.ToArray() }; context.Post((o) => { Bones = newBone; }, null); if (frame > 40 || frame < -40) { direction = !direction; } if (direction) { ++frame; } else { --frame; } }
/// <summary> /// Rotate around three axes. /// </summary> /// <param name="p1"> /// The previous mouse position. /// </param> /// <param name="p2"> /// The current mouse position. /// </param> /// <param name="rotateAround"> /// The point to rotate around. /// </param> public void RotateTurnball(Vector2 p1, Vector2 p2, Vector3 rotateAround) { this.InitTurnballRotationAxes(p1); Vector2 delta = p2 - p1; var relativeTarget = rotateAround - this.Camera.CameraInternal.Target; var relativePosition = rotateAround - this.Camera.CameraInternal.Position; float d = -1; if (this.CameraMode != CameraMode.Inspect) { d = 0.2f; } d *= (float)RotationSensitivity; var q1 = Quaternion.RotationAxis(this.rotationAxisX, d * Inv * delta.X / 180 * (float)Math.PI); var q2 = Quaternion.RotationAxis(this.rotationAxisY, d * delta.Y / 180 * (float)Math.PI); Quaternion q = q1 * q2; var m = Matrix.RotationQuaternion(q); Vector3 newLookDir = Vector3.TransformNormal(this.Camera.CameraInternal.LookDirection, m); Vector3 newUpDirection = Vector3.TransformNormal(this.Camera.CameraInternal.UpDirection, m); Vector3 newRelativeTarget = Vector3.TransformCoordinate(relativeTarget, m); Vector3 newRelativePosition = Vector3.TransformCoordinate(relativePosition, m); var newRightVector = Vector3.Normalize(Vector3.Cross(newLookDir, newUpDirection)); var modUpDir = Vector3.Normalize(Vector3.Cross(newRightVector, newLookDir)); if ((newUpDirection - modUpDir).Length() > 1e-8) { newUpDirection = modUpDir; } var newTarget = rotateAround - newRelativeTarget; var newPosition = rotateAround - newRelativePosition; var newLookDirection = newTarget - newPosition; this.Camera.LookDirection = newLookDirection.ToVector3D(); if (this.CameraMode == CameraMode.Inspect) { this.Camera.Position = newPosition.ToPoint3D(); } this.Camera.UpDirection = newUpDirection.ToVector3D(); }
/// <summary> /// Called when [hit test]. /// </summary> /// <param name="context">The context.</param> /// <param name="totalModelMatrix">The total model matrix.</param> /// <param name="hits">The hits.</param> /// <returns></returns> protected override bool OnHitTest(HitTestContext context, global::SharpDX.Matrix totalModelMatrix, ref List <HitTestResult> hits) { var isHit = false; if (octreeManager != null) { isHit = octreeManager.HitTest(context, this.WrapperSource, totalModelMatrix, ref hits); if (isHit && logger.IsEnabled(LogLevel.Trace)) { logger.LogTrace("Octree hit test, hit at {}", hits[0].PointHit); } } else { isHit = base.OnHitTest(context, totalModelMatrix, ref hits); } return(isHit); }
/// <summary> /// Obtains the view transform matrix for a camera. (see page 327) /// </summary> /// <param name="camera"> /// Camera to obtain the ViewMatrix for /// </param> /// <returns> /// A Matrix object with the camera view transform matrix, or a Matrix with all zeros if the "camera" is null. /// </returns> public static Matrix GetViewMatrix(this Camera camera) { if (camera == null) { throw new ArgumentNullException("camera"); } if (camera is ProjectionCamera) { var projcam = camera as ProjectionCamera; return(Matrix.LookAtRH( projcam.Position.ToVector3(), (projcam.Position + projcam.LookDirection).ToVector3(), projcam.UpDirection.ToVector3())); } throw new HelixToolkitException("Unknown camera type."); }
/// <summary> /// Called when [hit test]. /// </summary> /// <param name="context">The context.</param> /// <param name="totalModelMatrix">The total model matrix.</param> /// <param name="ray">The ray.</param> /// <param name="hits">The hits.</param> /// <returns></returns> protected override bool OnHitTest(IRenderMatrices context, global::SharpDX.Matrix totalModelMatrix, ref global::SharpDX.Ray ray, ref List <HitTestResult> hits) { bool isHit = false; if (octreeManager != null) { isHit = octreeManager.HitTest(context, this.WrapperSource, totalModelMatrix, ray, ref hits); #if DEBUG if (isHit) { Debug.WriteLine("Octree hit test, hit at " + hits[0].PointHit); } #endif } else { isHit = base.OnHitTest(context, totalModelMatrix, ref ray, ref hits); } return(isHit); }
public static Matrix InverseViewMatrix(ref Matrix viewMatrix) { //var v33Transpose = new Matrix3x3( // viewMatrix.M11, viewMatrix.M21, viewMatrix.M31, // viewMatrix.M12, viewMatrix.M22, viewMatrix.M32, // viewMatrix.M13, viewMatrix.M23, viewMatrix.M33); //var vpos = viewMatrix.Row4.ToVector3(); // vpos = Vector3.Transform(vpos, v33Transpose) * -1; var x = viewMatrix.M41 * viewMatrix.M11 + viewMatrix.M42 * viewMatrix.M12 + viewMatrix.M43 * viewMatrix.M13; var y = viewMatrix.M41 * viewMatrix.M21 + viewMatrix.M42 * viewMatrix.M22 + viewMatrix.M43 * viewMatrix.M23; var z = viewMatrix.M41 * viewMatrix.M31 + viewMatrix.M42 * viewMatrix.M32 + viewMatrix.M43 * viewMatrix.M33; return(new Matrix( viewMatrix.M11, viewMatrix.M21, viewMatrix.M31, 0, viewMatrix.M12, viewMatrix.M22, viewMatrix.M32, 0, viewMatrix.M13, viewMatrix.M23, viewMatrix.M33, 0, -x, -y, -z, 1)); }
/// <summary> /// Rotate camera using 'Turntable' rotation. /// </summary> /// <param name="delta"> /// The relative change in position. /// </param> /// <param name="rotateAround"> /// The point to rotate around. /// </param> public void RotateTurntable(Vector2 delta, Vector3 rotateAround) { var relativeTarget = rotateAround - this.Camera.CameraInternal.Target; var relativePosition = rotateAround - this.Camera.CameraInternal.Position; var cUp = Camera.CameraInternal.UpDirection; var up = this.ModelUpDirection; var dir = Vector3.Normalize(Camera.CameraInternal.LookDirection); var right = Vector3.Normalize(Vector3.Cross(dir, cUp)); float d = -0.5f; if (this.CameraMode != CameraMode.Inspect) { d *= -0.2f; } d *= (float)this.RotationSensitivity; var q1 = Quaternion.RotationAxis(up, d * Inv * delta.X / 180 * (float)Math.PI); var q2 = Quaternion.RotationAxis(right, d * delta.Y / 180 * (float)Math.PI); Quaternion q = q1 * q2; var m = Matrix.RotationQuaternion(q); var newUpDirection = Vector3.TransformNormal(cUp, m); var newRelativeTarget = Vector3.TransformCoordinate(relativeTarget, m); var newRelativePosition = Vector3.TransformCoordinate(relativePosition, m); var newTarget = rotateAround - newRelativeTarget; var newPosition = rotateAround - newRelativePosition; this.Camera.LookDirection = (newTarget - newPosition).ToVector3D(); if (this.CameraMode == CameraMode.Inspect) { this.Camera.Position = newPosition.ToPoint3D(); } this.Camera.UpDirection = newUpDirection.ToVector3D(); }
private void LoadFile() { loader = new CMOReader(); var obj3Ds = loader.Read("Sphere_Bot_test.cmo"); foreach (var group in loader.AnimationHierarchy) { var boneGroup = new BoneGroupModel3D(); var skeletonGroup = new BoneGroupModel3D(); foreach (var obj3D in group.Meshes) { if (obj3D.Geometry is BoneSkinnedMeshGeometry3D boneMesh) { var model = new BoneSkinMeshGeometryModel3D() { Geometry = obj3D.Geometry, FrontCounterClockwise = false, CullMode = CullMode.Back, Material = obj3D.Material.ConvertToMaterial(), IsThrowingShadow = true }; boneGroup.Children.Add(model); } else if (obj3D.Geometry is MeshGeometry3D) { Models.Add(new MeshGeometryModel3D() { Geometry = obj3D.Geometry, CullMode = CullMode.Back, FrontCounterClockwise = false }); } } var skeletonModel = new BoneSkinMeshGeometryModel3D() { Geometry = BoneSkinnedMeshGeometry3D.CreateSkeletonMesh(group.Bones, 0.1f), CullMode = CullMode.Back, Material = BoneMaterial, PostEffects = "xray" }; skeletonGroup.Children.Add(skeletonModel); Models.Add(boneGroup); BoneModels.Add(skeletonGroup); BoneGroupsDictionary.Add(group.GUID, new List <BoneGroupModel3D>() { boneGroup, skeletonGroup }); } var diffuse = new MemoryStream(); using (var file = File.OpenRead(@"Sphere_Bot_Rusty_UVMap_color.png")) { file.CopyTo(diffuse); } var normal = new MemoryStream(); using (var file = File.OpenRead(@"Sphere_Bot_Rusty_UVMap_nmap.png")) { file.CopyTo(normal); } foreach (var group in Models) { if (group is GroupElement3D g) { foreach (var subModel in g.Children) { if (subModel is MaterialGeometryModel3D model) { var m = model.Material as PhongMaterial; m.EmissiveColor = Colors.Black.ToColor4(); m.DiffuseMap = diffuse; m.NormalMap = normal; m.RenderShadowMap = true; } } } } Animations = loader.UniqueAnimations.Keys.ToArray(); ModelTransform = new Media3D.MatrixTransform3D((Matrix.Scaling(10, 10, 10) * Matrix.RotationAxis(Vector3.UnitX, -(float)Math.PI / 2)).ToMatrix3D()); foreach (var group in loader.AnimationHierarchy) { foreach (var ani in group.Animations) { if (!keyframeUpdaters.ContainsKey(ani.Key)) { keyframeUpdaters.Add(ani.Key, new List <KeyValuePair <Guid, KeyFrameUpdater> >()); } keyframeUpdaters[ani.Key].Add(new KeyValuePair <Guid, KeyFrameUpdater>(group.GUID, new KeyFrameUpdater(ani.Value, group.Bones))); } } }
public MainViewModel() { this.Title = "BoneSkin Demo"; this.SubTitle = "WPF & SharpDX"; EffectsManager = new DefaultEffectsManager(); RenderTechnique = EffectsManager[DefaultRenderTechniqueNames.Blinn]; this.Camera = new HelixToolkit.Wpf.SharpDX.PerspectiveCamera { Position = new Media3D.Point3D(20, 20, 20), LookDirection = new Media3D.Vector3D(-20, -20, -20), UpDirection = new Media3D.Vector3D(0, 1, 0) }; this.Light1Color = Colors.White; this.Light1Direction = new Media3D.Vector3D(-10, -10, -10); this.AmbientLightColor = Colors.DarkGray; SetupCameraBindings(this.Camera); var builder = new MeshBuilder(true, true, true); path = new List <Vector3>(); for (int i = 0; i < NumSegments; ++i) { path.Add(new Vector3(0, (float)i / 10, 0)); } builder.AddTube(path, 2, Theta, false, false, true); Model = builder.ToMesh(); for (int i = 0; i < Model.Positions.Count; ++i) { Model.Positions[i] = new Vector3(Model.Positions[i].X, 0, Model.Positions[i].Z); } Material = new PhongMaterial() { DiffuseColor = Colors.SteelBlue.ToColor4() }; for (int i = 0; i < numBonesInModel; ++i) { boneInternal[i] = Matrix.Identity; } Bones = new BoneMatricesStruct() { Bones = boneInternal.ToArray() }; builder = new MeshBuilder(true, true, false); builder.AddBox(new Vector3(), 40, 0.5, 40, BoxFaces.All); FloorModel = builder.ToMesh(); int boneId = 0; numSegmentPerBone = (int)Math.Max(1, (double)Model.Positions.Count / Theta / (numBonesInModel - 1)); int count = 0; for (int i = 0; i < Model.Positions.Count / Theta; ++i) { boneParams.AddRange(Enumerable.Repeat(new BoneIds() { Bone1 = Math.Min(numBonesInModel - 1, boneId), Bone2 = Math.Min(numBonesInModel - 1, boneId - 1), Bone3 = Math.Min(numBonesInModel - 1, boneId + 1), Weights = new Vector4(0.6f, 0.2f, 0.2f, 0) }, Theta)); ++count; if (count == numSegmentPerBone) { count = 0; ++boneId; } } VertexBoneParams = boneParams.ToArray(); Instances = new List <Matrix>(); for (int i = 0; i < 3; ++i) { Instances.Add(Matrix.Translation(new Vector3(-5 + i * 4, 0, -10))); } for (int i = 0; i < 3; ++i) { Instances.Add(Matrix.Translation(new Vector3(-5 + i * 4, 0, 0))); } for (int i = 0; i < 3; ++i) { Instances.Add(Matrix.Translation(new Vector3(-5 + i * 4, 0, 10))); } StartAnimation(); }
public static global::SharpDX.Matrix Inverted(this global::SharpDX.Matrix m) { m.Invert(); return(m); }