/// <summary> /// edge p0 -> p1 is Anti aliased the others are not /// </summary> /// <param name="aaEdgeP0"></param> /// <param name="aaEdgeP1"></param> /// <param name="nonAaPoint"></param> public void Draw1EdgeTriangle(Vector2 aaEdgeP0, Vector2 aaEdgeP1, Vector2 nonAaPoint) { if (aaEdgeP0 == aaEdgeP1 || aaEdgeP1 == nonAaPoint || nonAaPoint == aaEdgeP0) { return; } Vector2 edgeP0P1Vector = aaEdgeP1 - aaEdgeP0; Vector2 edgeP0P1Normal = edgeP0P1Vector; edgeP0P1Normal.Normalize(); Vector2 normal = edgeP0P1Normal.GetPerpendicularRight(); double edgeDotP3 = Vector2.Dot(normal, nonAaPoint - aaEdgeP0); if (edgeDotP3 < 0) { edgeDotP3 = -edgeDotP3; } else { normal = -normal; } Vector2 edgeP0Offset; Vector2 edgeP1Offset; if (world != null) { // If world reference available, adjust the offset distance to screen space double unitsPerPixel; unitsPerPixel = world.GetWorldUnitsPerScreenPixelAtPosition(new Vector3(aaEdgeP0)); edgeP0Offset = aaEdgeP0 + (normal * unitsPerPixel); unitsPerPixel = world.GetWorldUnitsPerScreenPixelAtPosition(new Vector3(aaEdgeP1)); edgeP1Offset = aaEdgeP1 + (normal * unitsPerPixel); } else { edgeP0Offset = aaEdgeP0 + normal; edgeP1Offset = aaEdgeP1 + normal; } Vector2 texP0 = new Vector2(1 / 1023.0, .25); Vector2 texP1 = new Vector2(1 / 1023.0, .75); Vector2 texP2 = new Vector2((1 + edgeDotP3) / 1023.0, .25); Vector2 texEdgeP0Offset = new Vector2(0, .25); Vector2 texEdgeP1Offset = new Vector2(0, .75); FanStart(texP0, aaEdgeP0, texEdgeP0Offset, edgeP0Offset); FanDo(texEdgeP1Offset, edgeP1Offset); FanDo(texP1, aaEdgeP1); FanDo(texP2, nonAaPoint); }
public void WorldViewPerspectiveProjectionTests() { var world = new WorldView(1, 1); Assert.IsTrue(world.EyePosition.Equals(Vector3.UnitZ * 7, 1e-3)); world.CalculatePerspectiveMatrixOffCenter(567, 123, -200, 5, 55); Assert.IsTrue(world.GetScreenPosition(new Vector3(0, 0, 0)).Equals(new Vector2((567 - 200) / 2.0, 123 / 2.0), 1e-3)); Assert.AreEqual(5, world.NearZ, 1e-3); Assert.AreEqual(55, world.FarZ, 1e-3); Assert.AreEqual(4.14213562373095, world.NearPlaneHeightInViewspace, 1e-3); var ray = world.GetRayForLocalBounds(new Vector2((567 - 200) / 2.0, 123)); // top center Assert.AreEqual(WorldView.DefaultPerspectiveVFOVDegrees / 2, MathHelper.RadiansToDegrees(Math.Atan2(ray.directionNormal.Y, -ray.directionNormal.Z)), 1e-3); Assert.IsTrue((Vector3.UnitZ * 7).Equals(ray.origin, 1e-3)); Assert.AreEqual(world.NearPlaneHeightInViewspace * 2, world.GetViewspaceHeightAtPosition(new Vector3(1, 1, -10)), 1e-3); world.Scale = 3; Assert.AreEqual(world.NearPlaneHeightInViewspace * 2 / 3, world.GetWorldUnitsPerScreenPixelAtPosition(new Vector3(1, 1, (7 - 10) / 3.0)) * 123, 1e-3); }
public void WorldViewOrthographicProjectionTests() { var world = new WorldView(1, 1); Assert.IsTrue(world.EyePosition.Equals(Vector3.UnitZ * 7, 1e-3)); world.CalculateOrthogrphicMatrixOffCenterWithViewspaceHeight(680, 240, -200, 128, 5, 55); Assert.IsTrue(world.GetScreenPosition(new Vector3(0, 0, 0)).Equals(new Vector2((680 - 200) / 2.0, 240 / 2.0), 1e-3)); Assert.IsTrue(world.GetScreenPosition(new Vector3(128, 64, 0)).Equals(new Vector2(680 - 200, 240), 1e-3)); Assert.IsTrue(world.GetScreenPosition(new Vector3(-128, -64, 0)).Equals(new Vector2(0, 0), 1e-3)); Assert.AreEqual(5, world.NearZ, 1e-3); Assert.AreEqual(55, world.FarZ, 1e-3); Assert.AreEqual(128, world.NearPlaneHeightInViewspace, 1e-3); var ray = world.GetRayForLocalBounds(new Vector2((680 - 200) / 2.0, 240)); // top center Assert.IsTrue(Vector3.UnitZ.Equals(-ray.directionNormal.GetNormal(), 1e-3)); Assert.IsTrue(new Vector3(0, 64, 2).Equals(ray.origin, 1e-3)); Assert.AreEqual(world.NearPlaneHeightInViewspace, world.GetViewspaceHeightAtPosition(new Vector3(1, 1, -10)), 1e-3); world.Scale = 3; Assert.AreEqual(world.NearPlaneHeightInViewspace / 3, world.GetWorldUnitsPerScreenPixelAtPosition(new Vector3(1, 1, (7 - 10) / 3.0)) * 240, 1e-3); }
private void RenderSelection(IObject3D item, Color selectionColor, WorldView world) { if (item.Mesh == null) { return; } // Turn off lighting GL.Disable(EnableCap.Lighting); // Only render back faces GL.CullFace(CullFaceMode.Front); // Expand the object var worldMatrix = item.WorldMatrix(); var worldBounds = item.Mesh.GetAxisAlignedBoundingBox(worldMatrix); var worldCenter = worldBounds.Center; double distBetweenPixelsWorldSpace = world.GetWorldUnitsPerScreenPixelAtPosition(worldCenter); var pixelsAccross = worldBounds.Size / distBetweenPixelsWorldSpace; var pixelsWant = pixelsAccross + Vector3.One * 4 * Math.Sqrt(2); var wantMm = pixelsWant * distBetweenPixelsWorldSpace; var scaleMatrix = worldMatrix.ApplyAtPosition(worldCenter, Matrix4X4.CreateScale( wantMm.X / worldBounds.XSize, wantMm.Y / worldBounds.YSize, wantMm.Z / worldBounds.ZSize)); GLHelper.Render(item.Mesh, selectionColor, scaleMatrix, RenderTypes.Shaded, null, darkWireframe); // restore settings GL.CullFace(CullFaceMode.Back); GL.Enable(EnableCap.Lighting); }
public static void Render3DLineNoPrep(this WorldView world, Frustum clippingFrustum, Vector3 start, Vector3 end, Color color, double width = 1) { if (clippingFrustum.ClipLine(ref start, ref end)) { double unitsPerPixelStart = world.GetWorldUnitsPerScreenPixelAtPosition(start); double unitsPerPixelEnd = world.GetWorldUnitsPerScreenPixelAtPosition(end); Vector3 delta = start - end; var deltaLength = delta.Length; Matrix4X4 rotateTransform = Matrix4X4.CreateRotation(new Quaternion(Vector3.UnitX + new Vector3(.0001, -.00001, .00002), -delta / deltaLength)); Matrix4X4 scaleTransform = Matrix4X4.CreateScale(deltaLength, 1, 1); Vector3 lineCenter = (start + end) / 2; Matrix4X4 lineTransform = scaleTransform * rotateTransform * Matrix4X4.CreateTranslation(lineCenter); var startScale = unitsPerPixelStart * width; var endScale = unitsPerPixelEnd * width; for (int i = 0; i < unscaledLineMesh.Vertices.Count; i++) { var vertexPosition = unscaledLineMesh.Vertices[i]; if (vertexPosition.X < 0) { scaledLineMesh.Vertices[i] = new Vector3Float(vertexPosition.X, vertexPosition.Y * startScale, vertexPosition.Z * startScale); } else { scaledLineMesh.Vertices[i] = new Vector3Float(vertexPosition.X, vertexPosition.Y * endScale, vertexPosition.Z * endScale); } } if (true) { GL.Color4(color.Red0To255, color.Green0To255, color.Blue0To255, color.Alpha0To255); if (color.Alpha0To1 < 1) { GL.Enable(EnableCap.Blend); } else { //GL.Disable(EnableCap.Blend); } GL.MatrixMode(MatrixMode.Modelview); GL.PushMatrix(); GL.MultMatrix(lineTransform.GetAsFloatArray()); GL.Begin(BeginMode.Triangles); for (int faceIndex = 0; faceIndex < scaledLineMesh.Faces.Count; faceIndex++) { var face = scaledLineMesh.Faces[faceIndex]; var vertices = scaledLineMesh.Vertices; var position = vertices[face.v0]; GL.Vertex3(position.X, position.Y, position.Z); position = vertices[face.v1]; GL.Vertex3(position.X, position.Y, position.Z); position = vertices[face.v2]; GL.Vertex3(position.X, position.Y, position.Z); } GL.End(); GL.PopMatrix(); } else { scaledLineMesh.MarkAsChanged(); GLHelper.Render(scaledLineMesh, color, lineTransform, RenderTypes.Shaded); } } }
public static void Render3DLineNoPrep(this WorldView world, Frustum clippingFrustum, Vector3 start, Vector3 end, Color color, double width = 1, bool startArrow = false, bool endArrow = false) { if (clippingFrustum.ClipLine(ref start, ref end)) { double startScale = world.GetWorldUnitsPerScreenPixelAtPosition(start); double endScale = world.GetWorldUnitsPerScreenPixelAtPosition(end); Vector3 delta = start - end; var normal = delta.GetNormal(); var arrowWidth = 3 * width; var arrowLength = 6 * width; if (startArrow || endArrow) { // move the start and end points if (startArrow) { start -= normal * startScale * arrowLength; } if (endArrow) { end += normal * endScale * arrowLength; } delta = start - end; } var deltaLength = delta.Length; var rotateTransform = Matrix4X4.CreateRotation(new Quaternion(Vector3.UnitX + new Vector3(.0001, -.00001, .00002), -delta / deltaLength)); var scaleTransform = Matrix4X4.CreateScale(deltaLength, 1, 1); Vector3 lineCenter = (start + end) / 2; Matrix4X4 lineTransform = scaleTransform * rotateTransform * Matrix4X4.CreateTranslation(lineCenter); var startWidth = startScale * width; var endWidth = endScale * width; for (int i = 0; i < unscaledLineMesh.Vertices.Count; i++) { var vertexPosition = unscaledLineMesh.Vertices[i]; if (vertexPosition.X < 0) { scaledLineMesh.Vertices[i] = new Vector3Float(vertexPosition.X, vertexPosition.Y * startWidth, vertexPosition.Z * startWidth); } else { scaledLineMesh.Vertices[i] = new Vector3Float(vertexPosition.X, vertexPosition.Y * endWidth, vertexPosition.Z * endWidth); } } // render the line mesh directly GL.Color4(color.Red0To255, color.Green0To255, color.Blue0To255, color.Alpha0To255); GL.Enable(EnableCap.Blend); GL.MatrixMode(MatrixMode.Modelview); GL.PushMatrix(); GL.MultMatrix(lineTransform.GetAsFloatArray()); GL.Begin(BeginMode.Triangles); for (int faceIndex = 0; faceIndex < scaledLineMesh.Faces.Count; faceIndex++) { var face = scaledLineMesh.Faces[faceIndex]; var vertices = scaledLineMesh.Vertices; var position = vertices[face.v0]; GL.Vertex3(position.X, position.Y, position.Z); position = vertices[face.v1]; GL.Vertex3(position.X, position.Y, position.Z); position = vertices[face.v2]; GL.Vertex3(position.X, position.Y, position.Z); } GL.End(); GL.PopMatrix(); // render the arrows if any if (startArrow) { RenderHead(start, startScale, normal, arrowWidth, arrowLength, false); } if (endArrow) { RenderHead(end, startScale, normal, arrowWidth, arrowLength, true); } } }