/// <summary> /// Calculates the normal vectors. /// </summary> /// <param name="positions"> /// The positions. /// </param> /// <param name="triangleIndices"> /// The triangle indices. /// </param> /// <returns> /// Collection of normal vectors. /// </returns> public static Vector3DCollection CalculateNormals(IList<Point3D> positions, IList<int> triangleIndices) { var normals = new Vector3DCollection(positions.Count); for (int i = 0; i < positions.Count; i++) { normals.Add(new Vector3D()); } for (int i = 0; i < triangleIndices.Count; i += 3) { int index0 = triangleIndices[i]; int index1 = triangleIndices[i + 1]; int index2 = triangleIndices[i + 2]; var p0 = positions[index0]; var p1 = positions[index1]; var p2 = positions[index2]; Vector3D u = p1 - p0; Vector3D v = p2 - p0; Vector3D w = Vector3D.CrossProduct(u, v); w.Normalize(); normals[index0] += w; normals[index1] += w; normals[index2] += w; } for (int i = 0; i < normals.Count; i++) { var w = normals[i]; w.Normalize(); normals[i] = w; } return normals; }
public static MeshGeometry3D CreateRectangle(double height, double width) { var vertices = new Point3DCollection(); var normals = new Vector3DCollection(); var facets = new Int32Collection(); var textureCoords = new PointCollection(); vertices.Add(new Point3D(-width / 2, 0, -height / 2)); vertices.Add(new Point3D(-width / 2, 0, height / 2)); vertices.Add(new Point3D(width / 2, 0, -height / 2)); vertices.Add(new Point3D(width / 2, 0, height / 2)); normals.Add(new Vector3D(0, -1, 0)); normals.Add(new Vector3D(0, -1, 0)); normals.Add(new Vector3D(0, -1, 0)); normals.Add(new Vector3D(0, -1, 0)); textureCoords.Add(new Point(1,1)); textureCoords.Add(new Point(1, 0)); textureCoords.Add(new Point(0,1)); textureCoords.Add(new Point(0,0)); facets.Add(0); facets.Add(1); facets.Add(2); facets.Add(3); facets.Add(2); facets.Add(1); var rectangle = new MeshGeometry3D(); rectangle.Positions = vertices; rectangle.Normals = normals; rectangle.TriangleIndices = facets; rectangle.TextureCoordinates = textureCoords; return rectangle; }
protected override void ProcessFigure(CircularList<Point> list, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { int offset = vertices.Count; for (int i = 0; i <= list.Count; i++) { Point pt = list[i]; // Set vertices. vertices.Add(new Point3D(pt.X, pt.Y, 0)); vertices.Add(new Point3D(pt.X, pt.Y, -Depth)); // Set texture coordinates. textures.Add(new Point((double)i / list.Count, 0)); textures.Add(new Point((double)i / list.Count, 1)); // Set triangle indices. if (i < list.Count) { indices.Add(offset + i * 2 + 0); indices.Add(offset + i * 2 + 2); indices.Add(offset + i * 2 + 1); indices.Add(offset + i * 2 + 1); indices.Add(offset + i * 2 + 2); indices.Add(offset + i * 2 + 3); } } }
protected override void Triangulate(DependencyPropertyChangedEventArgs args, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { vertices.Clear(); normals.Clear(); indices.Clear(); textures.Clear(); MeshGeometry3D mesh = MeshGenerator.Geometry; foreach (Point3D vertex in mesh.Positions) vertices.Add(vertex); foreach (Vector3D normal in mesh.Normals) normals.Add(normal); foreach (int index in mesh.TriangleIndices) indices.Add(index); foreach (Point texture in mesh.TextureCoordinates) textures.Add(texture); }
private static void AddCircleInZCross(MeshBuilder mb, Point3D centre, double radius, int div) { var points = MeshBuilder.GetCircle(div); var vectors = new Point3DCollection(); var normals = new Vector3DCollection(); var textures = new PointCollection(); vectors.Add(new Point3D(centre.X, centre.Y, 0)); normals.Add(new Vector3D(0, 0, 1)); textures.Add(new Point(0.5, 0.5)); for (int i = 0; i < points.Count - 1; i++) { vectors.Add(new Point3D(points[i].X * radius + centre.X, points[i].Y * radius + centre.Y, centre.Z)); normals.Add(new Vector3D(0, 0, -1)); textures.Add(new Point(points[i].X * 0.5 + 0.5, points[i].Y * 0.5 + 0.5)); vectors.Add(new Point3D(points[i + 1].X * radius + centre.X, points[i + 1].Y * radius + centre.Y, centre.Z)); normals.Add(new Vector3D(0, 0, 01)); textures.Add(new Point(points[i + 1].X * 0.5 + 0.5, points[i + 1].Y * 0.5 + 0.5)); } mb.AddTriangleFan(vectors, normals, textures); }
protected override void Triangulate( DependencyPropertyChangedEventArgs args, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { // Clear all four collections. vertices.Clear(); normals.Clear(); indices.Clear(); textures.Clear(); // Convert TextGeometry to series of closed polylines. PathGeometry path = TextGeometry.GetFlattenedPathGeometry(0.001, ToleranceType.Relative); foreach (PathFigure fig in path.Figures) { list.Clear(); list.Add(fig.StartPoint); foreach (PathSegment seg in fig.Segments) { if (seg is LineSegment) { LineSegment lineseg = seg as LineSegment; list.Add(lineseg.Point); } else if (seg is PolyLineSegment) { PolyLineSegment polyline = seg as PolyLineSegment; for (int i = 0; i < polyline.Points.Count; i++) list.Add(polyline.Points[i]); } } // Figure is complete. Post-processing follows. if (list.Count > 0) { // Remove last point if it's the same as the first. if (list[0] == list[list.Count - 1]) list.RemoveAt(list.Count - 1); // Convert points to Y increasing up. for (int i = 0; i < list.Count; i++) { Point pt = list[i]; pt.Y = 2 * Origin.Y - pt.Y; list[i] = pt; } // For each figure, process the points. ProcessFigure(list, vertices, normals, indices, textures); } } }
public Vector3DCollection GenerateNormals() { Vector3DCollection vectors=new Vector3DCollection(); Vector3D vector; for(int i=0;i<VertexNormals.Count;i++) { vector=new Vector3D(VertexNormals[i].Normal.X,VertexNormals[i].Normal.Y,VertexNormals[i].Normal.Z); vectors.Add(vector); } return vectors; }
public static Vector3DCollection GetVectorCollection(List<XbimVector3D> points) { var ret = new Vector3DCollection(points.Count); foreach (var enumPoint in points) { ret.Add(new Vector3D(enumPoint.X, enumPoint.Y, enumPoint.Z)); } return ret; }
internal Enumerator(Vector3DCollection list) { Debug.Assert(list != null, "list may not be null."); _list = list; _version = list._version; _index = -1; _current = default(Vector3D); }
/// <summary> /// Initializes a new instance of the <see cref="MeshBuilder"/> class. /// </summary> /// <param name="generateNormals">generate normals</param> /// <param name="generateTextureCoordinates">generate texture coordinates</param> public MeshBuilder(bool generateNormals, bool generateTextureCoordinates) { positions = new Point3DCollection(); triangleIndices = new Int32Collection(); if (generateNormals) normals = new Vector3DCollection(); if (generateTextureCoordinates) textureCoordinates = new PointCollection(); }
// ProcessFigure override. protected override void ProcessFigure(CircularList<Point> list, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { int k = Slices * list.Count; int offset = vertices.Count; for (int i = 0; i < list.Count; i++) { Point ptBefore = list[i - 1]; Point pt = list[i]; Point ptAfter = list[i + 1]; Vector v1 = pt - ptBefore; v1.Normalize(); Vector v1Rotated = new Vector(-v1.Y, v1.X); Vector v2 = ptAfter - pt; v2.Normalize(); Vector v2Rotated = new Vector(-v2.Y, v2.X); Line2D line1 = new Line2D(pt, ptBefore); Line2D line2 = new Line2D(pt, ptAfter); for (int slice = 0; slice < Slices; slice++) { // Angle ranges from 0 to 360 degrees. double angle = slice * 2 * Math.PI / Slices; double scale = EllipseWidth / 2 * Math.Sin(angle); double depth = -Depth / 2 * (1 - Math.Cos(angle)); Line2D line1Shifted = line1 + scale * v1Rotated; Line2D line2Shifted = line2 + scale * v2Rotated; Point ptIntersect = line1Shifted * line2Shifted; // Set vertex. vertices.Add(new Point3D(ptIntersect.X, ptIntersect.Y, depth)); // Set texture coordinate. textures.Add(new Point((double)i / list.Count, Math.Sin(angle / 2))); // Set triangle indices. indices.Add(offset + (Slices * i + slice + 0) % k); indices.Add(offset + (Slices * i + slice + 1) % k); indices.Add(offset + (Slices * i + slice + 0 + Slices) % k); indices.Add(offset + (Slices * i + slice + 0 + Slices) % k); indices.Add(offset + (Slices * i + slice + 1) % k); indices.Add(offset + (Slices * i + slice + 1 + Slices) % k); } } }
public VectorFieldVisual3D() { Positions = new Point3DCollection(); Directions = new Vector3DCollection(); Fill = Brushes.Blue; ThetaDiv = 37; Diameter = 1; HeadLength = 2; _element = new ModelVisual3D(); Children.Add(_element); }
public static Vector3DCollection CombineVectorCollection(Vector3DCollection initialVectors, List<XbimVector3D> points) { var ret = new Vector3DCollection(initialVectors.Count + points.Count); foreach (var enumVector in initialVectors) { ret.Add(enumVector); } foreach (var enumPoint in points) { ret.Add(new Vector3D(enumPoint.X, enumPoint.Y, enumPoint.Z)); } return ret; }
public TriangleMeshAdapater(MFnMesh mesh) { MIntArray indices = new MIntArray(); MIntArray triangleCounts = new MIntArray(); MPointArray points = new MPointArray(); mesh.getTriangles(triangleCounts, indices); mesh.getPoints(points); // Get the triangle indices Indices = new Int32Collection((int)indices.length); for (int i = 0; i < indices.length; ++i) Indices.Add(indices[i]); // Get the control points (vertices) Points = new Point3DCollection((int)points.length); for (int i = 0; i < (int)points.length; ++i) { MPoint pt = points[i]; Points.Add(new Point3D(pt.x, pt.y, pt.z)); } // Get the number of triangle faces and polygon faces Debug.Assert(indices.length % 3 == 0); int triFaces = (int)indices.length / 3; int polyFaces = mesh.numPolygons; // We have normals per polygon, we want one per triangle. Normals = new Vector3DCollection(triFaces); int nCurrentTriangle = 0; // Iterate over each polygon for (int i = 0; i < polyFaces; ++i) { // Get the polygon normal var maya_normal = new MVector(); mesh.getPolygonNormal((int)i, maya_normal); System.Windows.Media.Media3D.Vector3D normal = new System.Windows.Media.Media3D.Vector3D(maya_normal.x, maya_normal.y, maya_normal.z); // Iterate over each tri in the current polygon int nTrisAtFace = triangleCounts[i]; for (int j = 0; j < nTrisAtFace; ++j) { Debug.Assert(nCurrentTriangle < triFaces); Normals.Add(normal); nCurrentTriangle++; } } Debug.Assert(nCurrentTriangle == triFaces); }
/// <summary> /// Implementation of Freezable.GetCurrentValueAsFrozenCore() /// </summary> protected override void GetCurrentValueAsFrozenCore(Freezable source) { Vector3DCollection sourceVector3DCollection = (Vector3DCollection)source; base.GetCurrentValueAsFrozenCore(source); int count = sourceVector3DCollection._collection.Count; _collection = new FrugalStructList <Vector3D>(count); for (int i = 0; i < count; i++) { _collection.Add(sourceVector3DCollection._collection[i]); } }
public void updateMesh( Point3DCollection verticies, Vector3DCollection normals) { Int32Collection triangleIndices = new Int32Collection(); for (int i = 0; i < verticies.Count/3; i++) { triangleIndices.Add(i*3); triangleIndices.Add(i*3+1); triangleIndices.Add(i*3+2); } this.mesh.TriangleIndices = triangleIndices; this.mesh.Positions = verticies; this.mesh.Normals = normals; this.InvalidateVisual(); }
/// <summary> /// Attempts to convert to a Vector3DCollection from the given object. /// </summary> /// <returns> /// The Vector3DCollection which was constructed. /// </returns> /// <exception cref="NotSupportedException"> /// A NotSupportedException is thrown if the example object is null or is not a valid type /// which can be converted to a Vector3DCollection. /// </exception> /// <param name="context"> The ITypeDescriptorContext for this call. </param> /// <param name="culture"> The requested CultureInfo. Note that conversion uses "en-US" rather than this parameter. </param> /// <param name="value"> The object to convert to an instance of Vector3DCollection. </param> public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { if (value == null) { throw GetConvertFromException(value); } String source = value as string; if (source != null) { return(Vector3DCollection.Parse(source)); } return(base.ConvertFrom(context, culture, value)); }
/// <summary> /// /// </summary> /// <param name="args"></param> /// <param name="vertices"></param> /// <param name="normals"></param> /// <param name="indices"></param> /// <param name="textures"></param> protected override void Triangulate( DependencyPropertyChangedEventArgs args, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { // Clear all four collections. vertices.Clear(); normals.Clear(); indices.Clear(); textures.Clear(); // Fill the vertices, normals, and textures collections. for (int stack = 0; stack <= Stacks; stack++) { double y = Length - stack * Length / Stacks; for (int slice = 0; slice <= Slices; slice++) { double theta = slice * 2 * Math.PI / Slices; double x = -Radius * Math.Sin(theta); double z = -Radius * Math.Cos(theta); normals.Add(new Vector3D(x, 0, z)); vertices.Add(new Point3D(x, y, z)); textures.Add(new Point((double)slice / Slices, (double)stack / Stacks)); } } // Fill the indices collection. for (int stack = 0; stack < Stacks; stack++) { for (int slice = 0; slice < Slices; slice++) { indices.Add((stack + 0) * (Slices + 1) + slice); indices.Add((stack + 1) * (Slices + 1) + slice); indices.Add((stack + 0) * (Slices + 1) + slice + 1); indices.Add((stack + 0) * (Slices + 1) + slice + 1); indices.Add((stack + 1) * (Slices + 1) + slice); indices.Add((stack + 1) * (Slices + 1) + slice + 1); } } }
/// <summary> /// ConvertTo - Attempt to convert an instance of Vector3DCollection to the given type /// </summary> /// <returns> /// The object which was constructoed. /// </returns> /// <exception cref="NotSupportedException"> /// A NotSupportedException is thrown if "value" is null or not an instance of Vector3DCollection, /// or if the destinationType isn't one of the valid destination types. /// </exception> /// <param name="context"> The ITypeDescriptorContext for this call. </param> /// <param name="culture"> The CultureInfo which is respected when converting. </param> /// <param name="value"> The object to convert to an instance of "destinationType". </param> /// <param name="destinationType"> The type to which this will convert the Vector3DCollection instance. </param> public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) { if (destinationType != null && value is Vector3DCollection) { Vector3DCollection instance = (Vector3DCollection)value; if (destinationType == typeof(string)) { // Delegate to the formatting/culture-aware ConvertToString method. #pragma warning suppress 6506 // instance is obviously not null return(instance.ConvertToString(null, culture)); } } // Pass unhandled cases to base class (which will throw exceptions for null value or destinationType.) return(base.ConvertTo(context, culture, value, destinationType)); }
public ArrayList decode() { ArrayList array = new ArrayList(); _mesh = new Point3DCollection(); _normals = new Vector3DCollection(); array.Add(_mesh); array.Add(_normals); for (int i = 0; i < _parser.numTriangles; i++) { ArrayList collection = _parser.index(i); _mesh.Add((Point3D)collection[INDEX_VERTEX0]); _mesh.Add((Point3D)collection[INDEX_VERTEX1]); _mesh.Add((Point3D)collection[INDEX_VERTEX2]); _normals.Add((Vector3D)collection[INDEX_NORMAL]); } return array; }
[FriendAccessAllowed] // Built into Core, also used by Framework. internal static object DeserializeFrom(BinaryReader reader) { // Get the size. uint count = reader.ReadUInt32(); Vector3DCollection collection = new Vector3DCollection((int)count); for (uint i = 0; i < count; i++) { Vector3D point = new Vector3D( XamlSerializationHelper.ReadDouble(reader), XamlSerializationHelper.ReadDouble(reader), XamlSerializationHelper.ReadDouble(reader)); collection.Add(point); } return(collection); }
public static void AddGeometry(this ModelVisual3D visual, GeometryModel3D geometry) { if (visual.Content == null) visual.Content = geometry; else { if (visual.Content is Model3DGroup) { GeometryModel3D m3d = (GeometryModel3D)((Model3DGroup)visual.Content).Children.First(); MeshGeometry3D main = (MeshGeometry3D)(m3d.Geometry); MeshGeometry3D toAdd = (MeshGeometry3D)(geometry.Geometry); Point3DCollection pc = new Point3DCollection(main.Positions.Count + toAdd.Positions.Count); foreach (var pt in main.Positions) pc.Add(pt); foreach (var pt in toAdd.Positions) { pc.Add(geometry.Transform.Transform(pt)); } main.Positions = pc; Vector3DCollection vc = new Vector3DCollection(main.Normals.Count + toAdd.Normals.Count); foreach (var v in main.Normals) vc.Add(v); foreach (var norm in toAdd.Normals) vc.Add(norm); main.Normals = vc; int maxIndices = main.Positions.Count; //we need to increment all indices by this amount foreach (var i in toAdd.TriangleIndices) main.TriangleIndices.Add(i + maxIndices); Int32Collection tc = new Int32Collection(main.TriangleIndices.Count + toAdd.TriangleIndices.Count); foreach (var i in main.TriangleIndices) tc.Add(i); foreach (var i in toAdd.TriangleIndices) tc.Add(i + maxIndices); main.TriangleIndices = tc; } //it is not a group but now needs to be else { Model3DGroup m3dGroup = new Model3DGroup(); m3dGroup.Children.Add(visual.Content); m3dGroup.Children.Add(geometry); visual.Content = m3dGroup; } } }
[FriendAccessAllowed] // Built into Core, also used by Framework. internal static object DeserializeFrom(BinaryReader reader) { // Get the size. uint count = reader.ReadUInt32() ; Vector3DCollection collection = new Vector3DCollection( (int) count) ; for ( uint i = 0; i < count ; i ++ ) { Vector3D point = new Vector3D( XamlSerializationHelper.ReadDouble( reader ), XamlSerializationHelper.ReadDouble( reader ) , XamlSerializationHelper.ReadDouble( reader ) ) ; collection.Add( point ); } return collection ; }
/// <summary> /// Parse - returns an instance converted from the provided string /// using the current culture /// <param name="source"> string with Vector3DCollection data </param> /// </summary> public static Vector3DCollection Parse(string source) { IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; TokenizerHelper th = new TokenizerHelper(source, formatProvider); Vector3DCollection resource = new Vector3DCollection(); Vector3D value; while (th.NextToken()) { value = new Vector3D( Convert.ToDouble(th.GetCurrentToken(), formatProvider), Convert.ToDouble(th.NextTokenRequired(), formatProvider), Convert.ToDouble(th.NextTokenRequired(), formatProvider)); resource.Add(value); } return(resource); }
public static void AddCylindarZ(this MeshBuilder mb, Point3D bottomCentre, double radius, double length, int div) { var points = MeshBuilder.GetCircle(div); var vectors = new Point3DCollection(); var normals = new Vector3DCollection(); var textures = new PointCollection(); for (int i = 0; i < points.Count; i++) { var p = points[i]; vectors.Add(new Point3D(p.X * radius + bottomCentre.X, p.Y * radius + bottomCentre.Y, bottomCentre.Z)); vectors.Add(new Point3D(p.X * radius + bottomCentre.X, p.Y * radius + bottomCentre.Y, bottomCentre.Z + length)); normals.Add(new Vector3D(0, 0, 1)); normals.Add(new Vector3D(0, 0, 1)); textures.Add(new Point((double)i / (div - 1), 0)); textures.Add(new Point((double)i / (div - 1), 1)); } mb.AddTriangleStrip(vectors, normals, textures); }
public static void AddCircleInZCross(this MeshBuilder mb, Point3D centre, double radius, int div, bool reversed) { var points = MeshBuilder.GetCircle(div); var vectors = new Point3DCollection(); var normals = new Vector3DCollection(); var textures = new PointCollection(); vectors.Add(centre); normals.Add(new Vector3D(0, 0, 1)); textures.Add(new Point(0.5, 0.5)); for (int i = 0; i < points.Count; i++) { var p = reversed ? points[points.Count - 1 - i] : points[i]; vectors.Add(new Point3D(p.X * radius + centre.X, p.Y * radius + centre.Y, centre.Z)); normals.Add(new Vector3D(0, 0, -1)); textures.Add(new Point(p.X * 0.5 + 0.5, p.Y * 0.5 + 0.5)); } mb.AddTriangleFan(vectors, normals, textures); }
public static MeshGeometry3D CreateMesh(int xVertices, int yVertices) { Vector3DCollection normals = new Vector3DCollection(); PointCollection textCoords = new PointCollection(); for (int y = 0; y < yVertices; y++) { for (int x = 0; x < xVertices; x++) { // Normals Vector3D n1 = new Vector3D(0, 0, 1); normals.Add(n1); // Texture Coordinates textCoords.Add(GetTextureCoordinate(xVertices, yVertices, y, x)); } } Int32Collection indices = GetTriangleIndices(xVertices, yVertices); MeshGeometry3D mesh = new MeshGeometry3D(); mesh.Normals = normals; mesh.TriangleIndices = indices; mesh.TextureCoordinates = textCoords; return mesh; }
private Model3DGroup GenerateTileStitching(PointCloudTileSource tileSource, TileInfo3D tileInfo) { PointCloudTile tile = tileInfo.Tile; MeshGeometry3D mesh = GetTileMeshGeometry(tileInfo.CurrentGeometry); Grid<float> grid = tileInfo.CurrentGrid; //Model3DGroup stitchingGroup = new Model3DGroup(); bool hasTop = false; bool hasLeft = false; Point3D topCornerPoint = default(Point3D); Point3D leftCornerPoint = default(Point3D); Vector3D topCornerNormal = default(Vector3D); Vector3D leftCornerNormal = default(Vector3D); // connect to left tile (if available) if (tile.Col > 0) { PointCloudTile leftTile = tileSource.TileSet.GetTile(tile.Row, tile.Col - 1); TileInfo3D leftTileInfo = null; if (leftTile != null && m_tileInfo.TryGetValue(leftTile, out leftTileInfo) && leftTileInfo.CurrentGrid == grid) { MeshGeometry3D leftMesh = GetTileMeshGeometry(leftTileInfo.CurrentGeometry); int leftPositionsStart = leftMesh.Positions.Count - grid.SizeY; hasLeft = true; leftCornerPoint = leftMesh.Positions[leftPositionsStart]; leftCornerNormal = leftMesh.Normals[leftPositionsStart]; if (!tileInfo.HasStitching(TileStitchingEdge.Left)) { MeshGeometry3D stitchingMesh = new MeshGeometry3D(); int positionCount = grid.SizeY * 2; Point3DCollection positions = new Point3DCollection(positionCount); Vector3DCollection normals = new Vector3DCollection(positionCount); for (int edgePosition = 0; edgePosition < grid.SizeY; edgePosition++) { positions.Add(leftMesh.Positions[leftPositionsStart + edgePosition]); normals.Add(leftMesh.Normals[leftPositionsStart + edgePosition]); positions.Add(mesh.Positions[edgePosition]); normals.Add(mesh.Normals[edgePosition]); } stitchingMesh.Positions = positions; stitchingMesh.Normals = normals; Int32Collection indices = new Int32Collection((grid.SizeY - 1) * 6); for (int i = 0; i < grid.SizeY - 1; i++) { int j = 2 * i; indices.Add(j); indices.Add(j + 1); indices.Add(j + 2); indices.Add(j + 2); indices.Add(j + 1); indices.Add(j + 3); } stitchingMesh.TriangleIndices = indices; stitchingMesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(stitchingMesh, m_overallCenteredExtent, MathUtils.ZAxis); GeometryModel3D stitchingModel = new GeometryModel3D(stitchingMesh, m_overviewMaterial); stitchingModel.Freeze(); tileInfo.UpdateStitching(stitchingModel, leftTileInfo.CurrentGrid, TileStitchingEdge.Left); //stitchingGroup.Children.Add(stitchingModel); } } } // connect to top tile (if available) if (tile.Row > 0) { PointCloudTile topTile = tileSource.TileSet.GetTile(tile.Row - 1, tile.Col); TileInfo3D topTileInfo = null; if (topTile != null && m_tileInfo.TryGetValue(topTile, out topTileInfo) && topTileInfo.CurrentGrid == grid) { MeshGeometry3D topMesh = GetTileMeshGeometry(topTileInfo.CurrentGeometry); hasTop = true; topCornerPoint = topMesh.Positions[grid.SizeY - 1]; topCornerNormal = topMesh.Normals[grid.SizeY - 1]; if (!tileInfo.HasStitching(TileStitchingEdge.Top)) { MeshGeometry3D stitchingMesh = new MeshGeometry3D(); int positionCount = grid.SizeX * 2; Point3DCollection positions = new Point3DCollection(positionCount); Vector3DCollection normals = new Vector3DCollection(positionCount); for (int edgePosition = 0; edgePosition < mesh.Positions.Count; edgePosition += grid.SizeY) { positions.Add(topMesh.Positions[edgePosition + grid.SizeY - 1]); normals.Add(topMesh.Normals[edgePosition + grid.SizeY - 1]); positions.Add(mesh.Positions[edgePosition]); normals.Add(mesh.Normals[edgePosition]); } stitchingMesh.Positions = positions; stitchingMesh.Normals = normals; Int32Collection indices = new Int32Collection((grid.SizeX - 1) * 6); for (int i = 0; i < grid.SizeX - 1; i++) { int j = 2 * i; indices.Add(j); indices.Add(j + 2); indices.Add(j + 1); indices.Add(j + 2); indices.Add(j + 3); indices.Add(j + 1); } stitchingMesh.TriangleIndices = indices; stitchingMesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(stitchingMesh, m_overallCenteredExtent, MathUtils.ZAxis); GeometryModel3D stitchingModel = new GeometryModel3D(stitchingMesh, m_overviewMaterial); stitchingModel.Freeze(); tileInfo.UpdateStitching(stitchingModel, topTileInfo.CurrentGrid, TileStitchingEdge.Top); //stitchingGroup.Children.Add(stitchingModel); } } } // connect to top left tile (if available) if (hasTop && hasLeft && !tileInfo.HasStitching(TileStitchingEdge.TopLeft)) { PointCloudTile topleftTile = tileSource.TileSet.GetTile(tile.Row - 1, tile.Col - 1); TileInfo3D topleftTileInfo = null; if (topleftTile != null && m_tileInfo.TryGetValue(topleftTile, out topleftTileInfo)) { MeshGeometry3D topleftMesh = GetTileMeshGeometry(topleftTileInfo.CurrentGeometry); MeshGeometry3D stitchingMesh = new MeshGeometry3D(); Point3DCollection positions = new Point3DCollection(4); Vector3DCollection normals = new Vector3DCollection(4); { positions.Add(topleftMesh.Positions[topleftMesh.Positions.Count - 1]); normals.Add(topleftMesh.Normals[topleftMesh.Positions.Count - 1]); positions.Add(topCornerPoint); normals.Add(topCornerNormal); positions.Add(leftCornerPoint); normals.Add(leftCornerNormal); positions.Add(mesh.Positions[0]); normals.Add(mesh.Normals[0]); } stitchingMesh.Positions = positions; stitchingMesh.Normals = normals; Int32Collection indices = new Int32Collection(6); indices.Add(0); indices.Add(1); indices.Add(2); indices.Add(2); indices.Add(1); indices.Add(3); stitchingMesh.TriangleIndices = indices; stitchingMesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(stitchingMesh, m_overallCenteredExtent, MathUtils.ZAxis); GeometryModel3D stitchingModel = new GeometryModel3D(stitchingMesh, m_overviewMaterial); stitchingModel.Freeze(); tileInfo.UpdateStitching(stitchingModel, topleftTileInfo.CurrentGrid, TileStitchingEdge.TopLeft); //stitchingGroup.Children.Add(stitchingModel); } } return tileInfo.GetNewStitching(); }
private void SendGraphicsToView(Point3DCollection points, Point3DCollection pointsSelected, Point3DCollection lines, Point3DCollection linesSelected, Point3DCollection redLines, Point3DCollection greenLines, Point3DCollection blueLines, Point3DCollection verts, Vector3DCollection norms, Int32Collection tris, Point3DCollection vertsSel, Vector3DCollection normsSel, Int32Collection trisSel, MeshGeometry3D mesh, MeshGeometry3D meshSel, List<BillboardTextItem> text) { Points = points; PointsSelected = pointsSelected; Lines = lines; LinesSelected = linesSelected; XAxes = redLines; YAxes = greenLines; ZAxes = blueLines; mesh.Positions = verts; mesh.Normals = norms; mesh.TriangleIndices = tris; meshSel.Positions = vertsSel; meshSel.Normals = normsSel; meshSel.TriangleIndices = trisSel; Mesh = mesh; MeshSelected = meshSel; Text = text; // Send property changed notifications for everything NotifyPropertyChanged(string.Empty); }
/// <summary> /// Use the render packages returned from the visualization manager to update the visuals. /// The visualization event arguments will contain a set of render packages and an id representing /// the associated node. Visualizations for the background preview will return an empty id. /// </summary> /// <param name="e"></param> public void RenderDrawables(VisualizationEventArgs e) { //check the id, if the id is meant for another watch, //then ignore it if (e.Id != _id) { return; } Debug.WriteLine(string.Format("Rendering visuals for {0}", e.Id)); var sw = new Stopwatch(); sw.Start(); Points = null; Lines = null; Mesh = null; XAxes = null; YAxes = null; ZAxes = null; PointsSelected = null; LinesSelected = null; MeshSelected = null; Text = null; MeshCount = 0; //separate the selected packages var packages = e.Packages.Where(x => x.Selected == false) .Where(rp=>rp.TriangleVertices.Count % 9 == 0) .ToArray(); var selPackages = e.Packages .Where(x => x.Selected) .Where(rp => rp.TriangleVertices.Count % 9 == 0) .ToArray(); //pre-size the points collections var pointsCount = packages.Select(x => x.PointVertices.Count/3).Sum(); var selPointsCount = selPackages.Select(x => x.PointVertices.Count / 3).Sum(); var points = new Point3DCollection(pointsCount); var pointsSelected = new Point3DCollection(selPointsCount); //pre-size the lines collections //these sizes are conservative as the axis lines will be //taken from the linestripvertex collections as well. var lineCount = packages.Select(x => x.LineStripVertices.Count/3).Sum(); var lineSelCount = selPackages.Select(x => x.LineStripVertices.Count / 3).Sum(); var lines = new Point3DCollection(lineCount); var linesSelected = new Point3DCollection(lineSelCount); var redLines = new Point3DCollection(lineCount); var greenLines = new Point3DCollection(lineCount); var blueLines = new Point3DCollection(lineCount); //pre-size the text collection var textCount = e.Packages.Count(x => x.DisplayLabels); var text = new List<BillboardTextItem>(textCount); //http://blogs.msdn.com/b/timothyc/archive/2006/08/31/734308.aspx //presize the mesh collections var meshVertCount = packages.Select(x => x.TriangleVertices.Count / 3).Sum(); var meshVertSelCount = selPackages.Select(x => x.TriangleVertices.Count / 3).Sum(); var mesh = new MeshGeometry3D(); var meshSel = new MeshGeometry3D(); var verts = new Point3DCollection(meshVertCount); var vertsSel = new Point3DCollection(meshVertSelCount); var norms = new Vector3DCollection(meshVertCount); var normsSel = new Vector3DCollection(meshVertSelCount); var tris = new Int32Collection(meshVertCount); var trisSel = new Int32Collection(meshVertSelCount); foreach (var package in packages) { ConvertPoints(package, points, text); ConvertLines(package, lines, redLines, greenLines, blueLines, text); ConvertMeshes(package, verts, norms, tris); } foreach (var package in selPackages) { ConvertPoints(package, pointsSelected, text); ConvertLines(package, linesSelected, redLines, greenLines, blueLines, text); ConvertMeshes(package, vertsSel, normsSel, trisSel); } sw.Stop(); Debug.WriteLine(string.Format("RENDER: {0} ellapsed for updating background preview.", sw.Elapsed)); var vm = (IWatchViewModel)DataContext; if (vm.CheckForLatestRenderCommand.CanExecute(e.TaskId)) { vm.CheckForLatestRenderCommand.Execute(e.TaskId); } points.Freeze(); pointsSelected.Freeze(); lines.Freeze(); linesSelected.Freeze(); redLines.Freeze(); greenLines.Freeze(); blueLines.Freeze(); verts.Freeze(); norms.Freeze(); tris.Freeze(); vertsSel.Freeze(); normsSel.Freeze(); trisSel.Freeze(); Dispatcher.Invoke(new Action<Point3DCollection, Point3DCollection, Point3DCollection, Point3DCollection, Point3DCollection, Point3DCollection, Point3DCollection, Point3DCollection, Vector3DCollection, Int32Collection, Point3DCollection, Vector3DCollection, Int32Collection, MeshGeometry3D, MeshGeometry3D, List<BillboardTextItem>>(SendGraphicsToView), DispatcherPriority.Render, new object[] {points, pointsSelected, lines, linesSelected, redLines, greenLines, blueLines, verts, norms, tris, vertsSel, normsSel, trisSel, mesh, meshSel, text}); }
/// <summary> /// /// </summary> /// <param name="vertices"></param> /// <param name="normals"></param> /// <param name="indices"></param> /// <param name="textures"></param> protected void TriangleSubdivide(Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { for (int i = 0; i < 3; i++) { verticesBase[2 - i] = vertices[vertices.Count - 1]; normalsBase[2 - i] = normals[vertices.Count - 1]; texturesBase[2 - i] = textures[vertices.Count - 1]; vertices.RemoveAt(vertices.Count - 1); normals.RemoveAt(normals.Count - 1); indices.RemoveAt(indices.Count - 1); textures.RemoveAt(textures.Count - 1); } int indexStart = vertices.Count; for (int slice = 0; slice <= Slices; slice++) { double weight = (double)slice / Slices; Point3D vertex1 = Point3DWeight(verticesBase[0], verticesBase[1], weight); Point3D vertex2 = Point3DWeight(verticesBase[0], verticesBase[2], weight); Vector3D normal1 = Vector3DWeight(normalsBase[0], normalsBase[1], weight); Vector3D normal2 = Vector3DWeight(normalsBase[0], normalsBase[2], weight); Point texture1 = PointWeight(texturesBase[0], texturesBase[1], weight); Point texture2 = PointWeight(texturesBase[0], texturesBase[2], weight); for (int i = 0; i <= slice; i++) { weight = (double)i / slice; if (Double.IsNaN(weight)) weight = 0; vertices.Add(Point3DWeight(vertex1, vertex2, weight)); normals.Add(Vector3DWeight(normal1, normal2, weight)); textures.Add(PointWeight(texture1, texture2, weight)); } } for (int slice = 0; slice < Slices; slice++) { int base1 = (slice + 1) * slice / 2; int base2 = base1 + slice + 1; for (int i = 0; i <= 2 * slice; i++) { int half = i / 2; if ((i & 1) == 0) // even { indices.Add(indexStart + base1 + half); indices.Add(indexStart + base2 + half); indices.Add(indexStart + base2 + half + 1); } else // odd { indices.Add(indexStart + base1 + half); indices.Add(indexStart + base2 + half + 1); indices.Add(indexStart + base1 + half + 1); } } } }
/// <summary> /// Creates a new mesh where no vertices are shared. /// </summary> /// <param name="input"> /// The input mesh. /// </param> /// <returns> /// A new mesh. /// </returns> public static MeshGeometry3D NoSharedVertices(MeshGeometry3D input) { var p = new Point3DCollection(); var ti = new Int32Collection(); Vector3DCollection n = null; if (input.Normals != null) { n = new Vector3DCollection(); } PointCollection tc = null; if (input.TextureCoordinates != null) { tc = new PointCollection(); } for (int i = 0; i < input.TriangleIndices.Count; i += 3) { int i0 = i; int i1 = i + 1; int i2 = i + 2; int index0 = input.TriangleIndices[i0]; int index1 = input.TriangleIndices[i1]; int index2 = input.TriangleIndices[i2]; var p0 = input.Positions[index0]; var p1 = input.Positions[index1]; var p2 = input.Positions[index2]; p.Add(p0); p.Add(p1); p.Add(p2); ti.Add(i0); ti.Add(i1); ti.Add(i2); if (n != null) { n.Add(input.Normals[index0]); n.Add(input.Normals[index1]); n.Add(input.Normals[index2]); } if (tc != null) { tc.Add(input.TextureCoordinates[index0]); tc.Add(input.TextureCoordinates[index1]); tc.Add(input.TextureCoordinates[index2]); } } return new MeshGeometry3D { Positions = p, TriangleIndices = ti, Normals = n, TextureCoordinates = tc }; }
protected override void Triangulate(DependencyPropertyChangedEventArgs args, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { vertices.Clear(); normals.Clear(); indices.Clear(); textures.Clear(); Point3D[,] faces = Faces; PointCollection texturesBase = TextureCoordinates; int indexTextures = 0; for (int face = 0; face < faces.GetLength(0); face++) { Vector3D normal = Vector3D.CrossProduct(faces[face, 1] - faces[face, 0], faces[face, 2] - faces[face, 0]); // For faces that are triangles. if (faces.GetLength(1) == 3) { int indexBase = vertices.Count; for (int i = 0; i < 3; i++) { vertices.Add(faces[face, i]); normals.Add(normal); indices.Add(indexBase + i); if (texturesBase != null && texturesBase.Count > 0) { textures.Add(texturesBase[indexTextures]); indexTextures = (indexTextures + 1) % texturesBase.Count; } } if (Slices > 1) TriangleSubdivide(vertices, normals, indices, textures); } // For faces that are not triangles. else { for (int i = 0; i < faces.GetLength(1) - 1; i++) { int indexBase = vertices.Count; int num = faces.GetLength(1) - 1; vertices.Add(faces[face, 0]); vertices.Add(faces[face, i + 1]); vertices.Add(faces[face, (i + 1) % num + 1]); if (texturesBase != null && texturesBase.Count >= faces.GetLength(1)) { textures.Add(texturesBase[indexTextures + 0]); textures.Add(texturesBase[indexTextures + i + 1]); textures.Add(texturesBase[indexTextures + (i + 1) % num + 1]); } normals.Add(normal); normals.Add(normal); normals.Add(normal); indices.Add(indexBase + 0); indices.Add(indexBase + 1); indices.Add(indexBase + 2); if (Slices > 1) TriangleSubdivide(vertices, normals, indices, textures); } if (texturesBase != null && texturesBase.Count > 0) indexTextures = (indexTextures + faces.GetLength(1)) % texturesBase.Count; } } }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods internal override void UpdateResource(DUCE.Channel channel, bool skipOnChannelCheck) { // If we're told we can skip the channel check, then we must be on channel Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel)); if (skipOnChannelCheck || _duceResource.IsOnChannel(channel)) { base.UpdateResource(channel, skipOnChannelCheck); // Read values of properties into local variables Point3DCollection vPositions = Positions; Vector3DCollection vNormals = Normals; PointCollection vTextureCoordinates = TextureCoordinates; Int32Collection vTriangleIndices = TriangleIndices; // Store the count of this resource's contained collections in local variables. int PositionsCount = (vPositions == null) ? 0 : vPositions.Count; int NormalsCount = (vNormals == null) ? 0 : vNormals.Count; int TextureCoordinatesCount = (vTextureCoordinates == null) ? 0 : vTextureCoordinates.Count; int TriangleIndicesCount = (vTriangleIndices == null) ? 0 : vTriangleIndices.Count; // Pack & send command packet DUCE.MILCMD_MESHGEOMETRY3D data; unsafe { data.Type = MILCMD.MilCmdMeshGeometry3D; data.Handle = _duceResource.GetHandle(channel); data.PositionsSize = (uint)(sizeof(MilPoint3F) * PositionsCount); data.NormalsSize = (uint)(sizeof(MilPoint3F) * NormalsCount); data.TextureCoordinatesSize = (uint)(sizeof(Point) * TextureCoordinatesCount); data.TriangleIndicesSize = (uint)(sizeof(Int32) * TriangleIndicesCount); channel.BeginCommand( (byte *)&data, sizeof(DUCE.MILCMD_MESHGEOMETRY3D), (int)(data.PositionsSize + data.NormalsSize + data.TextureCoordinatesSize + data.TriangleIndicesSize) ); // Copy this collection's elements (or their handles) to reserved data for (int i = 0; i < PositionsCount; i++) { MilPoint3F resource = CompositionResourceManager.Point3DToMilPoint3F(vPositions.Internal_GetItem(i)); channel.AppendCommandData( (byte *)&resource, sizeof(MilPoint3F) ); } // Copy this collection's elements (or their handles) to reserved data for (int i = 0; i < NormalsCount; i++) { MilPoint3F resource = CompositionResourceManager.Vector3DToMilPoint3F(vNormals.Internal_GetItem(i)); channel.AppendCommandData( (byte *)&resource, sizeof(MilPoint3F) ); } // Copy this collection's elements (or their handles) to reserved data for (int i = 0; i < TextureCoordinatesCount; i++) { Point resource = vTextureCoordinates.Internal_GetItem(i); channel.AppendCommandData( (byte *)&resource, sizeof(Point) ); } // Copy this collection's elements (or their handles) to reserved data for (int i = 0; i < TriangleIndicesCount; i++) { Int32 resource = vTriangleIndices.Internal_GetItem(i); channel.AppendCommandData( (byte *)&resource, sizeof(Int32) ); } channel.EndCommand(); } } }
public static void DrawLibGGraphicItem(NodeModel node, object geom, string tag, RenderDescription rd, Octree.OctreeSearch.Octree octree) { var selected = DynamoSelection.Instance.Selection.Contains(node); var g = geom as GraphicItem; if (g is CoordinateSystem) { #region draw coordinate systems var line_strip_vertices = g.line_strip_vertices_threadsafe(); for (int i = 0; i < line_strip_vertices.Count; i += 6) { var p1 = new Point3D( line_strip_vertices[i], line_strip_vertices[i + 1], line_strip_vertices[i + 2]); var p2 = new Point3D( line_strip_vertices[i + 3], line_strip_vertices[i + 4], line_strip_vertices[i + 5]); if (i < 6) { rd.XAxisPoints.Add(p1); rd.XAxisPoints.Add(p2); } else if (i >= 6 && i < 12) { rd.YAxisPoints.Add(p1); rd.YAxisPoints.Add(p2); } else { rd.ZAxisPoints.Add(p1); rd.ZAxisPoints.Add(p2); } } #endregion } else { #region draw points var point_vertices = g.point_vertices_threadsafe(); for (int i = 0; i < point_vertices.Count; i += 3) { var pos = new Point3D(point_vertices[i], point_vertices[i + 1], point_vertices[i + 2]); if (selected) { rd.SelectedPoints.Add(pos); } else { rd.Points.Add(pos); } if (node.DisplayLabels) { rd.Text.Add(new BillboardTextItem { Text = tag, Position = pos }); } } #endregion #region draw lines FloatList line_strip_vertices = g.line_strip_vertices_threadsafe(); for (int i = 0; i < line_strip_vertices.Count-3; i += 3) { var start = new Point3D( line_strip_vertices[i], line_strip_vertices[i + 1], line_strip_vertices[i + 2]); var end = new Point3D( line_strip_vertices[i + 3], line_strip_vertices[i + 4], line_strip_vertices[i + 5]); //draw a label at the start of the curve if (node.DisplayLabels && i == 0) { rd.Text.Add(new BillboardTextItem { Text = tag, Position = start }); } if (selected) { rd.SelectedLines.Add(start); rd.SelectedLines.Add(end); } else { rd.Lines.Add(start); rd.Lines.Add(end); } } #endregion #region draw surface //var sw = new Stopwatch(); //sw.Start(); var builder = new MeshBuilder(); var points = new Point3DCollection(); var tex = new PointCollection(); var norms = new Vector3DCollection(); var tris = new List<int>(); FloatList triangle_vertices = g.triangle_vertices_threadsafe(); FloatList triangle_normals = g.triangle_normals_threadsafe(); for (int i = 0; i < triangle_vertices.Count; i+=3) { var new_point = new Point3D(triangle_vertices[i], triangle_vertices[i + 1], triangle_vertices[i + 2]); var normal = new Vector3D(triangle_normals[i], triangle_normals[i + 1], triangle_normals[i + 2]); //find a matching point //compare the angle between the normals //to discern a 'break' angle for adjacent faces //int foundIndex = -1; //for (int j = 0; j < points.Count; j++) //{ // var testPt = points[j]; // var testNorm = norms[j]; // var ang = Vector3D.AngleBetween(normal, testNorm); // if (new_point.X == testPt.X && // new_point.Y == testPt.Y && // new_point.Z == testPt.Z && // ang > 90.0000) // { // foundIndex = j; // break; // } //} //if (foundIndex != -1) //{ // tris.Add(foundIndex); // continue; //} tris.Add(points.Count); points.Add(new_point); norms.Add(normal); tex.Add(new System.Windows.Point(0,0)); octree.AddNode(new_point.X, new_point.Y, new_point.Z, node.GUID.ToString()); } //builder.AddTriangles(points, norms, tex); builder.Append(points, tris, norms, tex); //sw.Stop(); //Debug.WriteLine(string.Format("{0} elapsed for drawing geometry.", sw.Elapsed)); //don't add empty meshes if (builder.Positions.Count > 0) { if (selected) { rd.SelectedMeshes.Add(builder.ToMesh(true)); } else { rd.Meshes.Add(builder.ToMesh(true)); } } #endregion } }
// Abstract method to convert figure to mesh geometry. protected abstract void ProcessFigure(CircularList<Point> list, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures);
/// <summary> /// /// </summary> /// <param name="args"> /// The DependencyPropertyChangedEventArgs object originally /// passed to the PropertyChanged handler that initiated this /// recalculation. /// </param> /// <param name="vertices"> /// The Point3DCollection corresponding to the Positions property /// of the MeshGeometry3D. /// </param> /// <param name="normals"> /// The Vector3DCollection corresponding to the Normals property /// of the MeshGeometry3D. /// </param> /// <param name="indices"> /// The Int32Collection corresponding to the TriangleIndices /// property of the MeshGeometry3D. /// </param> /// <param name="textures"> /// The PointCollection corresponding to the TextureCoordinates /// property of the MeshGeometry3D. /// </param> protected override void Triangulate(DependencyPropertyChangedEventArgs args, Point3DCollection vertices, Vector3DCollection normals, Int32Collection indices, PointCollection textures) { // Clear all four collections. vertices.Clear(); normals.Clear(); indices.Clear(); textures.Clear(); // Loop for outside (side = 1) and inside (side = -1). for (int side = 1; side >= -1; side -= 2) { int offset = vertices.Count; // Begin at the top end. Fill the collections. for (int stack = 0; stack <= EndStacks; stack++) { double y = Length; double radius = Radius + side * stack * Thickness / 2 / EndStacks; int top = offset + (stack + 0) * (Slices + 1); int bot = offset + (stack + 1) * (Slices + 1); for (int slice = 0; slice <= Slices; slice++) { double theta = slice * 2 * Math.PI / Slices; double x = -radius * Math.Sin(theta); double z = -radius * Math.Cos(theta); vertices.Add(new Point3D(x, y, z)); normals.Add(new Vector3D(0, side, 0)); textures.Add(new Point((double)slice / Slices, Fold * stack / EndStacks)); if (stack < EndStacks && slice < Slices) { indices.Add(top + slice); indices.Add(bot + slice); indices.Add(top + slice + 1); indices.Add(top + slice + 1); indices.Add(bot + slice); indices.Add(bot + slice + 1); } } } offset = vertices.Count; // Length of the tube: Fill in the collections. for (int stack = 0; stack <= Stacks; stack++) { double y = Length - stack * Length / Stacks; int top = offset + (stack + 0) * (Slices + 1); int bot = offset + (stack + 1) * (Slices + 1); for (int slice = 0; slice <= Slices; slice++) { double theta = slice * 2 * Math.PI / Slices; double x = -(Radius + side * Thickness / 2) * Math.Sin(theta); double z = -(Radius + side * Thickness / 2) * Math.Cos(theta); vertices.Add(new Point3D(x, y, z)); normals.Add(new Vector3D(side * x, 0, side * z)); textures.Add(new Point((double)slice / Slices, Fold + (1 - 2 * Fold) * stack / Stacks)); if (stack < Stacks && slice < Slices) { indices.Add(top + slice); indices.Add(bot + slice); indices.Add(top + slice + 1); indices.Add(top + slice + 1); indices.Add(bot + slice); indices.Add(bot + slice + 1); } } } offset = vertices.Count; // Finish with the bottom end. Fill the collections. for (int stack = 0; stack <= EndStacks; stack++) { double y = 0; double radius = Radius + side * Thickness / 2 * (1 - (double)stack / EndStacks); int top = offset + (stack + 0) * (Slices + 1); int bot = offset + (stack + 1) * (Slices + 1); for (int slice = 0; slice <= Slices; slice++) { double theta = slice * 2 * Math.PI / Slices; double x = -radius * Math.Sin(theta); double z = -radius * Math.Cos(theta); vertices.Add(new Point3D(x, y, z)); normals.Add(new Vector3D(0, -side, 0)); textures.Add(new Point((double)slice / Slices, (1 - Fold) + Fold * stack / EndStacks)); if (stack < EndStacks && slice < Slices) { indices.Add(top + slice); indices.Add(bot + slice); indices.Add(top + slice + 1); indices.Add(top + slice + 1); indices.Add(bot + slice); indices.Add(bot + slice + 1); } } } } }