public static int ExpectedElementCount(this IGeometryAttributes self, AttributeDescriptor desc) { switch (desc.Association) { case Association.assoc_all: return(1); case Association.assoc_none: return(0); case Association.assoc_vertex: return(self.NumVertices); case Association.assoc_face: return(self.NumFaces); case Association.assoc_corner: return(self.NumCorners); case Association.assoc_edge: return(self.NumCorners); case Association.assoc_subgeometry: return(self.NumSubgeometries); case Association.assoc_instance: return(self.NumInstances); } return(-1); }
/// <summary> /// Applies a transformation function to position attributes and another to normal attributes. When deforming, we may want to /// apply a similar deformation to the normals. For example a matrix can change the position, rotation, and scale of a geometry, /// but the only changes should be to the direction of the normal, not the length. /// </summary> public static IGeometryAttributes Deform(this IGeometryAttributes g, Func <Vector3, Vector3> positionTransform, Func <Vector3, Vector3> normalTransform) => g.Attributes.Select( a => (a.Descriptor.Semantic == "position" && a is GeometryAttribute <Vector3> p) ? p.Data.Select(positionTransform).ToAttribute(a.Descriptor) : (a.Descriptor.Semantic == "normal" && a is GeometryAttribute <Vector3> n) ? n.Data.Select(normalTransform).ToAttribute(a.Descriptor) : a) .ToGeometryAttributes();
/// <summary> /// Converts a quadrilateral mesh into a triangular mesh carrying over all attributes. /// </summary> public static IGeometryAttributes TriangulateQuadMesh(this IGeometryAttributes g) { if (g.NumCornersPerFace != 4) { throw new Exception("Not a quad mesh"); } var cornerRemap = new int[g.NumFaces * 6]; var faceRemap = new int[g.NumFaces * 2]; var cur = 0; for (var i = 0; i < g.NumFaces; ++i) { cornerRemap[cur++] = i * 4 + 0; cornerRemap[cur++] = i * 4 + 1; cornerRemap[cur++] = i * 4 + 2; cornerRemap[cur++] = i * 4 + 0; cornerRemap[cur++] = i * 4 + 2; cornerRemap[cur++] = i * 4 + 3; faceRemap[i * 2 + 0] = i; faceRemap[i * 2 + 1] = i; } return(g.RemapFacesAndCorners(faceRemap.ToIArray(), cornerRemap.ToIArray(), 3)); }
/// <summary> /// Applies vertex colors /// </summary> public static IGeometryAttributes Color(this IGeometryAttributes g, Vector4 color) { return(g.Attributes .Where(a => a.Descriptor.Semantic != Semantic.Color) .Concat(Enumerable.Repeat(g.NumVertices.Select(_ => color).ToAttribute(new AttributeDescriptor(Association.assoc_vertex, Semantic.Color, DataType.dt_float32, 4)), 1)) .ToGeometryAttributes()); }
public static byte[] WriteToBytes(this IGeometryAttributes self) { using (var memoryStream = new MemoryStream()) { self.Write(memoryStream); return(memoryStream.ToArray()); } }
public G3dWriter(IGeometryAttributes g, G3dHeader?header = null) { Attributes = g; Meta = (header ?? G3dHeader.Default).ToBytes().ToNamedBuffer("meta"); Names = new[] { Meta.Name }.Concat(g.Attributes.ToEnumerable().Select(attr => attr.Name)).ToArray(); Sizes = new[] { Meta.NumBytes() }.Concat(g.Attributes.ToEnumerable().Select(attr => attr.GetByteSize())).ToArray(); Header = BFast.BFast.CreateBFastHeader(Sizes, Names); }
/// <summary> /// Low-level remap function. Maps faces and corners at the same time. /// In some cases, this is important (e.g. triangulating quads). /// Note: sub-geometries are lost. /// </summary> public static IGeometryAttributes RemapFacesAndCorners(this IGeometryAttributes g, IArray <int> faceRemap, IArray <int> cornerRemap, int numCornersPerFace = -1) => g.VertexAttributes() .Concat(g.NoneAttributes()) .Concat(g.FaceAttributes().Select(attr => attr.Remap(faceRemap))) .Concat(g.EdgeAttributes().Select(attr => attr.Remap(cornerRemap))) .Concat(g.CornerAttributes().Select(attr => attr.Remap(cornerRemap))) .Concat(g.WholeGeometryAttributes()) .SetFaceSizeAttribute(numCornersPerFace) .ToGeometryAttributes();
public static IGeometryAttributes FlipWindingOrder(this IGeometryAttributes g) => g.VertexAttributes() .Concat(g.NoneAttributes()) .Concat(g.FaceAttributes()) .Concat(g.EdgeAttributes().Select(attr => attr.Remap(g.IndexFlippedRemapping()))) .Concat(g.CornerAttributes().Select(attr => attr.Remap(g.IndexFlippedRemapping()))) .Concat(g.WholeGeometryAttributes()) .FlipNormalAttributes() .ToGeometryAttributes();
/// <summary> /// Updates the vertex buffer (e.g. after identifying unwanted faces) and the index /// buffer. Vertices are either re-ordered, removed, or deleted. Does not affect any other /// </summary> public static IGeometryAttributes RemapVertices(this IGeometryAttributes g, IArray <int> newVertices, IArray <int> newIndices) => (new[] { newIndices.ToIndexAttribute() } .Concat( g.VertexAttributes() .Select(attr => attr.Remap(newVertices))) .Concat(g.NoneAttributes()) .Concat(g.FaceAttributes()) .Concat(g.EdgeAttributes()) .Concat(g.CornerAttributes()) .Concat(g.WholeGeometryAttributes()) ) .ToGeometryAttributes();
/// <summary> /// The vertRemap is a list of vertices in the new vertex buffer, and where they came from. /// This could be a reordering of the original vertex buffer, it could even be a repetition. /// It could also be some vertices were deleted, BUT if those vertices are still referenced /// then this will throw an exception. /// The values in the index buffer will change, but it will stay the same length. /// </summary> public static IGeometryAttributes RemapVertices(this IGeometryAttributes g, IArray <int> vertRemap) { var vertLookup = (-1).Repeat(g.NumVertices).ToArray(); for (var i = 0; i < vertRemap.Count; ++i) { var oldVert = vertRemap[i]; vertLookup[oldVert] = i; } var oldIndices = g.GetAttributeIndex()?.Data ?? g.NumVertices.Range(); var newIndices = oldIndices.Select(i => vertLookup[i]).Evaluate(); if (newIndices.Any(x => x == -1)) { throw new Exception("At least one of the indices references a vertex that no longer exists"); } return(g.RemapVertices(vertRemap, newIndices)); }
public static GeometryAttribute <int> GetAttributeIndex(this IGeometryAttributes self) => self.GetAttribute <int>(CommonAttributes.Index);
public static IArray <int> GetAttributeDataObjectFaceSize(this IGeometryAttributes self) => self.GetAttributeObjectFaceSize()?.Data;
public static GeometryAttribute <Vector4> GetAttributeVertexTangent(this IGeometryAttributes self) => self.GetAttribute <Vector4>(CommonAttributes.VertexTangent);
public static GeometryAttribute <Byte4> GetAttributeVertexColor8Bit(this IGeometryAttributes self) => self.GetAttribute <Byte4>(CommonAttributes.VertexColor8Bit);
public static IArray <Vector3> GetAttributeDataVertexNormal(this IGeometryAttributes self) => self.GetAttributeVertexNormal()?.Data;
public static IArray <Vector2> GetAttributeDataVertexUv(this IGeometryAttributes self) => self.GetAttributeVertexUv()?.Data;
public static IArray <Vector3> GetAttributeDataPosition(this IGeometryAttributes self) => self.GetAttributePosition()?.Data;
public static IArray <int> GetAttributeDataIndex(this IGeometryAttributes self) => self.GetAttributeIndex()?.Data;
public static GeometryAttribute <Vector3> GetAttributePosition(this IGeometryAttributes self) => self.GetAttribute <Vector3>(CommonAttributes.Position);
public static GeometryAttribute <Matrix4x4> GetAttributeInstanceTransforms(this IGeometryAttributes self) => self.GetAttribute <Matrix4x4>(CommonAttributes.InstanceTransforms);
public static GeometryAttribute <Vector2> GetAttributeVertexUv(this IGeometryAttributes self) => self.GetAttribute <Vector2>(CommonAttributes.VertexUv);
public static IArray <Matrix4x4> GetAttributeDataInstanceTransforms(this IGeometryAttributes self) => self.GetAttributeInstanceTransforms()?.Data;
public static GeometryAttribute <Vector3> GetAttributeVertexNormal(this IGeometryAttributes self) => self.GetAttribute <Vector3>(CommonAttributes.VertexNormal);
public static GeometryAttribute <int> GetAttributeInstanceGeometries(this IGeometryAttributes self) => self.GetAttribute <int>(CommonAttributes.InstanceGeometries);
public static GeometryAttribute <Vector4> GetAttributeVertexColor(this IGeometryAttributes self) => self.GetAttribute <Vector4>(CommonAttributes.VertexColor);
public static GeometryAttribute <Vector3> GetAttributeLineTangentOut(this IGeometryAttributes self) => self.GetAttribute <Vector3>(CommonAttributes.LineTangentOut);
public static IArray <Byte4> GetAttributeDataVertexColor8Bit(this IGeometryAttributes self) => self.GetAttributeVertexColor8Bit()?.Data;
public static IArray <Vector3> GetAttributeDataLineTangentOut(this IGeometryAttributes self) => self.GetAttributeLineTangentOut()?.Data;
public static IArray <Vector4> GetAttributeDataVertexTangent(this IGeometryAttributes self) => self.GetAttributeVertexTangent()?.Data;
public static GeometryAttribute <int> GetAttributeObjectFaceSize(this IGeometryAttributes self) => self.GetAttribute <int>(CommonAttributes.ObjectFaceSize);