private static void TransformPlanarTexCoord(ref Vector2 texCoord, Vertex vertex, Vector3 center, Vector3 vec) { Vector3 binormal; float d = Vector3.Dot(vertex.Normal, Vector3.UnitX); if (d >= 0.5f || d <= -0.5f) { binormal = new Vector3(0f, 1f, 0f); if (vertex.Normal.X < 0f) { binormal.X = -binormal.X; binormal.Y = -binormal.Y; binormal.Z = -binormal.Z; } } else { binormal = new Vector3(1f, 0f, 0f); if (vertex.Normal.Y > 0f) { binormal.X = -binormal.X; binormal.Y = -binormal.Y; binormal.Z = -binormal.Z; } } Vector3 tangent = binormal % vertex.Normal; texCoord.Y = -(Vector3.Dot(tangent, vec) * 2f - 0.5f); texCoord.X = 1f + (Vector3.Dot(binormal, vec) * 2f - 0.5f); }
// I had a lot of trouble with problems with equality and GetHashCode of OMVR.Vertex // so this implementation creates a proper hash for a Vertex so it can be used // in a dictionary. public static BHash VertexBHash(OMVR.Vertex vert) { BHasher hasher = new BHasherMdjb2(); MeshInfo.VertexBHash(vert, hasher); return(hasher.Finish()); }
/// <summary> /// Apply texture coordinate modifications from a /// <seealso cref="TextureEntryFace"/> to a list of vertices /// </summary> /// <param name="vertices">Vertex list to modify texture coordinates for</param> /// <param name="center">Center-point of the face</param> /// <param name="teFace">Face texture parameters</param> public void TransformTexCoords(List <OMVR.Vertex> vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace) { // compute trig stuff up front float cosineAngle = (float)Math.Cos(teFace.Rotation); float sinAngle = (float)Math.Sin(teFace.Rotation); // need a check for plainer vs default // just do default for now (I don't know what planar is) for (int ii = 0; ii < vertices.Count; ii++) { // tex coord comes to us as a number between zero and one // transform about the center of the texture OMVR.Vertex vert = vertices[ii]; // repeat, offset, rotate // float tX = (vert.TexCoord.X - 0.5f) * teFace.RepeatU + teFace.OffsetU; // float tY = (vert.TexCoord.Y - 0.5f) * teFace.RepeatV - teFace.OffsetV; // vert.TexCoord.X = (tX * cosineAngle - tY * sinAngle) + 0.5f; // vert.TexCoord.Y = (tX * sinAngle + tY * cosineAngle) + 0.5f; float tX = vert.TexCoord.X - 0.5f; float tY = vert.TexCoord.Y - 0.5f; // rotate, scale, offset vert.TexCoord.X = (tX * cosineAngle - tY * sinAngle) * teFace.RepeatU - teFace.OffsetU + 0.5f; vert.TexCoord.Y = (tX * sinAngle + tY * cosineAngle) * teFace.RepeatV - teFace.OffsetV + 0.5f; vertices[ii] = vert; } return; }
/// <summary> /// Method for generating mesh Face from a heightmap /// </summary> /// <param name="zMap">Two dimension array of floats containing height information</param> /// <param name="xBegin">Starting value for X</param> /// <param name="xEnd">Max value for X</param> /// <param name="yBegin">Starting value for Y</param> /// <param name="yEnd">Max value of Y</param> /// <returns></returns> public Face TerrainMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd) { SculptMesh newMesh = new SculptMesh(zMap, xBegin, xEnd, yBegin, yEnd, true); Face terrain = new Face(); int faceVertices = newMesh.coords.Count; terrain.Vertices = new List <Vertex>(faceVertices); terrain.Indices = new List <ushort>(newMesh.faces.Count * 3); for (int j = 0; j < faceVertices; j++) { var vert = new OMVR.Vertex { Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z), Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z), TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V) }; terrain.Vertices.Add(vert); } for (int j = 0; j < newMesh.faces.Count; j++) { terrain.Indices.Add((ushort)newMesh.faces[j].v1); terrain.Indices.Add((ushort)newMesh.faces[j].v2); terrain.Indices.Add((ushort)newMesh.faces[j].v3); } return(terrain); }
// Given a list of meshes, combine them into one mesh and return a containing BInstance. private BInstance CreateOneInstanceFromMeshes(BHash materialHash, List <InvertedMesh> meshes) { // Pick one of the meshes to be the 'root' mesh. // Someday may need to find the most center mesh to work from. InvertedMesh rootIMesh = meshes.First(); // The new instance will be at the location of the root mesh with no rotation BInstance inst = new BInstance(); inst.Position = rootIMesh.containingInstance.Position; inst.Rotation = OMV.Quaternion.Identity; inst.coordAxis = rootIMesh.containingInstance.coordAxis; try { // The mesh we're going to build MeshInfo meshInfo = new MeshInfo(); foreach (InvertedMesh imesh in meshes) { int indicesBase = meshInfo.vertexs.Count; // Go through the mesh, map all vertices to global coordinates then convert relative to root meshInfo.vertexs.AddRange(imesh.renderableMesh.mesh.vertexs.Select(vert => { OMVR.Vertex newVert = new OMVR.Vertex(); OMV.Vector3 worldPos = vert.Position; worldPos = worldPos * imesh.containingDisplayable.offsetRotation + imesh.containingDisplayable.offsetPosition; worldPos = worldPos * imesh.containingInstance.Rotation + imesh.containingInstance.Position; // Make new vert relative to the BInstance it's being added to newVert.Position = worldPos - inst.Position; newVert.Normal = vert.Normal * imesh.containingDisplayable.offsetRotation * imesh.containingInstance.Rotation; newVert.TexCoord = vert.TexCoord; return(newVert); })); meshInfo.indices.AddRange(imesh.renderableMesh.mesh.indices.Select(ind => ind + indicesBase)); } RenderableMesh newMesh = new RenderableMesh(); newMesh.num = 0; newMesh.material = rootIMesh.renderableMesh.material; // The material we share newMesh.mesh = meshInfo; RenderableMeshGroup meshGroup = new RenderableMeshGroup(); meshGroup.meshes.Add(newMesh); Displayable displayable = new Displayable(meshGroup); displayable.name = "combinedMaterialMeshes-" + materialHash.ToString(); inst.Representation = displayable; } catch (Exception e) { ConvOAR.Globals.log.ErrorFormat("{0} CreateInstanceFromSharedMaterialMeshes: exception: {1}", _logHeader, e); } return(inst); }
public static void OnAllVertex(MeshInfo mi, OperateOnVertex vertOp) { for (int jj = 0; jj < mi.vertexs.Count; jj++) { OMVR.Vertex aVert = mi.vertexs[jj]; vertOp(ref aVert); mi.vertexs[jj] = aVert; } }
/// <summary> /// Create a faceted mesh from prim shape parameters. /// Generates a a series of faces, each face containing a mesh and /// material metadata. /// A prim will turn into multiple faces with each being independent /// meshes and each having different material information. /// </summary> /// <param name="prim">Primitive to generate the mesh from</param> /// <param name="lod">Level of detail to generate the mesh at</param> /// <returns>The generated mesh</returns > public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod) { bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle); PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true); if (newPrim == null) { return(null); } // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List <OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List <OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List <OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List <OMVR.PathPoint>(); var indexer = newPrim.GetVertexIndexer(); for (int i = 0; i < indexer.numPrimFaces; i++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List <OMVR.Vertex>(); oface.Indices = new List <ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)i); for (int j = 0; j < indexer.viewerVertices[i].Count; j++) { var vert = new OMVR.Vertex(); var m = indexer.viewerVertices[i][j]; vert.Position = new Vector3(m.v.X, m.v.Y, m.v.Z); vert.Normal = new Vector3(m.n.X, m.n.Y, m.n.Z); vert.TexCoord = new OMV.Vector2(m.uv.U, 1.0f - m.uv.V); oface.Vertices.Add(vert); } for (int j = 0; j < indexer.viewerPolygons[i].Count; j++) { var p = indexer.viewerPolygons[i][j]; // Skip "degenerate faces" where the same vertex appears twice in the same tri if (p.v1 == p.v2 || p.v1 == p.v2 || p.v2 == p.v3) { continue; } oface.Indices.Add((ushort)p.v1); oface.Indices.Add((ushort)p.v2); oface.Indices.Add((ushort)p.v3); } omvrmesh.Faces.Add(oface); } return(omvrmesh); }
private static void VertexBHash(OMVR.Vertex vert, BHasher hasher) { hasher.Add(vert.Position.X); hasher.Add(vert.Position.Y); hasher.Add(vert.Position.Z); hasher.Add(vert.Normal.X); hasher.Add(vert.Normal.Y); hasher.Add(vert.Normal.Z); hasher.Add(vert.TexCoord.X); hasher.Add(vert.TexCoord.Y); }
/// <summary> /// Apply texture coordinate modifications from a /// <seealso cref="TextureEntryFace"/> to a list of vertices /// </summary> /// <param name="vertices">Vertex list to modify texture coordinates for</param> /// <param name="center">Center-point of the face</param> /// <param name="teFace">Face texture parameters</param> public void TransformTexCoords(List <OMVR.Vertex> vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace, Vector3 primScale) { // compute trig stuff up front float cosineAngle = (float)Math.Cos(teFace.Rotation); float sinAngle = (float)Math.Sin(teFace.Rotation); for (int ii = 0; ii < vertices.Count; ii++) { // tex coord comes to us as a number between zero and one // transform about the center of the texture OMVR.Vertex vert = vertices[ii]; // aply planar tranforms to the UV first if applicable if (teFace.TexMapType == MappingType.Planar) { Vector3 binormal; float d = Vector3.Dot(vert.Normal, Vector3.UnitX); if (d >= 0.5f || d <= -0.5f) { binormal = Vector3.UnitY; if (vert.Normal.X < 0f) { binormal *= -1; } } else { binormal = Vector3.UnitX; if (vert.Normal.Y > 0f) { binormal *= -1; } } Vector3 tangent = binormal % vert.Normal; Vector3 scaledPos = vert.Position * primScale; vert.TexCoord.X = 1f + (Vector3.Dot(binormal, scaledPos) * 2f - 0.5f); vert.TexCoord.Y = -(Vector3.Dot(tangent, scaledPos) * 2f - 0.5f); } float repeatU = teFace.RepeatU; float repeatV = teFace.RepeatV; float tX = vert.TexCoord.X - 0.5f; float tY = vert.TexCoord.Y - 0.5f; vert.TexCoord.X = (tX * cosineAngle + tY * sinAngle) * repeatU + teFace.OffsetU + 0.5f; vert.TexCoord.Y = (-tX * sinAngle + tY * cosineAngle) * repeatV + teFace.OffsetV + 0.5f; vertices[ii] = vert; } return; }
// Create a new MeshInfo with a copy of what is in another MeshInfo. // Note that we need to do a deep'ish copy since the values of the // vertices may be modified in the copy. // OMVR.Vertex and OMV.Vextor3 are structs so they are copied. public MeshInfo(MeshInfo other) { handle = new EntityHandleUUID(); vertexs = other.vertexs.ConvertAll(v => { OMVR.Vertex newV = new OMVR.Vertex(); newV.Position = v.Position; newV.Normal = v.Normal; newV.TexCoord = v.TexCoord; return(newV); }); // vertexs = new List<OMVR.Vertex>(other.vertexs); indices = new List <int>(other.indices); scale = new OMV.Vector3(other.scale); faceCenter = new OMV.Vector3(other.faceCenter); }
// Walk through all the vertices and scale the included meshes // Returns 'true' of the mesh was changed. public static bool ScaleMeshes(MeshInfo meshInfo, OMV.Vector3 scale) { bool ret = false; if (scale.X != 1.0 || scale.Y != 1.0 || scale.Z != 1.0) { ret = true; for (int ii = 0; ii < meshInfo.vertexs.Count; ii++) { OMVR.Vertex aVert = meshInfo.vertexs[ii]; aVert.Position *= scale; meshInfo.vertexs[ii] = aVert; } } return(ret); }
public void AddVertex(Vertex v) { int index; if (LookUp.ContainsKey(v)) { index = LookUp[v]; } else { index = Vertices.Count; Vertices.Add(v); LookUp[v] = index; } Indices.Add((uint)index); }
public SimpleMesh GenerateSimpleMesh(Primitive prim, DetailLevel lod) { Path path = GeneratePath(); Profile profile = GenerateProfile(); MeshmerizerMesh meshmerizer = new MeshmerizerMesh(); meshmerizer = GenerateMeshmerizerMesh(prim); // Create the vertex array List<Vertex> vertices = new List<Vertex>(meshmerizer.primMesh.coords.Count); for (int i = 0; i < meshmerizer.primMesh.coords.Count; i++) { Coord c = meshmerizer.primMesh.coords[i]; Vertex vertex = new Vertex(); vertex.Position = new Vector3(c.X, c.Y, c.Z); vertices.Add(vertex); } // Create the index array List<ushort> indices = new List<ushort>(meshmerizer.primMesh.faces.Count * 3); for (int i = 0; i < meshmerizer.primMesh.faces.Count; i++) { MeshmerizerFace f = meshmerizer.primMesh.faces[i]; indices.Add((ushort)f.v1); indices.Add((ushort)f.v2); indices.Add((ushort)f.v3); } SimpleMesh mesh = new SimpleMesh(); mesh.Prim = prim; mesh.Path = path; mesh.Profile = profile; mesh.Vertices = vertices; mesh.Indices = indices; return mesh; }
// PrimMesher has a terrain mesh generator but it doesn't compute normals. // TODO: Optimize by removing vertices that are just mid points. // Having a vertex for every height is very inefficient especially for flat areas. public static OMVR.Face TerrainMesh(float[,] heights, float realSizeX, float realSizeY) { List <ushort> indices = new List <ushort>(); int sizeX = heights.GetLength(0); int sizeY = heights.GetLength(1); // build the vertices in an array for computing normals and eventually for // optimizations. Vert[,] vertices = new Vert[sizeX, sizeY]; float stepX = (realSizeX) / (float)sizeX; // the real dimension step for each heightmap step float stepY = (realSizeY) / (float)sizeY; float coordStepX = 1.0f / (float)sizeX; // the coordinate dimension step for each heightmap step float coordStepY = 1.0f / (float)sizeY; uint index = 0; for (int xx = 0; xx < sizeX; xx++) { for (int yy = 0; yy < sizeY; yy++) { Vert vert = new Vert(); vert.Position = new OMV.Vector3(stepX * xx, stepY * yy, heights[xx, yy]); vert.Normal = new OMV.Vector3(0f, 1f, 0f); // normal pointing up for the moment vert.TexCoord = new OMV.Vector2(coordStepX * xx, coordStepY * yy); vert.index = index++; vertices[xx, yy] = vert; } } // Pass over the far edges and make sure the mesh streaches the whole area for (int xx = 0; xx < sizeX; xx++) { vertices[xx, sizeY - 1].Position.Y = realSizeY + 1; } for (int yy = 0; yy < sizeY; yy++) { vertices[sizeX - 1, yy].Position.X = realSizeY + 1; } // Compute the normals // Take three corners of each quad and calculate the normal for the vector // a--b--e--... // | | | // d--c--h--... // The triangle a-b-d calculates the normal for a, etc for (int xx = 0; xx < sizeX - 1; xx++) { for (int yy = 0; yy < sizeY - 1; yy++) { vertices[xx, yy].Normal = MakeNormal(vertices[xx, yy], vertices[xx + 1, yy], vertices[xx, yy + 1]); } } // The vertices along the edges need an extra pass to compute the normals for (int xx = 0; xx < sizeX - 1; xx++) { vertices[xx, sizeY - 1].Normal = MakeNormal(vertices[xx, sizeY - 1], vertices[xx + 1, sizeY - 1], vertices[xx, sizeY - 2]); } for (int yy = 0; yy < sizeY - 1; yy++) { vertices[sizeX - 1, yy].Normal = MakeNormal(vertices[sizeX - 1, yy], vertices[sizeX - 1, yy + 1], vertices[sizeX - 2, yy]); } vertices[sizeX - 1, sizeY - 1].Normal = MakeNormal(vertices[sizeX - 1, sizeY - 1], vertices[sizeX - 2, sizeY - 1], vertices[sizeX - 1, sizeY - 2]); // Convert our vertices into the format expected by the caller List <OMVR.Vertex> vertexList = new List <OMVR.Vertex>(); for (int xx = 0; xx < sizeX; xx++) { for (int yy = 0; yy < sizeY; yy++) { Vert vert = vertices[xx, yy]; OMVR.Vertex oVert = new OMVR.Vertex(); oVert.Position = vert.Position; oVert.Normal = vert.Normal; oVert.TexCoord = vert.TexCoord; vertexList.Add(oVert); } } // Make indices for all the vertices. // Pass over the matrix and create two triangles for each quad // // 00-----01 // | f1 /| // | / | // | / f2 | // 10-----11 // // Counter Clockwise for (int xx = 0; xx < sizeX - 1; xx++) { for (int yy = 0; yy < sizeY - 1; yy++) { indices.Add((ushort)vertices[xx + 0, yy + 0].index); indices.Add((ushort)vertices[xx + 1, yy + 0].index); indices.Add((ushort)vertices[xx + 0, yy + 1].index); indices.Add((ushort)vertices[xx + 0, yy + 1].index); indices.Add((ushort)vertices[xx + 1, yy + 0].index); indices.Add((ushort)vertices[xx + 1, yy + 1].index); } } OMVR.Face aface = new OMVR.Face(); aface.Vertices = vertexList; aface.Indices = indices; return(aface); }
/// <summary> /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this /// routine since all the context for finding teh texture is elsewhere. /// </summary> /// <returns>The faceted mesh or null if can't do it</returns> public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod) { byte sculptType = (byte)prim.Sculpt.Type; bool mirror = ((sculptType & 128) != 0); bool invert = ((sculptType & 64) != 0); // mirror = false; // TODO: libomv doesn't support these and letting them flop around causes problems // invert = false; OMV.SculptType omSculptType = (OMV.SculptType)(sculptType & 0x07); PrimMesher.SculptMesh.SculptType smSculptType; switch (omSculptType) { case OpenMetaverse.SculptType.Cylinder: smSculptType = PrimMesher.SculptMesh.SculptType.cylinder; break; case OpenMetaverse.SculptType.Plane: smSculptType = PrimMesher.SculptMesh.SculptType.plane; break; case OpenMetaverse.SculptType.Sphere: smSculptType = PrimMesher.SculptMesh.SculptType.sphere; break; case OpenMetaverse.SculptType.Torus: smSculptType = PrimMesher.SculptMesh.SculptType.torus; break; default: smSculptType = PrimMesher.SculptMesh.SculptType.plane; break; } // The lod for sculpties is the resolution of the texture passed. // The first guess is 1:1 then lower resolutions after that // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height); int mesherLod = 32; // number used in Idealist viewer switch (lod) { case OMVR.DetailLevel.Highest: break; case OMVR.DetailLevel.High: break; case OMVR.DetailLevel.Medium: mesherLod /= 2; break; case OMVR.DetailLevel.Low: mesherLod /= 4; break; } PrimMesher.SculptMesh newMesh = new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, mirror, invert); int numPrimFaces = 1; // a scuplty has only one face // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List<OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List<OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List<OMVR.PathPoint>(); for (int ii = 0; ii < numPrimFaces; ii++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List<OMVR.Vertex>(); oface.Indices = new List<ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)ii); int faceVertices = 0; foreach (PrimMesher.ViewerFace vface in newMesh.viewerFaces) { OMVR.Vertex vert = new OMVR.Vertex(); vert.Position = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z); vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V); vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z); oface.Vertices.Add(vert); vert = new OMVR.Vertex(); vert.Position = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z); vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V); vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z); oface.Vertices.Add(vert); vert = new OMVR.Vertex(); vert.Position = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z); vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V); vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z); oface.Vertices.Add(vert); oface.Indices.Add((ushort)(faceVertices * 3 + 0)); oface.Indices.Add((ushort)(faceVertices * 3 + 1)); oface.Indices.Add((ushort)(faceVertices * 3 + 2)); faceVertices++; } if (faceVertices > 0) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return omvrmesh; }
/// <summary> /// Load the mesh from a stream /// </summary> /// <param name="filename">The filename and path of the file containing the mesh data</param> public virtual void LoadMesh(string filename) { using(FileStream meshData = new FileStream(filename, FileMode.Open, FileAccess.Read)) using (EndianAwareBinaryReader reader = new EndianAwareBinaryReader(meshData)) { Header = TrimAt0(reader.ReadString(24)); if (!String.Equals(Header, MeshHeader)) throw new FileLoadException("Unrecognized mesh format"); // Populate base mesh parameters HasWeights = (reader.ReadByte() != 0); HasDetailTexCoords = (reader.ReadByte() != 0); Position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); RotationAngles = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); /* RotationOrder = */ reader.ReadByte(); Scale = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); // Populate the vertex array NumVertices = reader.ReadUInt16(); Vertices = new Vertex[NumVertices]; for (int i = 0; i < NumVertices; i++) Vertices[i].Coord = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); for (int i = 0; i < NumVertices; i++) Vertices[i].Normal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); for (int i = 0; i < NumVertices; i++) Vertices[i].BiNormal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); for (int i = 0; i < NumVertices; i++) Vertices[i].TexCoord = new Vector2(reader.ReadSingle(), reader.ReadSingle()); if (HasDetailTexCoords) { for (int i = 0; i < NumVertices; i++) Vertices[i].DetailTexCoord = new Vector2(reader.ReadSingle(), reader.ReadSingle()); } if (HasWeights) { for (int i = 0; i < NumVertices; i++) Vertices[i].Weight = reader.ReadSingle(); } NumFaces = reader.ReadUInt16(); Faces = new Face[NumFaces]; for (int i = 0; i < NumFaces; i++) Faces[i].Indices = new[] { reader.ReadInt16(), reader.ReadInt16(), reader.ReadInt16() }; if (HasWeights) { NumSkinJoints = reader.ReadUInt16(); SkinJoints = new string[NumSkinJoints]; for (int i = 0; i < NumSkinJoints; i++) { SkinJoints[i] = TrimAt0(reader.ReadString(64)); } } else { NumSkinJoints = 0; SkinJoints = new string[0]; } // Grab morphs List<Morph> morphs = new List<Morph>(); string morphName = TrimAt0(reader.ReadString(64)); while (morphName != MorphFooter) { if (reader.BaseStream.Position + 48 >= reader.BaseStream.Length) throw new FileLoadException("Encountered end of file while parsing morphs"); Morph morph = new Morph(); morph.Name = morphName; morph.NumVertices = reader.ReadInt32(); morph.Vertices = new MorphVertex[morph.NumVertices]; for (int i = 0; i < morph.NumVertices; i++) { morph.Vertices[i].VertexIndex = reader.ReadUInt32(); morph.Vertices[i].Coord = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); morph.Vertices[i].Normal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); morph.Vertices[i].BiNormal = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); morph.Vertices[i].TexCoord = new Vector2(reader.ReadSingle(), reader.ReadSingle()); } morphs.Add(morph); // Grab the next name morphName = TrimAt0(reader.ReadString(64)); } Morphs = morphs.ToArray(); // Check if there are remaps or if we're at the end of the file if (reader.BaseStream.Position < reader.BaseStream.Length - 1) { NumRemaps = reader.ReadInt32(); VertexRemaps = new VertexRemap[NumRemaps]; for (int i = 0; i < NumRemaps; i++) { VertexRemaps[i].RemapSource = reader.ReadInt32(); VertexRemaps[i].RemapDestination = reader.ReadInt32(); } } else { NumRemaps = 0; VertexRemaps = new VertexRemap[0]; } } // uncompress the skin weights if (Skeleton != null) { // some meshes aren't weighted, which doesn't make much sense. // we check for left and right eyeballs, and assign them a 100% // to their respective bone List<string> expandedJointList = Skeleton.BuildExpandedJointList(SkinJoints); if (expandedJointList.Count == 0) { if (Name == "eyeBallLeftMesh") { expandedJointList.AddRange(new[] { "mEyeLeft", "mSkull" }); } else if (Name == "eyeBallRightMesh") { expandedJointList.AddRange(new[] { "mEyeRight", "mSkull" }); } } if (expandedJointList.Count > 0) ExpandCompressedSkinWeights(expandedJointList); } }
public RenderingMesh GetRenderingMesh(LLPrimitive prim, DetailLevel lod) { RenderingMesh mesh; ulong physicsKey = prim.GetPhysicsKey(); // Try a cache lookup first if (m_meshCache != null && m_meshCache.TryGetRenderingMesh(physicsKey, lod, out mesh)) { return(mesh); } // Can't go any further without a prim renderer if (m_renderer == null) { return(null); } // Convert our DetailLevel to the OpenMetaverse.Rendering DetailLevel OpenMetaverse.Rendering.DetailLevel detailLevel; switch (lod) { case DetailLevel.Low: detailLevel = OpenMetaverse.Rendering.DetailLevel.Low; break; case DetailLevel.Medium: detailLevel = OpenMetaverse.Rendering.DetailLevel.Medium; break; case DetailLevel.High: detailLevel = OpenMetaverse.Rendering.DetailLevel.High; break; case DetailLevel.Highest: default: detailLevel = OpenMetaverse.Rendering.DetailLevel.Highest; break; } FacetedMesh facetedMesh = null; if (prim.Prim.Sculpt != null && prim.Prim.Sculpt.SculptTexture != UUID.Zero) { // Sculpty meshing Bitmap sculptTexture = GetSculptMap(prim.Prim.Sculpt.SculptTexture); if (sculptTexture != null) { facetedMesh = m_renderer.GenerateFacetedSculptMesh(prim.Prim, sculptTexture, detailLevel); } } else { // Basic prim meshing facetedMesh = m_renderer.GenerateFacetedMesh(prim.Prim, detailLevel); } if (facetedMesh != null) { #region FacetedMesh to RenderingMesh Conversion mesh = new RenderingMesh(); mesh.Faces = new RenderingMesh.Face[facetedMesh.Faces.Count]; for (int i = 0; i < facetedMesh.Faces.Count; i++) { Face face = facetedMesh.Faces[i]; Vertex[] vertices = new Vertex[face.Vertices.Count]; for (int j = 0; j < face.Vertices.Count; j++) { OpenMetaverse.Rendering.Vertex omvrVertex = face.Vertices[j]; vertices[j] = new Vertex { Position = omvrVertex.Position, Normal = omvrVertex.Normal, TexCoord = omvrVertex.TexCoord }; } ushort[] indices = face.Indices.ToArray(); mesh.Faces[i] = new RenderingMesh.Face { Vertices = vertices, Indices = indices }; } #endregion FacetedMesh to RenderingMesh Conversion // Store the result in the mesh cache, if we have one if (m_meshCache != null) { m_meshCache.StoreRenderingMesh(physicsKey, lod, mesh); } return(mesh); } else { return(null); } }
private static void LerpPlanarVertex(Vertex v0, Vertex v1, Vertex v2, ref Vertex vout, float coef01, float coef02) { vout.Position = v0.Position + ((v1.Position - v0.Position) * coef01) + ((v2.Position - v0.Position) * coef02); vout.TexCoord = v0.TexCoord + ((v1.TexCoord - v0.TexCoord) * coef01) + ((v2.TexCoord - v0.TexCoord) * coef02); vout.Normal = v0.Normal; vout.Binormal = v0.Binormal; }
private static void CreateSide(ref Face face, LLObject.ObjectData prim, List<Vertex> primVertices, Path path, Profile profile) { bool flat = (face.Mask & FaceMask.Flat) != 0; int maxS = profile.Positions.Count; int s, t, i; float ss, tt; int numVertices = face.NumS * face.NumT; int numIndices = (face.NumS - 1) * (face.NumT - 1) * 6; face.Center = Vector3.Zero; int beginSTex = (int)Math.Floor(profile.Positions[face.BeginS].Z); int numS = (((face.Mask & FaceMask.Inner) != 0) && ((face.Mask & FaceMask.Flat) != 0) && face.NumS > 2) ? face.NumS / 2 : face.NumS; int curVertex = 0; // Copy the vertices into the array for (t = face.BeginT; t < face.BeginT + face.NumT; t++) { tt = path.Points[t].TexT; for (s = 0; s < numS; s++) { if ((face.Mask & FaceMask.End) != 0) { if (s != 0) ss = 1f; else ss = 0f; } else { // Get s value for tex-coord if (!flat) ss = profile.Positions[face.BeginS + s].Z; else ss = profile.Positions[face.BeginS + s].Z - beginSTex; } // Check to see if this triangle wraps around the array if (face.BeginS + s >= maxS) i = face.BeginS + s + maxS * (t - 1); // We're wrapping else i = face.BeginS + s + maxS * t; Vertex vertex = new Vertex(); vertex.Position = primVertices[i].Position; vertex.TexCoord = new Vector2(ss, tt); vertex.Normal = Vector3.Zero; vertex.Binormal = Vector3.Zero; if (curVertex == 0) face.MinExtent = face.MaxExtent = primVertices[i].Position; else UpdateMinMax(ref face, primVertices[i].Position); face.Vertices.Add(vertex); ++curVertex; if (((face.Mask & FaceMask.Inner) != 0) && ((face.Mask & FaceMask.Flat) != 0) && face.NumS > 2 && s > 0) { vertex.Position = primVertices[i].Position; //vertex.TexCoord = new Vector2(ss, tt); //vertex.Normal = Vector3.Zero; //vertex.Binormal = Vector3.Zero; face.Vertices.Add(vertex); ++curVertex; } } if (((face.Mask & FaceMask.Inner) != 0) && ((face.Mask & FaceMask.Flat) != 0) && face.NumS > 2) { if ((face.Mask & FaceMask.Open) != 0) s = numS - 1; else s = 0; i = face.BeginS + s + maxS * t; ss = profile.Positions[face.BeginS + s].Z - beginSTex; Vertex vertex = new Vertex(); vertex.Position = primVertices[i].Position; vertex.TexCoord = new Vector2(ss, tt); vertex.Normal = Vector3.Zero; vertex.Binormal = Vector3.Zero; UpdateMinMax(ref face, vertex.Position); face.Vertices.Add(vertex); ++curVertex; } } face.Center = (face.MinExtent + face.MaxExtent) * 0.5f; bool flatFace = ((face.Mask & FaceMask.Flat) != 0); // Now we generate the indices for (t = 0; t < (face.NumT - 1); t++) { for (s = 0; s < (face.NumS - 1); s++) { face.Indices.Add((ushort)(s + face.NumS * t)); // Bottom left face.Indices.Add((ushort)(s + 1 + face.NumS * (t + 1))); // Top right face.Indices.Add((ushort)(s + face.NumS * (t + 1))); // Top left face.Indices.Add((ushort)(s + face.NumS * t)); // Bottom left face.Indices.Add((ushort)(s + 1 + face.NumS * t)); // Bottom right face.Indices.Add((ushort)(s + 1 + face.NumS * (t + 1))); // Top right face.Edge.Add((face.NumS - 1) * 2 * t + s * 2 + 1); // Bottom left/top right neighbor face if (t < face.NumT - 2) // Top right/top left neighbor face face.Edge.Add((face.NumS - 1) * 2 * (t + 1) + s * 2 + 1); else if (face.NumT <= 3 || path.Open) // No neighbor face.Edge.Add(-1); else // Wrap on T face.Edge.Add(s * 2 + 1); if (s > 0) // Top left/bottom left neighbor face face.Edge.Add((face.NumS - 1) * 2 * t + s * 2 - 1); else if (flatFace || profile.Open) // No neighbor face.Edge.Add(-1); else // Wrap on S face.Edge.Add((face.NumS - 1) * 2 * t + (face.NumS - 2) * 2 + 1); if (t > 0) // Bottom left/bottom right neighbor face face.Edge.Add((face.NumS - 1) * 2 * (t - 1) + s * 2); else if (face.NumT <= 3 || path.Open) // No neighbor face.Edge.Add(-1); else // Wrap on T face.Edge.Add((face.NumS - 1) * 2 * (face.NumT - 2) + s * 2); if (s < face.NumS - 2) // Bottom right/top right neighbor face face.Edge.Add((face.NumS - 1) * 2 * t + (s + 1) * 2); else if (flatFace || profile.Open) // No neighbor face.Edge.Add(-1); else // Wrap on S face.Edge.Add((face.NumS - 1) * 2 * t); face.Edge.Add((face.NumS - 1) * 2 * t + s * 2); // Top right/bottom left neighbor face } } // Generate normals, loop through each triangle for (i = 0; i < face.Indices.Count / 3; i++) { Vertex v0 = face.Vertices[face.Indices[i * 3 + 0]]; Vertex v1 = face.Vertices[face.Indices[i * 3 + 1]]; Vertex v2 = face.Vertices[face.Indices[i * 3 + 2]]; // Calculate triangle normal Vector3 norm = (v0.Position - v1.Position) % (v0.Position - v2.Position); // Calculate binormal Vector3 binorm = CalcBinormalFromTriangle(v0.Position, v0.TexCoord, v1.Position, v1.TexCoord, v2.Position, v2.TexCoord); // Add triangle normal to vertices for (int j = 0; j < 3; j++) { Vertex vertex = face.Vertices[face.Indices[i * 3 + j]]; vertex.Normal += norm; vertex.Binormal += binorm; face.Vertices[face.Indices[i * 3 + j]] = vertex; } // Even out quad contributions if (i % 2 == 0) { Vertex vertex = face.Vertices[face.Indices[i * 3 + 2]]; vertex.Normal += norm; vertex.Binormal += binorm; face.Vertices[face.Indices[i * 3 + 2]] = vertex; } else { Vertex vertex = face.Vertices[face.Indices[i * 3 + 1]]; vertex.Normal += norm; vertex.Binormal += binorm; face.Vertices[face.Indices[i * 3 + 1]] = vertex; } } // Adjust normals based on wrapping and stitching Vector3 test1 = face.Vertices[0].Position - face.Vertices[face.NumS * (face.NumT - 2)].Position; Vector3 test2 = face.Vertices[face.NumS - 1].Position - face.Vertices[face.NumS * (face.NumT - 2) + face.NumS - 1].Position; bool sBottomConverges = (test1.LengthSquared() < 0.000001f); bool sTopConverges = (test2.LengthSquared() < 0.000001f); // TODO: Sculpt support Primitive.SculptType sculptType = Primitive.SculptType.None; if (sculptType == Primitive.SculptType.None) { if (!path.Open) { // Wrap normals on T for (i = 0; i < face.NumS; i++) { Vector3 norm = face.Vertices[i].Normal + face.Vertices[face.NumS * (face.NumT - 1) + i].Normal; Vertex vertex = face.Vertices[i]; vertex.Normal = norm; face.Vertices[i] = vertex; vertex = face.Vertices[face.NumS * (face.NumT - 1) + i]; vertex.Normal = norm; face.Vertices[face.NumS * (face.NumT - 1) + i] = vertex; } } if (!profile.Open && !sBottomConverges) { // Wrap normals on S for (i = 0; i < face.NumT; i++) { Vector3 norm = face.Vertices[face.NumS * i].Normal + face.Vertices[face.NumS * i + face.NumS - 1].Normal; Vertex vertex = face.Vertices[face.NumS * i]; vertex.Normal = norm; face.Vertices[face.NumS * i] = vertex; vertex = face.Vertices[face.NumS * i + face.NumS - 1]; vertex.Normal = norm; face.Vertices[face.NumS * i + face.NumS - 1] = vertex; } } if (prim.PathCurve == LLObject.PathCurve.Circle && prim.ProfileCurve == LLObject.ProfileCurve.HalfCircle) { if (sBottomConverges) { // All lower S have same normal Vector3 unitX = new Vector3(1f, 0f, 0f); for (i = 0; i < face.NumT; i++) { Vertex vertex = face.Vertices[face.NumS * i]; vertex.Normal = unitX; face.Vertices[face.NumS * i] = vertex; } } if (sTopConverges) { // All upper S have same normal Vector3 negUnitX = new Vector3(-1f, 0f, 0f); for (i = 0; i < face.NumT; i++) { Vertex vertex = face.Vertices[face.NumS * i + face.NumS - 1]; vertex.Normal = negUnitX; face.Vertices[face.NumS * i + face.NumS - 1] = vertex; } } } } else { // FIXME: Sculpt support } // Normalize normals and binormals for (i = 0; i < face.Vertices.Count; i++) { Vertex vertex = face.Vertices[i]; vertex.Normal.Normalize(); vertex.Binormal.Normalize(); face.Vertices[i] = vertex; } }
/// <summary> /// Method for generating mesh Face from a heightmap /// </summary> /// <param name="zMap">Two dimension array of floats containing height information</param> /// <param name="xBegin">Starting value for X</param> /// <param name="xEnd">Max value for X</param> /// <param name="yBegin">Starting value for Y</param> /// <param name="yEnd">Max value of Y</param> /// <returns></returns> public OMVR.Face TerrainMesh(float[,] zMap, float xBegin, float xEnd, float yBegin, float yEnd) { PrimMesher.SculptMesh newMesh = new PrimMesher.SculptMesh(zMap, xBegin, xEnd, yBegin, yEnd, true); OMVR.Face terrain = new OMVR.Face(); int faceVertices = newMesh.coords.Count; terrain.Vertices = new List<Vertex>(faceVertices); terrain.Indices = new List<ushort>(newMesh.faces.Count * 3); for (int j = 0; j < faceVertices; j++) { var vert = new OMVR.Vertex(); vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z); vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z); vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V); terrain.Vertices.Add(vert); } for (int j = 0; j < newMesh.faces.Count; j++) { terrain.Indices.Add((ushort)newMesh.faces[j].v1); terrain.Indices.Add((ushort)newMesh.faces[j].v2); terrain.Indices.Add((ushort)newMesh.faces[j].v3); } return terrain; }
/// <summary> /// Generates a a series of faces, each face containing a mesh and /// metadata /// </summary> /// <param name="prim">Primitive to generate the mesh from</param> /// <param name="lod">Level of detail to generate the mesh at</param> /// <returns>The generated mesh</returns > public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod) { bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle); PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true); if (newPrim == null) return null; int numViewerFaces = newPrim.viewerFaces.Count; int numPrimFaces = newPrim.numPrimFaces; for (uint i = 0; i < numViewerFaces; i++) { PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i]; if (isSphere) { vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f; vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f; vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f; } } // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List<OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List<OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List<OMVR.PathPoint>(); Dictionary<OMV.Vector3, int> vertexAccount = new Dictionary<OMV.Vector3, int>(); for (int ii = 0; ii < numPrimFaces; ii++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List<OMVR.Vertex>(); oface.Indices = new List<ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)ii); int faceVertices = 0; vertexAccount.Clear(); OMV.Vector3 pos; int indx; OMVR.Vertex vert; foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces) { if (vface.primFaceNumber == ii) { faceVertices++; pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z); if (vertexAccount.ContainsKey(pos)) { // we aleady have this vertex in the list. Just point the index at it oface.Indices.Add((ushort)vertexAccount[pos]); } else { // the vertex is not in the list. Add it and the new index. vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V); vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V); vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V); vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } } } if (faceVertices > 0) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return omvrmesh; }
/// <summary> /// Generates a a series of faces, each face containing a mesh and /// metadata /// </summary> /// <param name="prim">Primitive to generate the mesh from</param> /// <param name="lod">Level of detail to generate the mesh at</param> /// <returns>The generated mesh</returns > public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod) { bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle); PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true); if (newPrim == null) { return(null); } int numViewerFaces = newPrim.viewerFaces.Count; int numPrimFaces = newPrim.numPrimFaces; for (uint i = 0; i < numViewerFaces; i++) { PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i]; if (isSphere) { vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f; vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f; vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f; } } // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List <OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List <OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List <OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List <OMVR.PathPoint>(); Dictionary <OMV.Vector3, int> vertexAccount = new Dictionary <OMV.Vector3, int>(); for (int ii = 0; ii < numPrimFaces; ii++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List <OMVR.Vertex>(); oface.Indices = new List <ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)ii); int faceVertices = 0; vertexAccount.Clear(); OMV.Vector3 pos; int indx; OMVR.Vertex vert; foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces) { if (vface.primFaceNumber == ii) { faceVertices++; pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z); if (vertexAccount.ContainsKey(pos)) { // we aleady have this vertex in the list. Just point the index at it oface.Indices.Add((ushort)vertexAccount[pos]); } else { // the vertex is not in the list. Add it and the new index. vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V); vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V); vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V); vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } } } if (faceVertices > 0) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return(omvrmesh); }
private List<Face> GenerateFaces(Primitive prim) { MeshmerizerMesh meshmerizer = new MeshmerizerMesh(); meshmerizer = GenerateMeshmerizerMesh(prim); // Create the vertex array List<Vertex> vertices = new List<Vertex>(meshmerizer.primMesh.coords.Count); for (int i = 0; i < meshmerizer.primMesh.coords.Count; i++) { Coord c = meshmerizer.primMesh.coords[i]; Vertex vertex = new Vertex(); vertex.Position = new Vector3(c.X, c.Y, c.Z); vertices.Add(vertex); } // Create the index array List<ushort> indices = new List<ushort>(meshmerizer.primMesh.faces.Count * 3); for (int i = 0; i < meshmerizer.primMesh.faces.Count; i++) { MeshmerizerFace f = meshmerizer.primMesh.faces[i]; indices.Add((ushort)f.v1); indices.Add((ushort)f.v2); indices.Add((ushort)f.v3); } Face face = new Face(); face.Edge = new List<int>(); face.TextureFace = prim.Textures.DefaultTexture; face.Vertices = vertices; face.Indices = indices; List<Face> faces = new List<Face>(1); faces.Add(face); return faces; }
//public void SetView(OpenMetaverse.Vector3 center, int roll, int pitch, int yaw, int zoom) //{ // this.Center = center; // scrollRoll.Value = roll; // scrollPitch.Value = pitch; // scrollYaw.Value = yaw; // scrollZoom.Value = zoom; //} public static FacetedMesh GenerateFacetedMesh(Primitive prim, OSDMap MeshData, DetailLevel LOD) { FacetedMesh ret = new FacetedMesh(); ret.Faces = new List<Face>(); ret.Prim = prim; ret.Profile = new Profile(); ret.Profile.Faces = new List<ProfileFace>(); ret.Profile.Positions = new List<OpenMetaverse.Vector3>(); ret.Path = new OpenMetaverse.Rendering.Path(); ret.Path.Points = new List<PathPoint>(); try { OSD facesOSD = null; switch (LOD) { default: case DetailLevel.Highest: facesOSD = MeshData["high_lod"]; break; case DetailLevel.High: facesOSD = MeshData["medium_lod"]; break; case DetailLevel.Medium: facesOSD = MeshData["low_lod"]; break; case DetailLevel.Low: facesOSD = MeshData["lowest_lod"]; break; } if (facesOSD == null || !(facesOSD is OSDArray)) { return ret; } OSDArray decodedMeshOsdArray = (OSDArray)facesOSD; for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++) { OSD subMeshOsd = decodedMeshOsdArray[faceNr]; Face oface = new Face(); oface.ID = faceNr; oface.Vertices = new List<Vertex>(); oface.Indices = new List<ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)faceNr); if (subMeshOsd is OSDMap) { OSDMap subMeshMap = (OSDMap)subMeshOsd; OpenMetaverse.Vector3 posMax = new OpenMetaverse.Vector3(); posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"]; OpenMetaverse.Vector3 posMin = new OpenMetaverse.Vector3(); posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"]; OpenMetaverse.Vector2 texPosMax = new OpenMetaverse.Vector2(); texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"]; OpenMetaverse.Vector2 texPosMin = new OpenMetaverse.Vector2(); texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"]; byte[] posBytes = subMeshMap["Position"]; byte[] norBytes = subMeshMap["Normal"]; byte[] texBytes = subMeshMap["TexCoord0"]; for (int i = 0; i < posBytes.Length; i += 6) { ushort uX = Utils.BytesToUInt16(posBytes, i); ushort uY = Utils.BytesToUInt16(posBytes, i + 2); ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); Vertex vx = new Vertex(); vx.Position = new OpenMetaverse.Vector3( Utils.UInt16ToFloat(uX, posMin.X, posMax.X), Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y), Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z)); ushort nX = Utils.BytesToUInt16(norBytes, i); ushort nY = Utils.BytesToUInt16(norBytes, i + 2); ushort nZ = Utils.BytesToUInt16(norBytes, i + 4); vx.Normal = new OpenMetaverse.Vector3( Utils.UInt16ToFloat(nX, posMin.X, posMax.X), Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y), Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z)); var vertexIndexOffset = oface.Vertices.Count * 4; if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4) { ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset); ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2); vx.TexCoord = new OpenMetaverse.Vector2( Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X), Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y)); } oface.Vertices.Add(vx); } byte[] triangleBytes = subMeshMap["TriangleList"]; for (int i = 0; i < triangleBytes.Length; i += 6) { ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i)); oface.Indices.Add(v1); ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2)); oface.Indices.Add(v2); ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4)); oface.Indices.Add(v3); } } ret.Faces.Add(oface); } } catch (Exception ex) { Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning); } return ret; }
public RenderingMesh GetRenderingMesh(LLPrimitive prim, DetailLevel lod) { RenderingMesh mesh; ulong physicsKey = prim.GetPhysicsKey(); // Try a cache lookup first if (m_meshCache != null && m_meshCache.TryGetRenderingMesh(physicsKey, lod, out mesh)) return mesh; // Can't go any further without a prim renderer if (m_renderer == null) return null; // Convert our DetailLevel to the OpenMetaverse.Rendering DetailLevel OpenMetaverse.Rendering.DetailLevel detailLevel; switch (lod) { case DetailLevel.Low: detailLevel = OpenMetaverse.Rendering.DetailLevel.Low; break; case DetailLevel.Medium: detailLevel = OpenMetaverse.Rendering.DetailLevel.Medium; break; case DetailLevel.High: detailLevel = OpenMetaverse.Rendering.DetailLevel.High; break; case DetailLevel.Highest: default: detailLevel = OpenMetaverse.Rendering.DetailLevel.Highest; break; } FacetedMesh facetedMesh = null; if (prim.Prim.Sculpt != null && prim.Prim.Sculpt.SculptTexture != UUID.Zero) { // Sculpty meshing Bitmap sculptTexture = GetSculptMap(prim.Prim.Sculpt.SculptTexture); if (sculptTexture != null) facetedMesh = m_renderer.GenerateFacetedSculptMesh(prim.Prim, sculptTexture, detailLevel); } else { // Basic prim meshing facetedMesh = m_renderer.GenerateFacetedMesh(prim.Prim, detailLevel); } if (facetedMesh != null) { #region FacetedMesh to RenderingMesh Conversion mesh = new RenderingMesh(); mesh.Faces = new RenderingMesh.Face[facetedMesh.Faces.Count]; for (int i = 0; i < facetedMesh.Faces.Count; i++) { Face face = facetedMesh.Faces[i]; Vertex[] vertices = new Vertex[face.Vertices.Count]; for (int j = 0; j < face.Vertices.Count; j++) { OpenMetaverse.Rendering.Vertex omvrVertex = face.Vertices[j]; vertices[j] = new Vertex { Position = omvrVertex.Position, Normal = omvrVertex.Normal, TexCoord = omvrVertex.TexCoord }; } ushort[] indices = face.Indices.ToArray(); mesh.Faces[i] = new RenderingMesh.Face { Vertices = vertices, Indices = indices }; } #endregion FacetedMesh to RenderingMesh Conversion // Store the result in the mesh cache, if we have one if (m_meshCache != null) m_meshCache.StoreRenderingMesh(physicsKey, lod, mesh); return mesh; } else { return null; } }
/// <summary> /// Generates a a series of faces, each face containing a mesh and /// metadata /// </summary> /// <param name="prim">Primitive to generate the mesh from</param> /// <param name="lod">Level of detail to generate the mesh at</param> /// <returns>The generated mesh</returns > public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod) { bool isSphere = ((OMV.ProfileCurve)(prim.PrimData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle); PrimMesher.PrimMesh newPrim = GeneratePrimMesh(prim, lod, true); if (newPrim == null) return null; // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List<OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List<OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List<OMVR.PathPoint>(); var indexer = newPrim.GetVertexIndexer(); for (int i = 0; i < indexer.numPrimFaces; i++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List<OMVR.Vertex>(); oface.Indices = new List<ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)i); for (int j = 0; j < indexer.viewerVertices[i].Count; j++) { var vert = new OMVR.Vertex(); var m = indexer.viewerVertices[i][j]; vert.Position = new Vector3(m.v.X, m.v.Y, m.v.Z); vert.Normal = new Vector3(m.n.X, m.n.Y, m.n.Z); vert.TexCoord = new OMV.Vector2(m.uv.U, 1.0f - m.uv.V); oface.Vertices.Add(vert); } for (int j = 0; j < indexer.viewerPolygons[i].Count; j++) { var p = indexer.viewerPolygons[i][j]; // Skip "degenerate faces" where the same vertex appears twice in the same tri if (p.v1 == p.v2 || p.v1 == p.v2 || p.v2 == p.v3) continue; oface.Indices.Add((ushort)p.v1); oface.Indices.Add((ushort)p.v2); oface.Indices.Add((ushort)p.v3); } omvrmesh.Faces.Add(oface); } return omvrmesh; }
/// <summary> /// Generates a a series of faces, each face containing a mesh and /// metadata /// </summary> /// <param name="prim">Primitive to generate the mesh from</param> /// <param name="lod">Level of detail to generate the mesh at</param> /// <returns>The generated mesh</returns > public OMVR.FacetedMesh GenerateFacetedMesh(OMV.Primitive prim, OMVR.DetailLevel lod) { OMV.Primitive.ConstructionData primData = prim.PrimData; int sides = 4; int hollowsides = 4; float profileBegin = primData.ProfileBegin; float profileEnd = primData.ProfileEnd; bool isSphere = false; if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.Circle) { switch (lod) { case OMVR.DetailLevel.Low: sides = 6; break; case OMVR.DetailLevel.Medium: sides = 12; break; default: sides = 24; break; } } else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.EqualTriangle) sides = 3; else if ((OMV.ProfileCurve)(primData.profileCurve & 0x07) == OMV.ProfileCurve.HalfCircle) { // half circle, prim is a sphere isSphere = true; switch (lod) { case OMVR.DetailLevel.Low: sides = 6; break; case OMVR.DetailLevel.Medium: sides = 12; break; default: sides = 24; break; } profileBegin = 0.5f * profileBegin + 0.5f; profileEnd = 0.5f * profileEnd + 0.5f; } if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Same) hollowsides = sides; else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Circle) { switch (lod) { case OMVR.DetailLevel.Low: hollowsides = 6; break; case OMVR.DetailLevel.Medium: hollowsides = 12; break; default: hollowsides = 24; break; } } else if ((OMV.HoleType)primData.ProfileHole == OMV.HoleType.Triangle) hollowsides = 3; PrimMesher.PrimMesh newPrim = new PrimMesher.PrimMesh(sides, profileBegin, profileEnd, (float)primData.ProfileHollow, hollowsides); newPrim.viewerMode = true; newPrim.holeSizeX = primData.PathScaleX; newPrim.holeSizeY = primData.PathScaleY; newPrim.pathCutBegin = primData.PathBegin; newPrim.pathCutEnd = primData.PathEnd; newPrim.topShearX = primData.PathShearX; newPrim.topShearY = primData.PathShearY; newPrim.radius = primData.PathRadiusOffset; newPrim.revolutions = primData.PathRevolutions; newPrim.skew = primData.PathSkew; switch (lod) { case OMVR.DetailLevel.Low: newPrim.stepsPerRevolution = 6; break; case OMVR.DetailLevel.Medium: newPrim.stepsPerRevolution = 12; break; default: newPrim.stepsPerRevolution = 24; break; } if ((primData.PathCurve == OMV.PathCurve.Line) || (primData.PathCurve == OMV.PathCurve.Flexible)) { newPrim.taperX = 1.0f - primData.PathScaleX; newPrim.taperY = 1.0f - primData.PathScaleY; newPrim.twistBegin = (int)(180 * primData.PathTwistBegin); newPrim.twistEnd = (int)(180 * primData.PathTwist); newPrim.ExtrudeLinear(); } else { newPrim.taperX = primData.PathTaperX; newPrim.taperY = primData.PathTaperY; newPrim.twistBegin = (int)(360 * primData.PathTwistBegin); newPrim.twistEnd = (int)(360 * primData.PathTwist); newPrim.ExtrudeCircular(); } int numViewerFaces = newPrim.viewerFaces.Count; int numPrimFaces = newPrim.numPrimFaces; for (uint i = 0; i < numViewerFaces; i++) { PrimMesher.ViewerFace vf = newPrim.viewerFaces[(int)i]; if (isSphere) { vf.uv1.U = (vf.uv1.U - 0.5f) * 2.0f; vf.uv2.U = (vf.uv2.U - 0.5f) * 2.0f; vf.uv3.U = (vf.uv3.U - 0.5f) * 2.0f; } } if (m_shouldScale) { newPrim.Scale(prim.Scale.X, prim.Scale.Y, prim.Scale.Z); } // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List<OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List<OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List<OMVR.PathPoint>(); Dictionary<OMV.Vector3, int> vertexAccount = new Dictionary<OMV.Vector3, int>(); for (int ii = 0; ii < numPrimFaces; ii++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List<OMVR.Vertex>(); oface.Indices = new List<ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)ii); int faceVertices = 0; vertexAccount.Clear(); OMV.Vector3 pos; int indx; OMVR.Vertex vert; foreach (PrimMesher.ViewerFace vface in newPrim.viewerFaces) { if (vface.primFaceNumber == ii) { faceVertices++; pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z); if (vertexAccount.ContainsKey(pos)) { // we aleady have this vertex in the list. Just point the index at it oface.Indices.Add((ushort)vertexAccount[pos]); } else { // the vertex is not in the list. Add it and the new index. vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V); vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V); vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V); vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } } } if (faceVertices > 0) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return omvrmesh; }
void AddFacesFromPolyList(polylist list, mesh mesh, ModelPrim prim, Matrix4 transform) { string material = list.material; source posSrc = null; source normalSrc = null; source uvSrc = null; ulong stride = 0; int posOffset = -1; int norOffset = -1; int uvOffset = -1; foreach (var inp in list.input) { stride = Math.Max(stride, inp.offset); if (inp.semantic == "VERTEX") { posSrc = FindSource(mesh.source, mesh.vertices.input[0].source); posOffset = (int)inp.offset; } else if (inp.semantic == "NORMAL") { normalSrc = FindSource(mesh.source, inp.source); norOffset = (int)inp.offset; } else if (inp.semantic == "TEXCOORD") { uvSrc = FindSource(mesh.source, inp.source); uvOffset = (int)inp.offset; } } stride += 1; if (posSrc == null) return; var vcount = StrToArray(list.vcount); var idx = StrToArray(list.p); Vector3[] normals = null; if (normalSrc != null) { var norVal = ((float_array)normalSrc.Item).Values; normals = new Vector3[norVal.Length / 3]; for (int i = 0; i < normals.Length; i++) { normals[i] = new Vector3((float)norVal[i * 3 + 0], (float)norVal[i * 3 + 1], (float)norVal[i * 3 + 2]); normals[i] = Vector3.TransformNormal(normals[i], transform); normals[i].Normalize(); } } Vector2[] uvs = null; if (uvSrc != null) { var uvVal = ((float_array)uvSrc.Item).Values; uvs = new Vector2[uvVal.Length / 2]; for (int i = 0; i < uvs.Length; i++) { uvs[i] = new Vector2((float)uvVal[i * 2 + 0], (float)uvVal[i * 2 + 1]); } } ModelFace face = new ModelFace(); face.MaterialID = list.material; if (face.MaterialID != null) { if (MatSymTarget.ContainsKey(list.material)) { ModelMaterial mat = Materials.Find(m => m.ID == MatSymTarget[list.material]); if (mat != null) { face.Material = mat; } } } int curIdx = 0; for (int i = 0; i < vcount.Length; i++) { var nvert = vcount[i]; if (nvert < 3 || nvert > 4) { throw new InvalidDataException("Only triangles and quads supported"); } Vertex[] verts = new Vertex[nvert]; for (int j = 0; j < nvert; j++) { verts[j].Position = prim.Positions[idx[curIdx + posOffset + (int)stride * j]]; if (normals != null) { verts[j].Normal = normals[idx[curIdx + norOffset + (int)stride * j]]; } if (uvs != null) { verts[j].TexCoord = uvs[idx[curIdx + uvOffset + (int)stride * j]]; } } if (nvert == 3) // add the triangle { face.AddVertex(verts[0]); face.AddVertex(verts[1]); face.AddVertex(verts[2]); } else if (nvert == 4) // quad, add two triangles { face.AddVertex(verts[0]); face.AddVertex(verts[1]); face.AddVertex(verts[2]); face.AddVertex(verts[0]); face.AddVertex(verts[2]); face.AddVertex(verts[3]); } curIdx += (int)stride * nvert; } prim.Faces.Add(face); }
private OMVR.FacetedMesh GenerateIRendererMesh(int numPrimFaces, OMV.Primitive prim, List <PrimMesher.ViewerFace> viewerFaces) { // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List <OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List <OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List <OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List <OMVR.PathPoint>(); Dictionary <OMV.Vector3, int> vertexAccount = new Dictionary <OMV.Vector3, int>(); OMV.Vector3 pos; int indx; OMVR.Vertex vert; for (int ii = 0; ii < numPrimFaces; ii++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List <OMVR.Vertex>(); oface.Indices = new List <ushort>(); if (prim.Textures == null) { oface.TextureFace = null; } else { oface.TextureFace = prim.Textures.GetFace((uint)ii); } int faceVertices = 0; vertexAccount.Clear(); foreach (PrimMesher.ViewerFace vface in viewerFaces) { if (vface.primFaceNumber == ii) { faceVertices++; pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv1.U, vface.uv1.V); vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z); vert.Normal.Normalize(); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv2.U, vface.uv2.V); vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z); vert.Normal.Normalize(); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv3.U, vface.uv3.V); vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z); vert.Normal.Normalize(); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } } } if (faceVertices > 0) { oface.TextureFace = null; if (prim.Textures != null) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return(omvrmesh); }
/// <summary> /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this /// routine since all the context for finding teh texture is elsewhere. /// </summary> /// <returns>The faceted mesh or null if can't do it</returns> public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod) { PrimMesher.SculptMesh.SculptType smSculptType; switch (prim.Sculpt.Type) { case OpenMetaverse.SculptType.Cylinder: smSculptType = PrimMesher.SculptMesh.SculptType.cylinder; break; case OpenMetaverse.SculptType.Plane: smSculptType = PrimMesher.SculptMesh.SculptType.plane; break; case OpenMetaverse.SculptType.Sphere: smSculptType = PrimMesher.SculptMesh.SculptType.sphere; break; case OpenMetaverse.SculptType.Torus: smSculptType = PrimMesher.SculptMesh.SculptType.torus; break; default: smSculptType = PrimMesher.SculptMesh.SculptType.plane; break; } // The lod for sculpties is the resolution of the texture passed. // The first guess is 1:1 then lower resolutions after that // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height); int mesherLod = 32; // number used in Idealist viewer switch (lod) { case OMVR.DetailLevel.Highest: break; case OMVR.DetailLevel.High: break; case OMVR.DetailLevel.Medium: mesherLod /= 2; break; case OMVR.DetailLevel.Low: mesherLod /= 4; break; } PrimMesher.SculptMesh newMesh = new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert); int numPrimFaces = 1; // a scuplty has only one face // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List<OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List<OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List<OMVR.PathPoint>(); Dictionary<OMVR.Vertex, int> vertexAccount = new Dictionary<OMVR.Vertex, int>(); for (int ii = 0; ii < numPrimFaces; ii++) { vertexAccount.Clear(); OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List<OMVR.Vertex>(); oface.Indices = new List<ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)ii); int faceVertices = newMesh.coords.Count; OMVR.Vertex vert; for (int j = 0; j < faceVertices; j++) { vert = new OMVR.Vertex(); vert.Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z); vert.Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z); vert.TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V); oface.Vertices.Add(vert); } for (int j = 0; j < newMesh.faces.Count; j++) { oface.Indices.Add((ushort)newMesh.faces[j].v1); oface.Indices.Add((ushort)newMesh.faces[j].v2); oface.Indices.Add((ushort)newMesh.faces[j].v3); } if (faceVertices > 0) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return omvrmesh; }
/// <summary> /// Decodes mesh asset into FacetedMesh /// </summary> /// <param name="prim">Mesh primitive</param> /// <param name="meshAsset">Asset retrieved from the asset server</param> /// <param name="LOD">Level of detail</param> /// <param name="mesh">Resulting decoded FacetedMesh</param> /// <returns>True if mesh asset decoding was successful</returns> public static bool TryDecodeFromAsset(Primitive prim, AssetMesh meshAsset, DetailLevel LOD, out FacetedMesh mesh) { mesh = null; try { if (!meshAsset.Decode()) { return false; } OSDMap MeshData = meshAsset.MeshData; mesh = new FacetedMesh(); mesh.Faces = new List<Face>(); mesh.Prim = prim; mesh.Profile.Faces = new List<ProfileFace>(); mesh.Profile.Positions = new List<Vector3>(); mesh.Path.Points = new List<PathPoint>(); OSD facesOSD = null; switch (LOD) { default: case DetailLevel.Highest: facesOSD = MeshData["high_lod"]; break; case DetailLevel.High: facesOSD = MeshData["medium_lod"]; break; case DetailLevel.Medium: facesOSD = MeshData["low_lod"]; break; case DetailLevel.Low: facesOSD = MeshData["lowest_lod"]; break; } if (facesOSD == null || !(facesOSD is OSDArray)) { return false; } OSDArray decodedMeshOsdArray = (OSDArray)facesOSD; for (int faceNr = 0; faceNr < decodedMeshOsdArray.Count; faceNr++) { OSD subMeshOsd = decodedMeshOsdArray[faceNr]; // Decode each individual face if (subMeshOsd is OSDMap) { Face oface = new Face(); oface.ID = faceNr; oface.Vertices = new List<Vertex>(); oface.Indices = new List<ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)faceNr); OSDMap subMeshMap = (OSDMap)subMeshOsd; Vector3 posMax; Vector3 posMin; // If PositionDomain is not specified, the default is from -0.5 to 0.5 if (subMeshMap.ContainsKey("PositionDomain")) { posMax = ((OSDMap)subMeshMap["PositionDomain"])["Max"]; posMin = ((OSDMap)subMeshMap["PositionDomain"])["Min"]; } else { posMax = new Vector3(0.5f, 0.5f, 0.5f); posMin = new Vector3(-0.5f, -0.5f, -0.5f); } // Vertex positions byte[] posBytes = subMeshMap["Position"]; // Normals byte[] norBytes = null; if (subMeshMap.ContainsKey("Normal")) { norBytes = subMeshMap["Normal"]; } // UV texture map Vector2 texPosMax = Vector2.Zero; Vector2 texPosMin = Vector2.Zero; byte[] texBytes = null; if (subMeshMap.ContainsKey("TexCoord0")) { texBytes = subMeshMap["TexCoord0"]; texPosMax = ((OSDMap)subMeshMap["TexCoord0Domain"])["Max"]; texPosMin = ((OSDMap)subMeshMap["TexCoord0Domain"])["Min"]; } // Extract the vertex position data // If present normals and texture coordinates too for (int i = 0; i < posBytes.Length; i += 6) { ushort uX = Utils.BytesToUInt16(posBytes, i); ushort uY = Utils.BytesToUInt16(posBytes, i + 2); ushort uZ = Utils.BytesToUInt16(posBytes, i + 4); Vertex vx = new Vertex(); vx.Position = new Vector3( Utils.UInt16ToFloat(uX, posMin.X, posMax.X), Utils.UInt16ToFloat(uY, posMin.Y, posMax.Y), Utils.UInt16ToFloat(uZ, posMin.Z, posMax.Z)); if (norBytes != null && norBytes.Length >= i + 4) { ushort nX = Utils.BytesToUInt16(norBytes, i); ushort nY = Utils.BytesToUInt16(norBytes, i + 2); ushort nZ = Utils.BytesToUInt16(norBytes, i + 4); vx.Normal = new Vector3( Utils.UInt16ToFloat(nX, posMin.X, posMax.X), Utils.UInt16ToFloat(nY, posMin.Y, posMax.Y), Utils.UInt16ToFloat(nZ, posMin.Z, posMax.Z)); } var vertexIndexOffset = oface.Vertices.Count * 4; if (texBytes != null && texBytes.Length >= vertexIndexOffset + 4) { ushort tX = Utils.BytesToUInt16(texBytes, vertexIndexOffset); ushort tY = Utils.BytesToUInt16(texBytes, vertexIndexOffset + 2); vx.TexCoord = new Vector2( Utils.UInt16ToFloat(tX, texPosMin.X, texPosMax.X), Utils.UInt16ToFloat(tY, texPosMin.Y, texPosMax.Y)); } oface.Vertices.Add(vx); } byte[] triangleBytes = subMeshMap["TriangleList"]; for (int i = 0; i < triangleBytes.Length; i += 6) { ushort v1 = (ushort)(Utils.BytesToUInt16(triangleBytes, i)); oface.Indices.Add(v1); ushort v2 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 2)); oface.Indices.Add(v2); ushort v3 = (ushort)(Utils.BytesToUInt16(triangleBytes, i + 4)); oface.Indices.Add(v3); } mesh.Faces.Add(oface); } } } catch (Exception ex) { Logger.Log("Failed to decode mesh asset: " + ex.Message, Helpers.LogLevel.Warning); return false; } return true; }
private static void CreateCap(ref Face face, List<Vertex> primVertices, Path path, Profile profile) { int i; int numVertices = profile.Positions.Count; //int numIndices = (numVertices - 2) * 3; int maxS = profile.Positions.Count; int maxT = path.Points.Count; face.Center = Vector3.Zero; int offset = 0; if ((face.Mask & FaceMask.Top) != 0) offset = (maxT - 1) * maxS; else offset = face.BeginS; // Figure out the normal, assume all caps are flat faces. // Cross product to get normals Vector2 cuv; Vector2 minUV = Vector2.Zero; Vector2 maxUV = Vector2.Zero; // Copy the vertices into the array for (i = 0; i < numVertices; i++) { Vertex vertex = new Vertex(); if ((face.Mask & FaceMask.Top) != 0) { vertex.Position = primVertices[i + offset].Position; vertex.TexCoord.X = profile.Positions[i].X + 0.5f; vertex.TexCoord.Y = profile.Positions[i].Y + 0.5f; } else { // Mirror for underside vertex.Position = primVertices[(numVertices - 1) - i].Position; vertex.TexCoord.X = profile.Positions[i].X + 0.5f; vertex.TexCoord.Y = 0.5f - profile.Positions[i].Y; } if (i == 0) { face.MinExtent = face.MaxExtent = primVertices[offset].Position; minUV = maxUV = primVertices[offset].TexCoord; } else { UpdateMinMax(ref face, vertex.Position); UpdateMinMax(ref minUV, ref maxUV, vertex.TexCoord); } face.Vertices.Add(vertex); } face.Center = (face.MinExtent + face.MaxExtent) * 0.5f; cuv = (minUV + maxUV) * 0.5f; Vector3 binormal = CalcBinormalFromTriangle( face.Center, cuv, face.Vertices[0].Position, face.Vertices[0].TexCoord, face.Vertices[1].Position, face.Vertices[1].TexCoord); binormal.Normalize(); Vector3 d0 = face.Center - face.Vertices[0].Position; Vector3 d1 = face.Center - face.Vertices[1].Position; Vector3 normal = ((face.Mask & FaceMask.Top) != 0) ? (d0 % d1) : (d1 % d0); normal.Normalize(); // If not hollow and not open create a center point in the cap if ((face.Mask & FaceMask.Hollow) == 0 && (face.Mask & FaceMask.Open) == 0) { Vertex vertex = new Vertex(); vertex.Position = face.Center; vertex.Normal = normal; vertex.Binormal = binormal; vertex.TexCoord = cuv; face.Vertices.Add(vertex); numVertices++; } for (i = 0; i < numVertices; i++) { Vertex vertex = face.Vertices[i]; vertex.Binormal = binormal; vertex.Normal = normal; face.Vertices[i] = vertex; } if ((face.Mask & FaceMask.Hollow) != 0) { if ((face.Mask & FaceMask.Top) != 0) { // HOLLOW TOP int pt1 = 0; int pt2 = numVertices - 1; i = 0; while (pt2 - pt1 > 1) { if (use_tri_1a2(profile, pt1, pt2)) { face.Indices.Add((ushort)pt1); face.Indices.Add((ushort)(pt1 + 1)); face.Indices.Add((ushort)pt2); pt1++; } else { face.Indices.Add((ushort)pt1); face.Indices.Add((ushort)(pt2 - 1)); face.Indices.Add((ushort)pt2); pt2--; } } } else { // HOLLOW BOTTOM int pt1 = 0; int pt2 = numVertices - 1; i = 0; while (pt2 - pt1 > 1) { // Flipped backfacing from top if (use_tri_1a2(profile, pt1, pt2)) { face.Indices.Add((ushort)pt1); face.Indices.Add((ushort)pt2); face.Indices.Add((ushort)(pt1 + 1)); pt1++; } else { face.Indices.Add((ushort)pt1); face.Indices.Add((ushort)pt2); face.Indices.Add((ushort)(pt2 - 1)); pt2--; } } } } else { // SOLID OPEN TOP // SOLID CLOSED TOP // SOLID OPEN BOTTOM // SOLID CLOSED BOTTOM // Not hollow, generate the triangle fan. // This is a tri-fan, so we reuse the same first point for all triangles for (i = 0; i < numVertices - 2; i++) { face.Indices.Add((ushort)(numVertices - 1)); face.Indices.Add((ushort)i); face.Indices.Add((ushort)(i + 1)); } } }
private OMVR.FacetedMesh GenerateIRendererMesh(int numPrimFaces, OMV.Primitive prim, List<PrimMesher.ViewerFace> viewerFaces) { // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List<OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List<OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List<OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List<OMVR.PathPoint>(); Dictionary<OMV.Vector3, int> vertexAccount = new Dictionary<OMV.Vector3, int>(); OMV.Vector3 pos; int indx; OMVR.Vertex vert; for (int ii=0; ii<numPrimFaces; ii++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List<OMVR.Vertex>(); oface.Indices = new List<ushort>(); if (prim.Textures == null) { oface.TextureFace = null; } else { oface.TextureFace = prim.Textures.GetFace((uint)ii); } int faceVertices = 0; vertexAccount.Clear(); foreach (PrimMesher.ViewerFace vface in viewerFaces) { if (vface.primFaceNumber == ii) { faceVertices++; pos = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv1.U, vface.uv1.V); vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z); vert.Normal.Normalize(); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv2.U, vface.uv2.V); vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z); vert.Normal.Normalize(); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } pos = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z); if (vertexAccount.ContainsKey(pos)) { oface.Indices.Add((ushort)vertexAccount[pos]); } else { vert = new OMVR.Vertex(); vert.Position = pos; vert.TexCoord = new OMV.Vector2(vface.uv3.U, vface.uv3.V); vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z); vert.Normal.Normalize(); oface.Vertices.Add(vert); indx = oface.Vertices.Count - 1; vertexAccount.Add(pos, indx); oface.Indices.Add((ushort)indx); } } } if (faceVertices > 0) { oface.TextureFace = null; if (prim.Textures != null) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return omvrmesh; }
private static void CreateUnCutCubeCap(ref Face face, List<Vertex> primVertices, Path path, Profile profile) { int maxS = profile.Positions.Count; int maxT = path.Points.Count; int gridSize = (profile.Positions.Count - 1) / 4; int quadCount = gridSize * gridSize; //int numVertices = (gridSize + 1) * (gridSize + 1); //int numIndices = quadCount * 4; int offset = 0; if ((face.Mask & FaceMask.Top) != 0) offset = (maxT - 1) * maxS; else offset = face.BeginS; Vertex[] corners = new Vertex[4]; Vertex baseVert; for (int t = 0; t < 4; t++) { corners[t].Position = primVertices[offset + (gridSize * t)].Position; corners[t].TexCoord.X = profile.Positions[gridSize * t].X + 0.5f; corners[t].TexCoord.Y = 0.5f - profile.Positions[gridSize * t].Y; } baseVert.Normal = ((corners[1].Position - corners[0].Position) % (corners[2].Position - corners[1].Position)); baseVert.Normal = Vector3.Normalize(baseVert.Normal); if ((face.Mask & FaceMask.Top) != 0) { baseVert.Normal *= -1f; } else { // Swap the UVs on the U(X) axis for top face Vector2 swap; swap = corners[0].TexCoord; corners[0].TexCoord = corners[3].TexCoord; corners[3].TexCoord = swap; swap = corners[1].TexCoord; corners[1].TexCoord = corners[2].TexCoord; corners[2].TexCoord = swap; } baseVert.Binormal = CalcBinormalFromTriangle( corners[0].Position, corners[0].TexCoord, corners[1].Position, corners[1].TexCoord, corners[2].Position, corners[2].TexCoord); for (int t = 0; t < 4; t++) { corners[t].Binormal = baseVert.Binormal; corners[t].Normal = baseVert.Normal; } int vtop = face.Vertices.Count; for (int gx = 0; gx < gridSize + 1; gx++) { for (int gy = 0; gy < gridSize + 1; gy++) { Vertex newVert = new Vertex(); LerpPlanarVertex( corners[0], corners[1], corners[3], ref newVert, (float)gx / (float)gridSize, (float)gy / (float)gridSize); face.Vertices.Add(newVert); if (gx == 0 && gy == 0) face.MinExtent = face.MaxExtent = newVert.Position; else UpdateMinMax(ref face, newVert.Position); } } face.Center = (face.MinExtent + face.MaxExtent) * 0.5f; int[] idxs = new int[] { 0, 1, gridSize + 2, gridSize + 2, gridSize + 1, 0 }; for (int gx = 0; gx < gridSize; gx++) { for (int gy = 0; gy < gridSize; gy++) { if ((face.Mask & FaceMask.Top) != 0) { for (int i = 5; i >= 0; i--) face.Indices.Add((ushort)(vtop + (gy * (gridSize + 1)) + gx + idxs[i])); } else { for (int i = 0; i < 6; i++) face.Indices.Add((ushort)(vtop + (gy * (gridSize + 1)) + gx + idxs[i])); } } } }
/// <summary> /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this /// routine since all the context for finding teh texture is elsewhere. /// </summary> /// <returns>The faceted mesh or null if can't do it</returns> public OMVR.FacetedMesh GenerateFacetedSculptMesh(Primitive prim, Bitmap scupltTexture, DetailLevel lod) { LibreMetaverse.PrimMesher.SculptMesh.SculptType smSculptType; switch (prim.Sculpt.Type) { case SculptType.Cylinder: smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.cylinder; break; case SculptType.Plane: smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.plane; break; case SculptType.Sphere: smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.sphere; break; case SculptType.Torus: smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.torus; break; default: smSculptType = LibreMetaverse.PrimMesher.SculptMesh.SculptType.plane; break; } // The lod for sculpties is the resolution of the texture passed. // The first guess is 1:1 then lower resolutions after that // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height); int mesherLod = 32; // number used in Idealist viewer switch (lod) { case OMVR.DetailLevel.Highest: break; case OMVR.DetailLevel.High: break; case OMVR.DetailLevel.Medium: mesherLod /= 2; break; case OMVR.DetailLevel.Low: mesherLod /= 4; break; } LibreMetaverse.PrimMesher.SculptMesh newMesh = new LibreMetaverse.PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, prim.Sculpt.Mirror, prim.Sculpt.Invert); int numPrimFaces = 1; // a scuplty has only one face // copy the vertex information into OMVR.IRendering structures FacetedMesh omvrmesh = new OMVR.FacetedMesh { Faces = new List <OMVR.Face>(), Prim = prim, Profile = new OMVR.Profile { Faces = new List <OMVR.ProfileFace>(), Positions = new List <OMV.Vector3>() }, Path = new OMVR.Path { Points = new List <OMVR.PathPoint>() } }; for (int ii = 0; ii < numPrimFaces; ii++) { Face oface = new OMVR.Face { Vertices = new List <OMVR.Vertex>(), Indices = new List <ushort>(), TextureFace = prim.Textures.GetFace((uint)ii) }; int faceVertices = newMesh.coords.Count; for (int j = 0; j < faceVertices; j++) { var vert = new OMVR.Vertex { Position = new Vector3(newMesh.coords[j].X, newMesh.coords[j].Y, newMesh.coords[j].Z), Normal = new Vector3(newMesh.normals[j].X, newMesh.normals[j].Y, newMesh.normals[j].Z), TexCoord = new Vector2(newMesh.uvs[j].U, newMesh.uvs[j].V) }; oface.Vertices.Add(vert); } for (int j = 0; j < newMesh.faces.Count; j++) { oface.Indices.Add((ushort)newMesh.faces[j].v1); oface.Indices.Add((ushort)newMesh.faces[j].v2); oface.Indices.Add((ushort)newMesh.faces[j].v3); } if (faceVertices > 0) { oface.TextureFace = prim.Textures.FaceTextures[ii] ?? prim.Textures.DefaultTexture; oface.ID = ii; omvrmesh.Faces.Add(oface); } } return(omvrmesh); }
private List<Vertex> GenerateVertices() { List<Vertex> vertices = new List<Vertex>(8); Vertex v = new Vertex(); // FIXME: Implement these v.Normal = Vector3.Zero; v.TexCoord = Vector2.Zero; v.Position = new Vector3(0.5f, 0.5f, -0.5f); vertices.Add(v); v.Position = new Vector3(0.5f, -0.5f, -0.5f); vertices.Add(v); v.Position = new Vector3(-0.5f, -0.5f, -0.5f); vertices.Add(v); v.Position = new Vector3(-0.5f, 0.5f, -0.5f); vertices.Add(v); v.Position = new Vector3(0.5f, 0.5f, 0.5f); vertices.Add(v); v.Position = new Vector3(0.5f, -0.5f, 0.5f); vertices.Add(v); v.Position = new Vector3(-0.5f, -0.5f, 0.5f); vertices.Add(v); v.Position = new Vector3(-0.5f, 0.5f, 0.5f); vertices.Add(v); return vertices; }
/// <summary> /// Create a sculpty faceted mesh. The actual scuplt texture is fetched and passed to this /// routine since all the context for finding teh texture is elsewhere. /// </summary> /// <returns>The faceted mesh or null if can't do it</returns> public OMVR.FacetedMesh GenerateFacetedSculptMesh(OMV.Primitive prim, System.Drawing.Bitmap scupltTexture, OMVR.DetailLevel lod) { byte sculptType = (byte)prim.Sculpt.Type; bool mirror = ((sculptType & 128) != 0); bool invert = ((sculptType & 64) != 0); // mirror = false; // TODO: libomv doesn't support these and letting them flop around causes problems // invert = false; OMV.SculptType omSculptType = (OMV.SculptType)(sculptType & 0x07); PrimMesher.SculptMesh.SculptType smSculptType; switch (omSculptType) { case OpenMetaverse.SculptType.Cylinder: smSculptType = PrimMesher.SculptMesh.SculptType.cylinder; break; case OpenMetaverse.SculptType.Plane: smSculptType = PrimMesher.SculptMesh.SculptType.plane; break; case OpenMetaverse.SculptType.Sphere: smSculptType = PrimMesher.SculptMesh.SculptType.sphere; break; case OpenMetaverse.SculptType.Torus: smSculptType = PrimMesher.SculptMesh.SculptType.torus; break; default: smSculptType = PrimMesher.SculptMesh.SculptType.plane; break; } // The lod for sculpties is the resolution of the texture passed. // The first guess is 1:1 then lower resolutions after that // int mesherLod = (int)Math.Sqrt(scupltTexture.Width * scupltTexture.Height); int mesherLod = 32; // number used in Idealist viewer switch (lod) { case OMVR.DetailLevel.Highest: break; case OMVR.DetailLevel.High: break; case OMVR.DetailLevel.Medium: mesherLod /= 2; break; case OMVR.DetailLevel.Low: mesherLod /= 4; break; } PrimMesher.SculptMesh newMesh = new PrimMesher.SculptMesh(scupltTexture, smSculptType, mesherLod, true, mirror, invert); int numPrimFaces = 1; // a scuplty has only one face // copy the vertex information into OMVR.IRendering structures OMVR.FacetedMesh omvrmesh = new OMVR.FacetedMesh(); omvrmesh.Faces = new List <OMVR.Face>(); omvrmesh.Prim = prim; omvrmesh.Profile = new OMVR.Profile(); omvrmesh.Profile.Faces = new List <OMVR.ProfileFace>(); omvrmesh.Profile.Positions = new List <OMV.Vector3>(); omvrmesh.Path = new OMVR.Path(); omvrmesh.Path.Points = new List <OMVR.PathPoint>(); for (int ii = 0; ii < numPrimFaces; ii++) { OMVR.Face oface = new OMVR.Face(); oface.Vertices = new List <OMVR.Vertex>(); oface.Indices = new List <ushort>(); oface.TextureFace = prim.Textures.GetFace((uint)ii); int faceVertices = 0; foreach (PrimMesher.ViewerFace vface in newMesh.viewerFaces) { OMVR.Vertex vert = new OMVR.Vertex(); vert.Position = new OMV.Vector3(vface.v1.X, vface.v1.Y, vface.v1.Z); vert.TexCoord = new OMV.Vector2(vface.uv1.U, 1.0f - vface.uv1.V); vert.Normal = new OMV.Vector3(vface.n1.X, vface.n1.Y, vface.n1.Z); oface.Vertices.Add(vert); vert = new OMVR.Vertex(); vert.Position = new OMV.Vector3(vface.v2.X, vface.v2.Y, vface.v2.Z); vert.TexCoord = new OMV.Vector2(vface.uv2.U, 1.0f - vface.uv2.V); vert.Normal = new OMV.Vector3(vface.n2.X, vface.n2.Y, vface.n2.Z); oface.Vertices.Add(vert); vert = new OMVR.Vertex(); vert.Position = new OMV.Vector3(vface.v3.X, vface.v3.Y, vface.v3.Z); vert.TexCoord = new OMV.Vector2(vface.uv3.U, 1.0f - vface.uv3.V); vert.Normal = new OMV.Vector3(vface.n3.X, vface.n3.Y, vface.n3.Z); oface.Vertices.Add(vert); oface.Indices.Add((ushort)(faceVertices * 3 + 0)); oface.Indices.Add((ushort)(faceVertices * 3 + 1)); oface.Indices.Add((ushort)(faceVertices * 3 + 2)); faceVertices++; } if (faceVertices > 0) { oface.TextureFace = prim.Textures.FaceTextures[ii]; if (oface.TextureFace == null) { oface.TextureFace = prim.Textures.DefaultTexture; } oface.ID = ii; omvrmesh.Faces.Add(oface); } } return(omvrmesh); }