private void Rebuild(UndoBuffer undoBuffer) { this.DebugDepth("Rebuild"); using (RebuildLock()) { var startingAabb = this.GetAxisAlignedBoundingBox(); // remove whatever rotation has been applied (they go in reverse order) Matrix = Matrix4X4.Identity; // add the current rotation Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(RotationXDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(RotationYDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(RotationZDegrees))); if (startingAabb.ZSize > 0) { // If the part was already created and at a height, maintain the height. PlatingHelper.PlaceMeshAtHeight(this, startingAabb.minXYZ.Z); } } Invalidate(new InvalidateArgs(this, InvalidateType.Matrix, null)); }
public void FrustumTransformTests() { Frustum frustum = new Frustum( new Plane(new Vector3(1, 0, 0), 20), new Plane(new Vector3(-1, 0, 0), 20), new Plane(new Vector3(0, 1, 0), 20), new Plane(new Vector3(0, -1, 0), 20), new Plane(new Vector3(0, 0, 1), 20), new Plane(new Vector3(0, 0, -1), 20)); // moved right { Frustum movedRightFrustum = Frustum.Transform(frustum, Matrix4X4.CreateTranslation(10, 0, 0)); Assert.IsTrue(movedRightFrustum.Planes[0] == new Plane(new Vector3(1, 0, 0), 30)); Assert.IsTrue(movedRightFrustum.Planes[1] == new Plane(new Vector3(-1, 0, 0), 10)); Assert.IsTrue(movedRightFrustum.Planes[2] == frustum.Planes[2]); Assert.IsTrue(movedRightFrustum.Planes[3] == frustum.Planes[3]); Assert.IsTrue(movedRightFrustum.Planes[4] == frustum.Planes[4]); Assert.IsTrue(movedRightFrustum.Planes[5] == frustum.Planes[5]); } // rotated right { Frustum movedRightFrustum = Frustum.Transform(frustum, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(45))); Matrix4X4 testMatrix = Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(45)); Plane control = new Plane(Vector3.TransformNormal(frustum.Planes[0].PlaneNormal, testMatrix), frustum.Planes[0].DistanceToPlaneFromOrigin); Assert.IsTrue(movedRightFrustum.Planes[0].Equals(control, .001, .01)); Assert.IsTrue(movedRightFrustum.Planes[1].Equals(new Plane(Vector3.TransformNormal(frustum.Planes[1].PlaneNormal, testMatrix), frustum.Planes[1].DistanceToPlaneFromOrigin))); Assert.IsTrue(movedRightFrustum.Planes[2].Equals(frustum.Planes[2])); Assert.IsTrue(movedRightFrustum.Planes[3].Equals(frustum.Planes[3])); Assert.IsTrue(movedRightFrustum.Planes[4].Equals(new Plane(Vector3.TransformNormal(frustum.Planes[4].PlaneNormal, testMatrix), frustum.Planes[4].DistanceToPlaneFromOrigin))); Assert.IsTrue(movedRightFrustum.Planes[5].Equals(new Plane(Vector3.TransformNormal(frustum.Planes[5].PlaneNormal, testMatrix), frustum.Planes[5].DistanceToPlaneFromOrigin))); } }
public static Vector3 MapMoveToSphere(Vector2 screenCenter, WorldView world, double trackBallRadius, Vector2 startPosition, Vector2 endPosition, bool rotateOnZ) { if (rotateOnZ) { var deltaFromScreenCenter = screenCenter - endPosition; var angleToTravel = screenCenter.GetDeltaAngle(startPosition, endPosition); // now rotate that position about z in the direction of the screen vector var positionOnRotationSphere = Vector3Ex.Transform(new Vector3(1, 0, 0), Matrix4X4.CreateRotationZ(angleToTravel / 2)); return(positionOnRotationSphere); } else { var deltaFromStartPixels = endPosition - startPosition; var deltaOnSurface = new Vector2(deltaFromStartPixels.X / trackBallRadius, deltaFromStartPixels.Y / trackBallRadius); var lengthOnSurfaceRadi = deltaOnSurface.Length; // get this rotation on the surface of the sphere about y var positionAboutY = Vector3Ex.Transform(new Vector3(0, 0, 1), Matrix4X4.CreateRotationY(lengthOnSurfaceRadi)); // get the angle that this distance travels around the sphere var angleToTravel = Math.Atan2(deltaOnSurface.Y, deltaOnSurface.X); // now rotate that position about z in the direction of the screen vector var positionOnRotationSphere = Vector3Ex.Transform(positionAboutY, Matrix4X4.CreateRotationZ(angleToTravel)); return(positionOnRotationSphere); } }
// Transform by quaternion public void PlaneTransformTest2() { Plane <float> target = new Plane <float>(1, 2, 3, 4); target = Plane.Normalize(target); Matrix4X4 <float> m = Matrix4X4.CreateRotationX(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ(MathHelper.ToRadians(30.0f)); Quaternion <float> q = Quaternion <float> .CreateFromRotationMatrix(m); Plane <float> expected = new Plane <float>(); float x = target.Normal.X, y = target.Normal.Y, z = target.Normal.Z, w = target.Distance; expected.Normal = new Vector3D <float>( x * m.M11 + y * m.M21 + z * m.M31 + w * m.M41, x * m.M12 + y * m.M22 + z * m.M32 + w * m.M42, x * m.M13 + y * m.M23 + z * m.M33 + w * m.M43); expected.Distance = x * m.M14 + y * m.M24 + z * m.M34 + w * m.M44; Plane <float> actual; actual = Plane.Transform(target, q); Assert.True(MathHelper.Equal(expected, actual), "Plane<float>.Transform did not return the expected value."); }
private Vector3 MapMoveToSphere(Vector2 screenPoint, bool rotateOnZ) { if (rotateOnZ) { var deltaFromScreenCenter = world.ScreenCenter - screenPoint; var angleToTravel = world.ScreenCenter.GetDeltaAngle(mouseDownPosition, screenPoint); // now rotate that position about z in the direction of the screen vector var positionOnRotationSphere = Vector3.Transform(new Vector3(1, 0, 0), Matrix4X4.CreateRotationZ(angleToTravel / 2)); return(positionOnRotationSphere); } else { var deltaFromStartPixels = screenPoint - mouseDownPosition; var deltaOnSurface = new Vector2(deltaFromStartPixels.X / rotationTrackingRadiusPixels, deltaFromStartPixels.Y / rotationTrackingRadiusPixels); var lengthOnSurfaceRadi = deltaOnSurface.Length; // get this rotation on the surface of the sphere about y var positionAboutY = Vector3.Transform(new Vector3(0, 0, 1), Matrix4X4.CreateRotationY(lengthOnSurfaceRadi)); // get the angle that this distance travels around the sphere var angleToTravel = Math.Atan2(deltaOnSurface.Y, deltaOnSurface.X); // now rotate that position about z in the direction of the screen vector var positionOnRotationSphere = Vector3.Transform(positionAboutY, Matrix4X4.CreateRotationZ(angleToTravel)); return(positionOnRotationSphere); } }
// Transform by matrix public void PlaneTransformTest1() { Plane <float> target = new Plane <float>(1, 2, 3, 4); target = Plane.Normalize(target); Matrix4X4 <float> m = Matrix4X4.CreateRotationX(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ(MathHelper.ToRadians(30.0f)); m.M41 = 10.0f; m.M42 = 20.0f; m.M43 = 30.0f; Plane <float> expected = new Plane <float>(); Matrix4X4 <float> inv; Matrix4X4.Invert(m, out inv); Matrix4X4 <float> itm = Matrix4X4.Transpose(inv); float x = target.Normal.X, y = target.Normal.Y, z = target.Normal.Z, w = target.Distance; expected.Normal = new Vector3D <float>( x * itm.M11 + y * itm.M21 + z * itm.M31 + w * itm.M41, x * itm.M12 + y * itm.M22 + z * itm.M32 + w * itm.M42, x * itm.M13 + y * itm.M23 + z * itm.M33 + w * itm.M43); expected.Distance = x * itm.M14 + y * itm.M24 + z * itm.M34 + w * itm.M44; Plane <float> actual; actual = Plane.Transform(target, m); Assert.True(MathHelper.Equal(expected, actual), "Plane<float>.Transform did not return the expected value."); }
public void RotateAbsolute(double x, double y, double z) { Matrix4X4 M1 = Matrix4X4.Identity; Matrix4X4 M2 = Matrix4X4.Identity; Matrix4X4 M3 = Matrix4X4.Identity; Matrix4X4 M4 = Matrix4X4.Identity; Vector3 save1; // save the old position save1.x = AxisToWorld[3, 0]; save1.y = AxisToWorld[3, 1]; save1.z = AxisToWorld[3, 2]; M1 = Matrix4X4.CreateRotationX(x); M2 = Matrix4X4.CreateRotationY(y); M3 = Matrix4X4.CreateRotationZ(z); // 1 * 2 * 3 M4 = M2 * M1; AxisToWorld = M3 * M4; // stuff the old position back in AxisToWorld[3, 0] = save1.x; AxisToWorld[3, 1] = save1.y; AxisToWorld[3, 2] = save1.z; AxisToWorld = Matrix4X4.Invert(WorldToAxis); }
public void Can_Rotate_Point_Around_Y() { var point = new Point(0, 0, 1); var halfQuarter = Matrix4X4.CreateRotationY(Math.PI / 4); var fullQuarter = Matrix4X4.CreateRotationY(Math.PI / 2); (halfQuarter * point).ShouldBe(new Point(Math.Sqrt(2) / 2, 0, Math.Sqrt(2) / 2)); (fullQuarter * point).ShouldBe(new Point(1, 0, 0)); }
public void Construct_Ray_When_Camera_Is_Transformed() { var camera = new Camera(201, 101, Math.PI / 2) { ViewTransform = Matrix4X4.CreateRotationY(Math.PI / 4) * Matrix4X4.CreateTranslation(0, -2, 5), }; var ray = camera.RayForPixel(100, 50); ray.Origin.ShouldBe(new Point(0, 2, -5)); ray.Direction.ShouldBe(new Vector(Math.Sqrt(2) / 2, 0, -Math.Sqrt(2) / 2)); }
public LogoSpinner(GuiWidget widget, double scale = 1.6, double spinSpeed = 0.6, double yOffset = 0.5, double rotateX = -0.1) { // loading animation stuff LightingData lighting = new LightingData(); Mesh logoMesh; using (var logoStream = StaticData.Instance.OpenStream(Path.Combine("Stls", "MH Logo.stl"))) { logoMesh = StlProcessing.Load(logoStream, CancellationToken.None); } // Position var aabb = logoMesh.GetAxisAlignedBoundingBox(); logoMesh.Transform(Matrix4X4.CreateTranslation(-aabb.Center)); logoMesh.Transform(Matrix4X4.CreateScale(scale / aabb.XSize)); var anglePerDraw = 1 / MathHelper.Tau * spinSpeed; var angle = 0.0; widget.BeforeDraw += (s, e) => { var screenSpaceBounds = widget.TransformToScreenSpace(widget.LocalBounds); WorldView world = new WorldView(screenSpaceBounds.Width, screenSpaceBounds.Height); world.Translate(new Vector3(0, yOffset, 0)); world.Rotate(Quaternion.FromEulerAngles(new Vector3(rotateX, 0, 0))); GLHelper.SetGlContext(world, screenSpaceBounds, lighting); GLHelper.Render(logoMesh, this.MeshColor, Matrix4X4.CreateRotationY(angle), RenderTypes.Shaded); GLHelper.UnsetGlContext(); }; Animation spinAnimation = new Animation() { DrawTarget = widget, FramesPerSecond = 20 }; spinAnimation.Update += (s, time) => { if (this.SpinLogo) { angle += anglePerDraw; } }; spinAnimation.Start(); }
public void GetRotation(ref Vector3 pOutVector) { Vector3 UpVector = new Vector3(0, 1, 0);; Vector3 ForwardVector = new Vector3(0, 0, 1); UpVector = Vector3.Transform(UpVector, AxisToWorld); ForwardVector = Vector3.Transform(ForwardVector, AxisToWorld); pOutVector.z = Math.Atan2(UpVector.x, UpVector.y); // DebugStream("It looks like z is now " << RadToDeg(pOutVector->z)); Matrix4X4 ZMatrix = Matrix4X4.CreateRotationZ(-pOutVector.z); UpVector = Vector3.Transform(UpVector, ZMatrix); ForwardVector = Vector3.Transform(ForwardVector, ZMatrix); // DebugStream("It looks like z is now " << RadToDeg(atan2(UpVector.x, UpVector.y))); pOutVector.y = -Math.Atan2(ForwardVector.x, ForwardVector.z); // DebugStream("It looks like y is now " << RadToDeg(pOutVector->y)); Matrix4X4 YMatrix = Matrix4X4.CreateRotationY(-pOutVector.y); UpVector = Vector3.Transform(UpVector, YMatrix); ForwardVector = Vector3.Transform(ForwardVector, YMatrix); // DebugStream("It looks like y is now " << RadToDeg(-atan2(ForwardVector.x, ForwardVector.z))); pOutVector.x = -Math.Atan2(UpVector.z, UpVector.y); // DebugStream("It looks like x is now " << RadToDeg(pOutVector->x)); //CMatrix XMatrix; //XMatrix.Rotate(0, -pOutVector->x, ROTATE_FAST); //XMatrix.TransformVector(&UpVector); //XMatrix.TransformVector(&ForwardVector); // DebugStream("It looks like x is now " << RadToDeg(-atan2(UpVector.z, UpVector.y))); #if _DEBUG CMatrix Test; CVector3D TestV, HoldV; TestV.Set((double)(rand() % 1024), (double)(rand() % 1024), (double)(rand() % 1024)); HoldV = TestV; Test.PrepareMatrix(0.f, 0.f, 0.f, pOutVector->x, pOutVector->y, pOutVector->z); WorldToAxis.TransformVector(&TestV); Test.TransformVector(&TestV); #endif }
public void Vector3TransformByQuaternionTest() { Vector3D <float> v = new Vector3D <float>(1.0f, 2.0f, 3.0f); Matrix4X4 <float> m = Matrix4X4.CreateRotationX <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ <float>(MathHelper.ToRadians(30.0f)); Quaternion <float> q = Quaternion <float> .CreateFromRotationMatrix(m); Vector3D <float> expected = Vector3D.Transform(v, m); Vector3D <float> actual = Vector3D.Transform(v, q); Assert.True(MathHelper.Equal(expected, actual), "Vector3D<float>f.Transform did not return the expected value."); }
public override void SetPosition(IObject3D selectedItem) { Vector3 boxCenter = GetControlCenter(selectedItem); double distBetweenPixelsWorldSpace = InteractionContext.World.GetWorldUnitsPerScreenPixelAtPosition(boxCenter); GetCornerPosition(selectedItem, out int cornerIndexOut); Matrix4X4 centerMatrix = Matrix4X4.Identity; switch (RotationAxis) { case 0: if (cornerIndexOut == 1 || cornerIndexOut == 3) { centerMatrix *= Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(90)); } else { centerMatrix *= Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(-90)); } centerMatrix *= Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(90) * cornerIndexOut); break; case 1: if (cornerIndexOut == 1 || cornerIndexOut == 3) { centerMatrix *= Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(-90)); } else { centerMatrix *= Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(90)); } centerMatrix *= Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(90) * cornerIndexOut); break; case 2: centerMatrix *= Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(90) * cornerIndexOut); break; } centerMatrix *= Matrix4X4.CreateScale(distBetweenPixelsWorldSpace) * Matrix4X4.CreateTranslation(boxCenter); TotalTransform = centerMatrix; }
public void Vector2TransformNormalTest() { Vector2D <float> v = new Vector2D <float>(1.0f, 2.0f); Matrix4X4 <float> m = Matrix4X4.CreateRotationX <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ <float>(MathHelper.ToRadians(30.0f)); m.M41 = 10.0f; m.M42 = 20.0f; m.M43 = 30.0f; Vector2D <float> expected = new Vector2D <float>(0.3169873f, 2.18301272f); Vector2D <float> actual; actual = Vector2D.TransformNormal(v, m); Assert.True(MathHelper.Equal(expected, actual), "Vector2f.Tranform did not return the expected value."); }
public void Vector3TransformNormalTest() { Vector3D <float> v = new Vector3D <float>(1.0f, 2.0f, 3.0f); Matrix4X4 <float> m = Matrix4X4.CreateRotationX <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationY <float>(MathHelper.ToRadians(30.0f)) * Matrix4X4.CreateRotationZ <float>(MathHelper.ToRadians(30.0f)); m.M41 = 10.0f; m.M42 = 20.0f; m.M43 = 30.0f; Vector3D <float> expected = new Vector3D <float>(2.19198728f, 1.53349364f, 2.61602545f); Vector3D <float> actual; actual = Vector3D.TransformNormal(v, m); Assert.True(MathHelper.Equal(expected, actual), "Vector3D<float>f.TransformNormal did not return the expected value."); }
public void QuaternionFromRotationMatrixWithScaledMatrixTest3() { float angle = MathHelper.ToRadians(180.0f); Matrix4X4 <float> matrix = Matrix4X4.CreateRotationX <float>(angle) * Matrix4X4.CreateRotationY <float>(angle); Quaternion <float> expected = Quaternion <float> .CreateFromAxisAngle(Vector3D <float> .UnitY, angle) * Quaternion <float> .CreateFromAxisAngle(Vector3D <float> .UnitX, angle); Quaternion <float> actual = Quaternion <float> .CreateFromRotationMatrix(matrix); Assert.True(MathHelper.EqualRotation(expected, actual), $"Quaternion<float>.CreateFromRotationMatrix did not return the expected value: expected {expected} actual {actual}"); // make sure convert back to matrix is same as we passed matrix. Matrix4X4 <float> m2 = Matrix4X4.CreateFromQuaternion <float>(actual); Assert.True(MathHelper.Equal(matrix, m2), $"Quaternion<float>.CreateFromQuaternion did not return the expected value: matrix {matrix} m2 {m2}"); }
public void QuaternionFromRotationMatrixTest3() { for (float angle = 0.0f; angle < 720.0f; angle += 10.0f) { Matrix4X4 <float> matrix = Matrix4X4.CreateRotationY <float>(angle); Quaternion <float> expected = Quaternion <float> .CreateFromAxisAngle(Vector3D <float> .UnitY, angle); Quaternion <float> actual = Quaternion <float> .CreateFromRotationMatrix(matrix); Assert.True(MathHelper.EqualRotation(expected, actual), $"Quaternion<float>.CreateFromRotationMatrix angle:{angle} did not return the expected value: expected {expected} actual {actual}"); // make sure convert back to matrix is same as we passed matrix. Matrix4X4 <float> m2 = Matrix4X4.CreateFromQuaternion <float>(actual); Assert.True(MathHelper.Equal(matrix, m2), $"Quaternion<float>.CreateFromQuaternion angle:{angle} did not return the expected value: matrix {matrix} m2 {m2}"); } }
public static async Task <CylinderObject3D> Create(double diameterBottom, double diameterTop, double height, int sides, Alignment alignment = Alignment.Z) { var item = new CylinderObject3D() { Advanced = true, Diameter = diameterBottom, DiameterTop = diameterTop, Height = height, Sides = sides, }; await item.Rebuild(); switch (alignment) { case Alignment.X: item.Matrix = Matrix4X4.CreateRotationY(MathHelper.Tau / 4); break; case Alignment.Y: item.Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 4); break; case Alignment.Z: // This is the natural case (how it was modeled) break; case Alignment.negX: item.Matrix = Matrix4X4.CreateRotationY(-MathHelper.Tau / 4); break; case Alignment.negY: item.Matrix = Matrix4X4.CreateRotationX(-MathHelper.Tau / 4); break; case Alignment.negZ: item.Matrix = Matrix4X4.CreateRotationX(MathHelper.Tau / 2); break; } return(item); }
public void MatrixColumnMajor() { // Make sure our matrix is set up colum major like opengl. LBB [7/11/2003] Matrix4X4 ColumnMajorRotationMatrix = Matrix4X4.CreateRotationY(.2345f); Matrix4X4 ColumnMajorTransLationMatrix = Matrix4X4.Identity; ColumnMajorTransLationMatrix.Translate(.2342f, 234234.734f, 223.324f); Matrix4X4 ColumnMajorAccumulatedMatrix = Matrix4X4.Identity; ColumnMajorAccumulatedMatrix = ColumnMajorRotationMatrix * ColumnMajorTransLationMatrix; double[] KnownMatrixFormFloats = { .972631f, 0.0f, -.232357f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, .232357f, 0.0f, .972631f, 0.0f, .2342f, 234234.73f, 223.324f, 1.0f }; Matrix4X4 KnownMatrixForm = Matrix4X4.Identity; KnownMatrixForm.SetElements(KnownMatrixFormFloats); Assert.IsTrue(KnownMatrixForm.Equals(ColumnMajorAccumulatedMatrix, .01f)); }
public override Task Rebuild() { this.DebugDepth("Rebuild"); using (RebuildLock()) { using (new CenterAndHeightMantainer(this)) { var startingAabb = this.GetAxisAlignedBoundingBox(); // remove whatever rotation has been applied (they go in reverse order) Matrix = Matrix4X4.Identity; // add the current rotation Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationX(MathHelper.DegreesToRadians(RotationXDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(RotationYDegrees))); Matrix = this.ApplyAtPosition(startingAabb.Center, Matrix4X4.CreateRotationZ(MathHelper.DegreesToRadians(RotationZDegrees))); } } Parent?.Invalidate(new InvalidateArgs(this, InvalidateType.Matrix)); return(Task.CompletedTask); }
private static World CreateWorld() { var floor = new Plane { Material = new Material { Pattern = new CheckersPattern(Color.White, Color.Black), Color = Color.White, Specular = 0, } }; var backWall = new Plane { TransformMatrix = new Transform().RotateX(Math.PI / 2) .RotateY(-Math.PI / 2) .Translate(1.5, 0, 0) .GetTransformationMatrix(), Material = new Material { Pattern = new StripePattern(new Color(0, 0.5, 0.5), new Color(1, 0, 0)) { TransformMatrix = Matrix4X4.CreateRotationY(Math.PI / 4) }, Specular = 0, } }; var middleSphere = new Sphere(Matrix4X4.CreateTranslation(-0.5, 1, 0.5)) { Material = new Material { Pattern = new RingPattern(new Color(1, 0, 0), new Color(0, 1, 0)) { TransformMatrix = Matrix4X4.CreateRotationX(Math.PI / -3) * Matrix4X4.CreateScale(0.25, 0.25, 0.25) }, Diffuse = 0.7, Specular = 0.3, } }; var rightSphere = new Sphere(Matrix4X4.CreateTranslation(1.5, 0.5, -0.5) * Matrix4X4.CreateScale(0.5, 0.5, 0.5)) { Material = new Material { Color = new Color(0.5, 1, 0.1), Diffuse = 0.7, Specular = 0.3, } }; var leftSphere = new Sphere(Matrix4X4.CreateTranslation(-1.5, 0.33, -0.75) * Matrix4X4.CreateScale(0.33, 0.33, 0.33)) { Material = new Material { Pattern = new StripePattern(new Color(0, 0, 1), new Color(0, 1, 0)) { TransformMatrix = Matrix4X4.CreateScale(0.25, 0.25, 0.25) }, Diffuse = 0.7, Specular = 0.3, } }; var light = new PointLight(new Point(-10, 10, -10), new Color(1, 1, 1)); return(new World { Objects = { middleSphere, rightSphere, leftSphere, floor, backWall }, PointLights = { light }, }); }
public void RotateRelative(double x, double y, double z) { #if true if (x != 0) { Matrix4X4 M1 = Matrix4X4.Identity; M1 = Matrix4X4.CreateRotationX(x); if (y != 0) { Matrix4X4 M2 = Matrix4X4.Identity; Matrix4X4 M4 = Matrix4X4.Identity; M2 = Matrix4X4.CreateRotationY(y); M4 = M2 * M1; if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); Matrix4X4 Delta = Matrix4X4.Identity; Delta = M3 * M4; AxisToWorld *= Delta; } else { AxisToWorld *= M4; } } else { if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); Matrix4X4 Delta = Matrix4X4.Identity; Delta = M3 * M1; AxisToWorld *= Delta; } else { AxisToWorld *= M1; } } } else { if (y != 0) { Matrix4X4 M2 = Matrix4X4.Identity; M2 = Matrix4X4.CreateRotationY(y); if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); Matrix4X4 Delta = Matrix4X4.Identity; Delta = M3 * M2; AxisToWorld *= Delta; } else { AxisToWorld *= M2; } } else { if (z != 0) { Matrix4X4 M3 = Matrix4X4.Identity; M3 = Matrix4X4.CreateRotationZ(z); AxisToWorld *= M3; } } } WorldToAxis = Matrix4X4.Invert(AxisToWorld); #else M1.Rotate(0, x); M2.Rotate(1, y); M3.Rotate(2, z); // 1 * 2 * 3 M4 = M2 * M1; Delta = M3 * M4; AxisToWorld = AxisToWorld * Delta; WorldToAxis = AxisToWorld.GetInverse(); #endif }
private static World CreateWorld() { var floor = new Sphere(Matrix4X4.CreateScale(10, 0.01, 10)) { Material = new Material { Color = new Color(1, 0.9, 0.9), Specular = 0, } }; var leftWall = new Sphere(Matrix4X4.CreateTranslation(0, 0, 5) * Matrix4X4.CreateRotationY(-Math.PI / 4) * Matrix4X4.CreateRotationX(Math.PI / 2) * Matrix4X4.CreateScale(10, 0.01, 10)) { Material = new Material { Color = new Color(1, 0.9, 0.9), Specular = 0, } }; var rightWall = new Sphere(Matrix4X4.CreateTranslation(0, 0, 5) * Matrix4X4.CreateRotationY(Math.PI / 4) * Matrix4X4.CreateRotationX(Math.PI / 2) * Matrix4X4.CreateScale(10, 0.01, 10)) { Material = new Material { Color = new Color(1, 0.9, 0.9), Specular = 0, } }; var middleSphere = new Sphere(Matrix4X4.CreateTranslation(-0.5, 1, 0.5)) { Material = new Material { Color = new Color(0.1, 1, 0.5), Diffuse = 0.7, Specular = 0.3, } }; var rightSphere = new Sphere(Matrix4X4.CreateTranslation(1.5, 0.5, -0.5) * Matrix4X4.CreateScale(0.5, 0.5, 0.5)) { Material = new Material { Color = new Color(0.5, 1, 0.1), Diffuse = 0.7, Specular = 0.3, } }; var leftSphere = new Sphere(Matrix4X4.CreateTranslation(-1.5, 0.33, -0.75) * Matrix4X4.CreateScale(0.33, 0.33, 0.33)) { Material = new Material { Color = new Color(1, 0.8, 0.1), Diffuse = 0.7, Specular = 0.3, } }; var light = new PointLight(new Point(-10, 10, -10), new Color(1, 1, 1)); return new World { Objects = {floor, rightWall, leftWall, middleSphere, rightSphere, leftSphere}, PointLights = {light}, }; }
public void FrustumTransformTests() { { Frustum frustum = new Frustum( new Plane(new Vector3(1, 0, 0), -20), new Plane(new Vector3(-1, 0, 0), -20), new Plane(new Vector3(0, 1, 0), -20), new Plane(new Vector3(0, -1, 0), -20), new Plane(new Vector3(0, 0, 1), -20), new Plane(new Vector3(0, 0, -1), -20)); Vector3Tests.TestFrustumClipLine(frustum, new Vector3(-5, 0, 0), new Vector3(5, 0, 0), true, new Vector3(-5, 0, 0), new Vector3(5, 0, 0)); Vector3Tests.TestFrustumClipLine(frustum, new Vector3(-50, 0, 0), new Vector3(-21, 0, 0), false, null, null); Vector3Tests.TestFrustumClipLine(frustum, new Vector3(-50, 0, 0), new Vector3(-19, 0, 0), true, new Vector3(-20, 0, 0), new Vector3(-19, 0, 0)); // moved right { Frustum movedRightFrustum = Frustum.Transform(frustum, Matrix4X4.CreateTranslation(10, 0, 0)); Assert.IsTrue(movedRightFrustum.Planes[0] == new Plane(new Vector3(1, 0, 0), -10)); Assert.IsTrue(movedRightFrustum.Planes[1] == new Plane(new Vector3(-1, 0, 0), -30)); Assert.IsTrue(movedRightFrustum.Planes[2] == frustum.Planes[2]); Assert.IsTrue(movedRightFrustum.Planes[3] == frustum.Planes[3]); Assert.IsTrue(movedRightFrustum.Planes[4] == frustum.Planes[4]); Assert.IsTrue(movedRightFrustum.Planes[5] == frustum.Planes[5]); Vector3Tests.TestFrustumClipLine(movedRightFrustum, new Vector3(-5, 0, 0), new Vector3(5, 0, 0), true, new Vector3(-5, 0, 0), new Vector3(5, 0, 0)); Vector3Tests.TestFrustumClipLine(movedRightFrustum, new Vector3(-50, 0, 0), new Vector3(-11, 0, 0), false, null, null); Vector3Tests.TestFrustumClipLine(movedRightFrustum, new Vector3(-50, 0, 0), new Vector3(-9, 0, 0), true, new Vector3(-10, 0, 0), new Vector3(-9, 0, 0)); } // rotated right { Frustum movedRightFrustum = Frustum.Transform(frustum, Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(45))); Matrix4X4 testMatrix = Matrix4X4.CreateRotationY(MathHelper.DegreesToRadians(45)); Plane control = new Plane(Vector3Ex.TransformNormal(frustum.Planes[0].Normal, testMatrix), frustum.Planes[0].DistanceFromOrigin); Assert.IsTrue(movedRightFrustum.Planes[0].Equals(control, .001, .01)); Assert.IsTrue(movedRightFrustum.Planes[1].Equals(new Plane(Vector3Ex.TransformNormal(frustum.Planes[1].Normal, testMatrix), frustum.Planes[1].DistanceFromOrigin))); Assert.IsTrue(movedRightFrustum.Planes[2].Equals(frustum.Planes[2])); Assert.IsTrue(movedRightFrustum.Planes[3].Equals(frustum.Planes[3])); Assert.IsTrue(movedRightFrustum.Planes[4].Equals(new Plane(Vector3Ex.TransformNormal(frustum.Planes[4].Normal, testMatrix), frustum.Planes[4].DistanceFromOrigin))); Assert.IsTrue(movedRightFrustum.Planes[5].Equals(new Plane(Vector3Ex.TransformNormal(frustum.Planes[5].Normal, testMatrix), frustum.Planes[5].DistanceFromOrigin))); } } // rotate about y 180 degrees { Matrix4X4 perspectiveMatrix = Matrix4X4.CreatePerspectiveFieldOfView(MathHelper.Tau / 4, 1, 3, 507); Frustum perspectiveFrustum = Frustum.FrustumFromProjectionMatrix(perspectiveMatrix); Vector3Tests.TestFrustumClipLine(perspectiveFrustum, new Vector3(-10, 0, -5), new Vector3(0, 0, -5), true, new Vector3(-5, 0, -5), new Vector3(0, 0, -5)); Vector3Tests.TestFrustumClipLine(perspectiveFrustum, new Vector3(-50, 0, -5), new Vector3(-21, 0, -5), false, null, null); Vector3Tests.TestFrustumClipLine(perspectiveFrustum, new Vector3(-50, 0, -20), new Vector3(-19, 0, -20), true, new Vector3(-20, 0, -20), new Vector3(-19, 0, -20)); var frustum = Frustum.Transform(perspectiveFrustum, Matrix4X4.CreateRotationY(MathHelper.Tau / 2)); // left Assert.IsTrue(frustum.Planes[0].Normal.Equals(new Vector3(-1, 0, 1).GetNormal(), .0001)); Assert.AreEqual(frustum.Planes[0].DistanceFromOrigin, 0, .0001); // right Assert.IsTrue(frustum.Planes[1].Normal.Equals(new Vector3(1, 0, 1).GetNormal(), .0001)); Assert.AreEqual(frustum.Planes[1].DistanceFromOrigin, 0, .0001); // bottom Assert.IsTrue(frustum.Planes[2].Normal.Equals(new Vector3(0, 1, 1).GetNormal(), .0001)); Assert.AreEqual(frustum.Planes[2].DistanceFromOrigin, 0, .0001); // top Assert.IsTrue(frustum.Planes[3].Normal.Equals(new Vector3(0, -1, 1).GetNormal(), .0001)); Assert.AreEqual(frustum.Planes[3].DistanceFromOrigin, 0, .0001); // near Assert.IsTrue(frustum.Planes[4].Normal.Equals(new Vector3(0, 0, 1), .0001)); Assert.AreEqual(frustum.Planes[4].DistanceFromOrigin, 3, .0001); // far Assert.IsTrue(frustum.Planes[5].Normal.Equals(new Vector3(0, 0, -1), .0001)); Assert.AreEqual(frustum.Planes[5].DistanceFromOrigin, -507, .0001); } // translate 10 down z { double zMove = 10; Matrix4X4 perspectiveMatrix = Matrix4X4.CreatePerspectiveFieldOfView(MathHelper.Tau / 4, 1, 3, 507); Frustum frustum = Frustum.FrustumFromProjectionMatrix(perspectiveMatrix); frustum = Frustum.Transform(frustum, Matrix4X4.CreateTranslation(0, 0, -10)); double expectedPlaneOffset = Math.Sqrt(2 * (zMove / 2) * (zMove / 2)); // left Assert.IsTrue(frustum.Planes[0].Normal.Equals(new Vector3(1, 0, -1).GetNormal(), .0001)); Assert.AreEqual(expectedPlaneOffset, frustum.Planes[0].DistanceFromOrigin, .0001); // right Assert.IsTrue(frustum.Planes[1].Normal.Equals(new Vector3(-1, 0, -1).GetNormal(), .0001)); Assert.AreEqual(expectedPlaneOffset, frustum.Planes[1].DistanceFromOrigin, .0001); // bottom Assert.IsTrue(frustum.Planes[2].Normal.Equals(new Vector3(0, 1, -1).GetNormal(), .0001)); Assert.AreEqual(expectedPlaneOffset, frustum.Planes[2].DistanceFromOrigin, .0001); // top Assert.IsTrue(frustum.Planes[3].Normal.Equals(new Vector3(0, -1, -1).GetNormal(), .0001)); Assert.AreEqual(expectedPlaneOffset, frustum.Planes[3].DistanceFromOrigin, .0001); // near Assert.IsTrue(frustum.Planes[4].Normal.Equals(new Vector3(0, 0, -1), .0001)); Assert.AreEqual(frustum.Planes[4].DistanceFromOrigin, 3 + zMove, .0001); // far Assert.IsTrue(frustum.Planes[5].Normal.Equals(new Vector3(0, 0, 1), .0001)); Assert.AreEqual(frustum.Planes[5].DistanceFromOrigin, -507 - zMove, .0001); } }
// Main display routine public void glutDisplayFunc(WorldView worldView, IObject3D item) { var mesh = item.Mesh; var meshVao = GLMeshVertexArrayObjectPlugin.Get(mesh); GL.PushAttrib(AttribMask.EnableBit | AttribMask.ViewportBit | AttribMask.TransformBit); // Projection and modelview matrices float near = 0.01f; float far = 20; var top = Math.Tan(35.0 / 360.0 * Math.PI) * near; var right = top * w / h; var proj = Matrix4X4.Frustum(-right, right, -top, top, near, far); // spin around var model = Matrix4X4.CreateRotationY(Math.PI / 180.0 * count++) * Matrix4X4.CreateTranslation(0, 0, -1.5); //proj = worldView.ProjectionMatrix; //model = worldView.ModelviewMatrix; gl.Enable(GL.DEPTH_TEST); gl.Viewport(0, 0, w, h); // select program and attach uniforms gl.UseProgram(scene_p_id); int proj_loc = gl.GetUniformLocation(scene_p_id, "proj"); gl.UniformMatrix4fv(proj_loc, 1, GL.FALSE, proj.GetAsFloatArray()); int model_loc = gl.GetUniformLocation(scene_p_id, "model"); gl.UniformMatrix4fv(model_loc, 1, GL.FALSE, model.GetAsFloatArray()); gl.Uniform1f(gl.GetUniformLocation(scene_p_id, "width"), w); gl.Uniform1f(gl.GetUniformLocation(scene_p_id, "height"), h); gl.BindVertexArray(meshVao.Vao); gl.Disable(GL.BLEND); for (int pass = 0; pass < renderPasses; pass++) { int first_pass = pass == 0 ? 1 : 0; gl.Uniform1i(gl.GetUniformLocation(scene_p_id, "first_pass"), first_pass); if (first_pass == 0) { gl.Uniform1i(gl.GetUniformLocation(scene_p_id, "depth_texture"), 0); gl.ActiveTexture(GL.TEXTURE0 + 0); GL.BindTexture(TextureTarget.Texture2D, depthTexture[pass - 1]); } gl.BindFramebuffer(GL.FRAMEBUFFER, frameBufferObject[pass]); gl.ClearColor(0.0, 0.4, 0.7, 0.0); gl.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); gl.DrawElements(GL.TRIANGLES, mesh.Faces.Count * 3, GL.UNSIGNED_INT, IntPtr.Zero); } // clean up and set to render to screen gl.BindVertexArray(0); gl.BindFramebuffer(GL.FRAMEBUFFER, 0); gl.ActiveTexture(GL.TEXTURE0 + 0); GL.BindTexture(TextureTarget.Texture2D, 0); gl.ClearColor(0.0, 0.4, 0.7, 0.0); gl.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT); for (int pass = 0; pass < renderPasses; pass++) { RenderLayer(pass); } RenderFinal(); gl.DepthFunc(GL.LESS); GL.PopAttrib(); gl.BindVertexArray(0); GL.BindTexture(TextureTarget.Texture2D, 0); gl.UseProgram(0); }
private static void AddRevolveStrip(IVertexSource vertexSource, Mesh mesh, double startAngle, double endAngle, bool revolveAroundZ) { Vector3 lastPosition = Vector3.Zero; Vector3 firstPosition = Vector3.Zero; foreach (var vertexData in vertexSource.Vertices()) { if (vertexData.IsStop) { break; } if (vertexData.IsMoveTo) { firstPosition = new Vector3(vertexData.position.X, 0, vertexData.position.Y); if (!revolveAroundZ) { firstPosition = new Vector3(vertexData.position.X, vertexData.position.Y, 0); } lastPosition = firstPosition; } if (vertexData.IsLineTo || vertexData.IsClose) { var currentPosition = new Vector3(vertexData.position.X, 0, vertexData.position.Y); if (!revolveAroundZ) { currentPosition = new Vector3(vertexData.position.X, vertexData.position.Y, 0); } if (vertexData.IsClose) { currentPosition = firstPosition; } if (currentPosition.X != 0 || lastPosition.X != 0) { if (revolveAroundZ) { mesh.CreateFace(new Vector3[] { Vector3Ex.Transform(currentPosition, Matrix4X4.CreateRotationZ(endAngle)), Vector3Ex.Transform(currentPosition, Matrix4X4.CreateRotationZ(startAngle)), Vector3Ex.Transform(lastPosition, Matrix4X4.CreateRotationZ(startAngle)), Vector3Ex.Transform(lastPosition, Matrix4X4.CreateRotationZ(endAngle)), }); } else { mesh.CreateFace(new Vector3[] { Vector3Ex.Transform(currentPosition, Matrix4X4.CreateRotationY(endAngle)), Vector3Ex.Transform(currentPosition, Matrix4X4.CreateRotationY(startAngle)), Vector3Ex.Transform(lastPosition, Matrix4X4.CreateRotationY(startAngle)), Vector3Ex.Transform(lastPosition, Matrix4X4.CreateRotationY(endAngle)), }); } } lastPosition = currentPosition; } } }
public static Mesh Revolve(this IVertexSource source, int angleSteps = 30, double angleStart = 0, double angleEnd = MathHelper.Tau, bool revolveAroundZ = true) { angleStart = MathHelper.Range0ToTau(angleStart); angleEnd = MathHelper.Range0ToTau(angleEnd); // make sure we close 360 shapes angleStart = fixCloseAngles(angleStart); angleEnd = fixCloseAngles(angleEnd); if (angleStart == 0 && angleEnd == MathHelper.Tau) { angleSteps = Math.Max(angleSteps, 3); } else { angleSteps = Math.Max(angleSteps, 1); } // convert to clipper polygons and scale so we can ensure good shapes Polygons polygons = source.CreatePolygons(); if (polygons.Select(poly => poly.Where(pos => pos.X < 0)).Any()) { // ensure good winding and consistent shapes polygons = polygons.GetCorrectedWinding(); var bounds = polygons.GetBounds(); bounds.Inflate(10); // clip against x=0 left and right var leftClip = new Polygon(); leftClip.Add(new IntPoint(0, bounds.Bottom)); leftClip.Add(new IntPoint(0, bounds.Top)); leftClip.Add(new IntPoint(bounds.Left, bounds.Top)); leftClip.Add(new IntPoint(bounds.Left, bounds.Bottom)); var rightStuff = polygons.Subtract(leftClip); var rightClip = new Polygon(); rightClip.Add(new IntPoint(0, bounds.Top)); rightClip.Add(new IntPoint(0, bounds.Bottom)); rightClip.Add(new IntPoint(bounds.Right, bounds.Bottom)); rightClip.Add(new IntPoint(bounds.Right, bounds.Top)); var leftStuff = polygons.Subtract(rightClip); // mirror left material across the origin var leftAdd = leftStuff.Scale(-1, 1); if (leftAdd.Count > 0) { if (rightStuff.Count > 0) { polygons = rightStuff.Union(leftAdd); } else { polygons = leftAdd; } } else { // there is nothing on the left polygons = rightStuff; } } // convert the data back to PathStorage VertexStorage cleanedPath = polygons.CreateVertexStorage(); var mesh = new Mesh(); var hasStartAndEndFaces = angleStart > 0.000001; hasStartAndEndFaces |= angleEnd < MathHelper.Tau - 0.000001; // check if we need to make closing faces if (hasStartAndEndFaces) { // make a face for the start Mesh extrudedVertexSource = cleanedPath.TriangulateFaces(); if (revolveAroundZ) { extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(angleStart)); } else { extrudedVertexSource.Transform(Matrix4X4.CreateRotationY(angleStart)); } mesh.CopyFaces(extrudedVertexSource); } // make the outside shell double angleDelta = (angleEnd - angleStart) / angleSteps; double currentAngle = angleStart; if (!hasStartAndEndFaces) { angleSteps--; } for (int i = 0; i < angleSteps; i++) { AddRevolveStrip(cleanedPath, mesh, currentAngle, currentAngle + angleDelta, revolveAroundZ); currentAngle += angleDelta; } if (!hasStartAndEndFaces) { if (((angleEnd - angleStart) < .0000001 || (angleEnd - MathHelper.Tau - angleStart) < .0000001) && (angleEnd - currentAngle) > .0000001) { // make sure we close the shape exactly AddRevolveStrip(cleanedPath, mesh, currentAngle, angleStart, revolveAroundZ); } } else // add the end face { // make a face for the end Mesh extrudedVertexSource = cleanedPath.TriangulateFaces(); if (revolveAroundZ) { extrudedVertexSource.Transform(Matrix4X4.CreateRotationX(MathHelper.Tau / 4)); extrudedVertexSource.Transform(Matrix4X4.CreateRotationZ(currentAngle)); } else { extrudedVertexSource.Transform(Matrix4X4.CreateRotationY(angleStart)); } extrudedVertexSource.ReverseFaces(); mesh.CopyFaces(extrudedVertexSource); } mesh.CleanAndMerge(); // return the completed mesh return(mesh); }