private void Render(GeometryModel3D model) { if (model.Geometry is MeshGeometry3D) { // Project geometry into a list of triangles ProjectedGeometry pg = MeshToProjectedGeometry((MeshGeometry3D)model.Geometry, model.Transform); // Remember the view matrix for view space lighting Matrix3D view = MatrixUtils.ViewMatrix(camera); // Render back faces RenderGeometry(pg, view, model.BackMaterial, VisibleFaces.Back); // Render front faces RenderGeometry(pg, view, model.Material, VisibleFaces.Front); } else if (model.Geometry == null) { // do nothing } else { throw new NotSupportedException("I cannot render Geometry3D of type: " + model.Geometry.GetType()); } }
private void Render(ScreenSpaceLines3D lines) { ProjectedGeometry geometry = MagicLinesToProjectedGeometry(lines, lines.Transform); Shader shader = new ScreenSpaceLinesShader(geometry.FrontFaceTriangles, buffer); shader.Rasterize(bounds.RenderBounds); // SSL are always front facing ( CCW winding ) triangles RenderSilhouetteTolerance(geometry, buffer, VisibleFaces.Front); }
private void RenderGeometry(ProjectedGeometry pg, Matrix3D view, Material material, VisibleFaces faces) { if (material == null) { return; } Triangle[] triangles = null; // Choose list based on triangle winding/facing switch (faces) { case VisibleFaces.Front: triangles = pg.FrontFaceTriangles; break; case VisibleFaces.Back: triangles = pg.BackFaceTriangles; break; default: throw new NotSupportedException("Cannot render these type of faces: " + faces.ToString()); } // We should only look into materials if we have any geometry to render. // Doing otherwise will throw exceptions when trying to use screen-space // bounds or UV coordinates. if (triangles.Length > 0) { // Create a flat, ordered list of textures to apply to this model List <Material> materials = ExtractMaterials(material); // Create a list of textures from the materials TextureFilter[] textures = TextureFilter.CreateTextures( materials, pg.OriginalMinUV, pg.OriginalMaxUV, Rect.Intersect(bounds.RenderBounds, pg.ScreenSpaceBounds)); // Use a precomputed light shader Shader shader = null; if (interpolation == InterpolationMode.Phong) { shader = new PrecomputedPhongShader(triangles, buffer, lights, textures, view); } else { shader = new PrecomputedGouraudShader(triangles, buffer, lights, textures, view); } shader.Rasterize(bounds.RenderBounds); RenderSilhouetteTolerance(pg, buffer, faces); } }
private void RenderSilhouetteTolerance(ProjectedGeometry geometry, RenderBuffer rasterization, VisibleFaces faces) { List <Edge> silhouetteEdges = null; // Choose list based on triangle winding/facing switch (faces) { case VisibleFaces.Front: silhouetteEdges = geometry.FrontFaceSilhouetteEdges; break; case VisibleFaces.Back: silhouetteEdges = geometry.BackFaceSilhouetteEdges; break; default: throw new NotSupportedException("Cannot render these type of faces: " + faces); } // Outline edge detection if (RenderTolerance.SilhouetteEdgeTolerance > 0) { // Create a set of triangles that will draw lines on the tolerance buffer SilhouetteEdgeTriangle[] edgeTriangles = new SilhouetteEdgeTriangle[2 * silhouetteEdges.Count]; int count = 0; //double the silhouette pixel tolerance in nonstandard DPI scenario. //This compensates for differences in anti-aliasing sampling patterns in high and low DPI double tolerance = RenderTolerance.SilhouetteEdgeTolerance; if (!RenderTolerance.IsSquare96Dpi) { tolerance *= 4; } foreach (Edge edge in silhouetteEdges) { // FWD triangle edgeTriangles[count++] = new SilhouetteEdgeTriangle(edge.Start, edge.End, tolerance); // BWD triangle edgeTriangles[count++] = new SilhouetteEdgeTriangle(edge.End, edge.Start, tolerance); } // Render our ignore geometry onto the tolerance buffer. RenderToToleranceShader edgeIgnore = new RenderToToleranceShader(edgeTriangles, rasterization); edgeIgnore.Rasterize(bounds.RenderBounds); } }
internal MeshGeometry3D ExtractTrianglesAtPoints( MeshGeometry3D mesh, Transform3D tx, Point[] selectionPoints) { ProjectedGeometry pg = MeshToProjectedGeometry(mesh, tx); MeshGeometry3D outputMesh = new MeshGeometry3D(); foreach (Triangle t in pg.FrontFaceTriangles) { foreach (Point p in selectionPoints) { if (t.Bounds.Contains(p.X + pixelCenterX, p.Y + pixelCenterY) && t.Contains(p.X + pixelCenterX, p.Y + pixelCenterY)) { t.SaveToMesh(outputMesh); // saving the triangle once is enough break; } } } foreach (Triangle t in pg.BackFaceTriangles) { foreach (Point p in selectionPoints) { if (t.Bounds.Contains(p.X + pixelCenterX, p.Y + pixelCenterY) && t.Contains(p.X + pixelCenterX, p.Y + pixelCenterY)) { // Back facing ... flip normals t.vertex1.Normal *= -1; t.vertex2.Normal *= -1; t.vertex3.Normal *= -1; t.SaveToMesh(outputMesh); // saving the triangle once is enough break; } } } return(outputMesh); }