private static void BuildFace(ref Face face, LLObject.ObjectData prim, List<Vertex> vertices, Path path, Profile profile, LLObject.TextureEntryFace teFace) { if (teFace != null) face.TextureFace = teFace; else throw new ArgumentException("teFace cannot be null"); face.Vertices.Clear(); if ((face.Mask & FaceMask.Cap) != 0) { if (((face.Mask & FaceMask.Hollow) == 0) && ((face.Mask & FaceMask.Open) == 0) && (prim.PathBegin == 0f) && (prim.ProfileCurve == LLObject.ProfileCurve.Square) && (prim.PathCurve == LLObject.PathCurve.Line)) { CreateUnCutCubeCap(ref face, vertices, path, profile); } else { CreateCap(ref face, vertices, path, profile); } } else if ((face.Mask & FaceMask.End) != 0 || (face.Mask & FaceMask.Side) != 0) { CreateSide(ref face, prim, vertices, path, profile); } else { throw new RenderingException("Unknown/uninitialized face type"); } }
/// <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> /// 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); }
// Returns an ExtendedPrimGroup with a mesh for the passed heightmap. // Note that the returned EPG does not include any face information -- the caller must add a texture. public DisplayableRenderable MeshFromHeightMap(float[,] pHeightMap, int regionSizeX, int regionSizeY, IAssetFetcher assetFetcher, OMV.Primitive.TextureEntryFace defaultTexture) { // OMVR.Face rawMesh = m_mesher.TerrainMesh(pHeightMap, 0, pHeightMap.GetLength(0)-1, 0, pHeightMap.GetLength(1)-1); ConvOAR.Globals.log.DebugFormat("{0} MeshFromHeightMap: heightmap=<{1},{2}>, regionSize=<{3},{4}>", _logHeader, pHeightMap.GetLength(0), pHeightMap.GetLength(1), regionSizeX, regionSizeY); OMVR.Face rawMesh = ConvoarTerrain.TerrainMesh(pHeightMap, (float)regionSizeX, (float)regionSizeY); RenderableMesh rm = ConvertFaceToRenderableMesh(rawMesh, assetFetcher, defaultTexture, new OMV.Vector3(1, 1, 1)); RenderableMeshGroup rmg = new RenderableMeshGroup(); rmg.meshes.Add(rm); return(rmg); }
public MaterialInfo(OMVR.Face face, OMV.Primitive.TextureEntryFace defaultTexture) { handle = new EntityHandleUUID(); faceTexture = face.TextureFace; if (faceTexture == null) { faceTexture = defaultTexture; } textureID = faceTexture.TextureID; if (faceTexture.RGBA.A != 1f) { fullAlpha = true; } RGBA = faceTexture.RGBA; bump = faceTexture.Bump; glow = faceTexture.Glow; shiny = faceTexture.Shiny; twoSided = ConvOAR.Globals.parms.P <bool>("DoubleSided"); }
/// <summary> /// Generates a sculpt mesh structure from a primitive /// </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.SimpleMesh GenerateSimpleSculptMesh(OMV.Primitive prim, Bitmap bits, OMVR.DetailLevel lod) { OMVR.FacetedMesh faceted = GenerateFacetedSculptMesh(prim, bits, lod); if (faceted != null && faceted.Faces.Count == 1) { OMVR.Face face = faceted.Faces[0]; OMVR.SimpleMesh mesh = new OMVR.SimpleMesh(); mesh.Indices = face.Indices; mesh.Vertices = face.Vertices; mesh.Path = faceted.Path; mesh.Prim = prim; mesh.Profile = faceted.Profile; mesh.Vertices = face.Vertices; return(mesh); } return(null); }
/// <summary> /// Checks if VBOs are created, if they are, bind them, if not create new /// </summary> /// <param name="face">Which face's mesh is uploaded in this VBO</param> /// <returns>True, if face data was succesfully uploaded to the graphics card memory</returns> public bool CheckVBO(Face face) { //hack // if (VertexVBO == -1) // { // Vertex[] vArray = face.Vertices.ToArray(); // Compat.GenBuffers(out VertexVBO); // Compat.BindBuffer(BufferTarget.ArrayBuffer, VertexVBO); // Compat.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vArray.Length * VertexSize), vArray, BufferUsageHint.StaticDraw); // if (Compat.BufferSize(BufferTarget.ArrayBuffer) != vArray.Length * VertexSize) // { // VBOFailed = true; // Compat.BindBuffer(BufferTarget.ArrayBuffer, 0); // Compat.DeleteBuffer(VertexVBO); // VertexVBO = -1; // return false; // } // } // // if (IndexVBO == -1) // { // ushort[] iArray = face.Indices.ToArray(); // Compat.GenBuffers(out IndexVBO); // Compat.BindBuffer(BufferTarget.ElementArrayBuffer, IndexVBO); // Compat.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(iArray.Length * sizeof(ushort)), iArray, BufferUsageHint.StaticDraw); // if (Compat.BufferSize(BufferTarget.ElementArrayBuffer) != iArray.Length * sizeof(ushort)) // { // VBOFailed = true; // Compat.BindBuffer(BufferTarget.ElementArrayBuffer, 0); // Compat.DeleteBuffer(IndexVBO); // IndexVBO = -1; // return false; // } // } return true; }
/// <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; }
private RenderableMesh ConvertFaceToRenderableMesh(OMVR.Face face, IAssetFetcher assetFetcher, OMV.Primitive.TextureEntryFace defaultTexture, OMV.Vector3 primScale) { RenderableMesh rmesh = new RenderableMesh(); rmesh.num = face.ID; // Copy one face's mesh imformation from the FacetedMesh into a MeshInfo MeshInfo meshInfo = new MeshInfo { vertexs = new List <OMVR.Vertex>(face.Vertices), indices = face.Indices.ConvertAll(ii => (int)ii), faceCenter = face.Center, scale = primScale }; BConverterOS.LogBProgress("{0} ConvertFaceToRenderableMesh: faceId={1}, numVert={2}, numInd={3}", _logHeader, face.ID, meshInfo.vertexs.Count, meshInfo.indices.Count); if (!ConvOAR.Globals.parms.P <bool>("DisplayTimeScaling")) { if (ScaleMeshes(meshInfo, primScale)) { BConverterOS.LogBProgress("{0} ConvertFaceToRenderableMesh: scaled mesh to {1}", _logHeader, primScale); } meshInfo.scale = OMV.Vector3.One; } // Find or create the MaterialInfo for this face. MaterialInfo matInfo = new MaterialInfo(face, defaultTexture); if (matInfo.textureID != null && matInfo.textureID != OMV.UUID.Zero && matInfo.textureID != OMV.Primitive.TextureEntry.WHITE_TEXTURE) { // Textures/images use the UUID from OpenSim and the hash is just the hash of the UUID EntityHandleUUID textureHandle = new EntityHandleUUID((OMV.UUID)matInfo.textureID); BHash textureHash = new BHashULong(textureHandle.GetUUID().GetHashCode()); ImageInfo lookupImageInfo = assetFetcher.GetImageInfo(textureHash, () => { // The image is not in the cache yet so create an ImageInfo entry for it // Note that image gets the same UUID as the OpenSim texture ImageInfo imageInfo = new ImageInfo(textureHandle); assetFetcher.FetchTextureAsImage(textureHandle) .Then(img => { imageInfo.SetImage(img); }) .Catch(e => { // Failure getting the image ConvOAR.Globals.log.ErrorFormat("{0} Failure fetching texture. id={1}. {2}", _logHeader, matInfo.textureID, e); // Create a simple, single color image to fill in for the missing image var fillInImage = new Bitmap(32, 32, System.Drawing.Imaging.PixelFormat.Format32bppArgb); Color theColor = Color.FromArgb(128, 202, 213, 170); // 0x80CAB5AA for (int xx = 0; xx < 32; xx++) { for (int yy = 0; yy < 32; yy++) { fillInImage.SetPixel(xx, yy, theColor); } } imageInfo.SetImage(fillInImage); }); imageInfo.imageIdentifier = (OMV.UUID)matInfo.textureID; BConverterOS.LogBProgress("{0} ConvertFaceToRenderableMesh: create ImageInfo. hash={1}, id={2}", _logHeader, textureHash, imageInfo.handle); return(imageInfo); }); matInfo.image = lookupImageInfo; // Update the UV information for the texture mapping BConverterOS.LogBProgress("{0} ConvertFaceToRenderableMesh: Converting tex coords using {1} texture", _logHeader, face.TextureFace == null ? "default" : "face"); _mesher.TransformTexCoords(meshInfo.vertexs, meshInfo.faceCenter, face.TextureFace == null ? defaultTexture : face.TextureFace, primScale); } // See that the material is in the cache MaterialInfo lookupMatInfo = assetFetcher.GetMaterialInfo(matInfo.GetBHash(), () => { return(matInfo); }); rmesh.material = lookupMatInfo; // See that the mesh is in the cache MeshInfo lookupMeshInfo = assetFetcher.GetMeshInfo(meshInfo.GetBHash(true), () => { return(meshInfo); }); rmesh.mesh = lookupMeshInfo; if (lookupMeshInfo.indices.Count == 0) // DEBUG DEBUG { ConvOAR.Globals.log.ErrorFormat("{0} indices count of zero. rmesh={1}", _logHeader, rmesh.ToString()); } // DEBUG DEBUG BConverterOS.LogBProgress("{0} ConvertFaceToRenderableMesh: rmesh.mesh={1}, rmesh.material={2}", _logHeader, rmesh.mesh, rmesh.material); return(rmesh); }
private void UpdateTerrain() { if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Terrain == null) return; ThreadPool.QueueUserWorkItem(sync => { int step = 1; for (int x = 0; x < 256; x += step) { for (int y = 0; y < 256; y += step) { float z = 0; int patchNr = ((int)x / 16) * 16 + (int)y / 16; if (Client.Network.CurrentSim.Terrain[patchNr] != null && Client.Network.CurrentSim.Terrain[patchNr].Data != null) { float[] data = Client.Network.CurrentSim.Terrain[patchNr].Data; z = data[(int)x % 16 * 16 + (int)y % 16]; } heightTable[x, y] = z; } } terrainFace = renderer.TerrainMesh(heightTable, 0f, 255f, 0f, 255f); terrainVertices = new ColorVertex[terrainFace.Vertices.Count]; for (int i = 0; i < terrainFace.Vertices.Count; i++) { byte[] part = Utils.IntToBytes(i); terrainVertices[i] = new ColorVertex() { Vertex = terrainFace.Vertices[i], Color = new Color4b() { R = part[0], G = part[1], B = part[2], A = 253 // terrain picking } }; } terrainIndices = terrainFace.Indices.ToArray(); terrainInProgress = false; terrainModified = false; terrainTextureNeedsUpdate = true; terrainTimeSinceUpdate = 0f; }); }
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> /// 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; }
/// <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> /// 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 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; }
private void UpdateTerrain() { if (Client.Network.CurrentSim == null || Client.Network.CurrentSim.Terrain == null) return; int step = 1; for (int x = 0; x < 255; x += step) { for (int y = 0; y < 255; y += step) { float z = 0; int patchNr = ((int)x / 16) * 16 + (int)y / 16; if (Client.Network.CurrentSim.Terrain[patchNr] != null && Client.Network.CurrentSim.Terrain[patchNr].Data != null) { float[] data = Client.Network.CurrentSim.Terrain[patchNr].Data; z = data[(int)x % 16 * 16 + (int)y % 16]; } heightTable[x, y] = z; } } terrainFace = renderer.TerrainMesh(heightTable, 0f, 255f, 0f, 255f); terrainVertices = terrainFace.Vertices.ToArray(); terrainIndices = terrainFace.Indices.ToArray(); TerrainModified = false; }
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 void CreateNewPrim(LLEntityBase ent) { m_log.Log(LogLevel.DRENDERDETAIL, "Create new prim {0}", ent.Name.Name); // entity render info is kept per region. Get the region prim structure RegionRenderInfo rri = GetRegionRenderInfo(ent.RegionContext); IEntityAvatar av; if (ent.TryGet <IEntityAvatar>(out av)) { // if this entity is an avatar, just put it on the display list lock (rri.renderAvatarList) { if (!rri.renderAvatarList.ContainsKey(av.LGID)) { RenderableAvatar ravv = new RenderableAvatar(); ravv.avatar = av; rri.renderAvatarList.Add(av.LGID, ravv); } } return; } OMV.Primitive prim = ent.Prim; /* don't do foliage yet * if (prim.PrimData.PCode == OMV.PCode.Grass || prim.PrimData.PCode == OMV.PCode.Tree || prim.PrimData.PCode == OMV.PCode.NewTree) { || lock (renderFoliageList) || renderFoliageList[prim.LocalID] = prim; || return; ||} */ RenderablePrim render = new RenderablePrim(); render.Prim = prim; render.acontext = ent.AssetContext; render.rcontext = ent.RegionContext; render.Position = prim.Position; render.Rotation = prim.Rotation; render.isVisible = true; // initially assume visible if (m_meshMaker == null) { m_meshMaker = new Renderer.Mesher.MeshmerizerR(); m_meshMaker.ShouldScaleMesh = false; } if (prim.Sculpt != null) { EntityNameLL textureEnt = EntityNameLL.ConvertTextureWorldIDToEntityName(ent.AssetContext, prim.Sculpt.SculptTexture); System.Drawing.Bitmap textureBitmap = ent.AssetContext.GetTexture(textureEnt); if (textureBitmap == null) { // the texture is not available. Request it. // Note that we just call this routine again when it is available. Hope it's not recursive ent.AssetContext.DoTextureLoad(textureEnt, AssetContextBase.AssetType.SculptieTexture, delegate(string name, bool trans) { CreateNewPrim(ent); return; } ); return; } render.Mesh = m_meshMaker.GenerateSculptMesh(textureBitmap, prim, OMVR.DetailLevel.Medium); textureBitmap.Dispose(); } else { render.Mesh = m_meshMaker.GenerateFacetedMesh(prim, OMVR.DetailLevel.High); } if (render.Mesh == null) { // mesh generation failed m_log.Log(LogLevel.DBADERROR, "FAILED MESH GENERATION: not generating new prim {0}", ent.Name.Name); return; } // Create a FaceData struct for each face that stores the 3D data // in an OpenGL friendly format for (int j = 0; j < render.Mesh.Faces.Count; j++) { OMVR.Face face = render.Mesh.Faces[j]; FaceData data = new FaceData(); // Vertices for this face data.Vertices = new float[face.Vertices.Count * 3]; for (int k = 0; k < face.Vertices.Count; k++) { data.Vertices[k * 3 + 0] = face.Vertices[k].Position.X; data.Vertices[k * 3 + 1] = face.Vertices[k].Position.Y; data.Vertices[k * 3 + 2] = face.Vertices[k].Position.Z; } // Indices for this face data.Indices = face.Indices.ToArray(); // Texture transform for this face OMV.Primitive.TextureEntryFace teFace = prim.Textures.GetFace((uint)j); m_meshMaker.TransformTexCoords(face.Vertices, face.Center, teFace); // Texcoords for this face data.TexCoords = new float[face.Vertices.Count * 2]; for (int k = 0; k < face.Vertices.Count; k++) { data.TexCoords[k * 2 + 0] = face.Vertices[k].TexCoord.X; data.TexCoords[k * 2 + 1] = face.Vertices[k].TexCoord.Y; } data.Normals = new float[face.Vertices.Count * 3]; for (int k = 0; k < face.Vertices.Count; k++) { data.Normals[k * 3 + 0] = face.Vertices[k].Normal.X; data.Normals[k * 3 + 1] = face.Vertices[k].Normal.Y; data.Normals[k * 3 + 2] = face.Vertices[k].Normal.Z; } // m_log.Log(LogLevel.DRENDERDETAIL, "CreateNewPrim: v={0}, i={1}, t={2}", // data.Vertices.GetLength(0), data.Indices.GetLength(0), data.TexCoords.GetLength(0)); // Texture for this face if (teFace.TextureID != OMV.UUID.Zero && teFace.TextureID != OMV.Primitive.TextureEntry.WHITE_TEXTURE) { lock (Textures) { if (!Textures.ContainsKey(teFace.TextureID)) { // temporarily add the entry to the table so we don't request it multiple times Textures.Add(teFace.TextureID, new TextureInfo(0, true)); // We haven't constructed this image in OpenGL yet, get ahold of it AssetContextBase.RequestTextureLoad( EntityNameLL.ConvertTextureWorldIDToEntityName(ent.AssetContext, teFace.TextureID), AssetContextBase.AssetType.Texture, OnTextureDownloadFinished); } } } // Set the UserData for this face to our FaceData struct face.UserData = data; render.Mesh.Faces[j] = face; } lock (rri.renderPrimList) { rri.renderPrimList[prim.LocalID] = render; } }
//int[] CubeMapDefines = new int[] //{ // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, // Gl.GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, // Gl.GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB //}; private void RenderPrims(RegionContextBase rcontext, RegionRenderInfo rri) { GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.Texture2D); lock (rri.renderPrimList) { bool firstPass = true; // GL.Disable(EnableCap.Blend); GL.Enable(EnableCap.Blend); GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); GL.Enable(EnableCap.DepthTest); GL.Enable(EnableCap.Normalize); GL.EnableClientState(ArrayCap.TextureCoordArray); GL.EnableClientState(ArrayCap.VertexArray); GL.EnableClientState(ArrayCap.NormalArray); StartRender: List <RenderablePrim> rpList = new List <RenderablePrim>(rri.renderPrimList.Values); // sort back to front rpList.Sort(delegate(RenderablePrim rp1, RenderablePrim rp2) { return((int)(((OMV.Vector3.Distance(m_renderer.Camera.Position, rp1.Prim.Position)) - (OMV.Vector3.Distance(m_renderer.Camera.Position, rp2.Prim.Position))) * 100f)); }); foreach (RenderablePrim rp in rpList) { // if this prim is not visible, just loop if (!rp.isVisible) { continue; } RenderablePrim prp = RenderablePrim.Empty; OMV.Primitive prim = rp.Prim; if (prim.ParentID != 0) { // Get the parent reference if (!rri.renderPrimList.TryGetValue(prim.ParentID, out prp)) { // Can't render a child with no parent prim, skip it continue; } } GL.PushName(prim.LocalID); GL.PushMatrix(); if (prim.ParentID != 0) { // Apply parent translation and rotation GL.MultMatrix(Math3D.CreateTranslationMatrix(prp.Position)); GL.MultMatrix(Math3D.CreateRotationMatrix(prp.Rotation)); } // Apply prim translation and rotation GL.MultMatrix(Math3D.CreateTranslationMatrix(rp.Position)); // apply region offset for multiple regions GL.MultMatrix(Math3D.CreateTranslationMatrix(CalcRegionOffset(rp.rcontext))); GL.MultMatrix(Math3D.CreateRotationMatrix(rp.Rotation)); // Scale the prim GL.Scale(prim.Scale.X, prim.Scale.Y, prim.Scale.Z); // Draw the prim faces for (int j = 0; j < rp.Mesh.Faces.Count; j++) { OMVR.Face face = rp.Mesh.Faces[j]; FaceData data = (FaceData)face.UserData; OMV.Color4 color = face.TextureFace.RGBA; bool alpha = false; int textureID = 0; if (color.A < 1.0f) { alpha = true; } TextureInfo info; if (face.TextureFace.TextureID != OMV.UUID.Zero && face.TextureFace.TextureID != OMV.Primitive.TextureEntry.WHITE_TEXTURE && m_renderer.Textures.TryGetValue(face.TextureFace.TextureID, out info)) { if (info.Alpha) { alpha = true; } textureID = info.ID; // if textureID has not been set, need to generate the mipmaps if (textureID == 0) { GenerateMipMaps(rp.acontext, face.TextureFace.TextureID, out textureID); info.ID = textureID; } // Enable texturing for this face GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); } else { if (face.TextureFace.TextureID == OMV.Primitive.TextureEntry.WHITE_TEXTURE || face.TextureFace.TextureID == OMV.UUID.Zero) { GL.PolygonMode(MaterialFace.Front, PolygonMode.Fill); } else { GL.PolygonMode(MaterialFace.Front, PolygonMode.Line); } } // if (firstPass && !alpha || !firstPass && alpha) { // GL.Color4(color.R, color.G, color.B, color.A); float[] matDiffuse = { color.R, color.G, color.B, color.A }; GL.Material(MaterialFace.FrontAndBack, MaterialParameter.Diffuse, matDiffuse); // Bind the texture if (textureID != 0) { GL.Enable(EnableCap.Texture2D); GL.BindTexture(TextureTarget.Texture2D, textureID); } else { GL.Disable(EnableCap.Texture2D); } GL.TexCoordPointer(2, TexCoordPointerType.Float, 0, data.TexCoords); GL.VertexPointer(3, VertexPointerType.Float, 0, data.Vertices); GL.NormalPointer(NormalPointerType.Float, 0, data.Normals); GL.DrawElements(BeginMode.Triangles, data.Indices.Length, DrawElementsType.UnsignedShort, data.Indices); // } } GL.PopMatrix(); GL.PopName(); } /* * if (firstPass) { * firstPass = false; * GL.Enable(EnableCap.Blend); * GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha); * // GL.Disable(EnableCap.DepthTest); * * goto StartRender; * } */ } GL.Enable(EnableCap.DepthTest); GL.Disable(EnableCap.Texture2D); }
/// <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> /// 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); } }
private static List<Face> CreateVolumeFaces(Primitive prim, Path path, Profile profile, List<Vertex> vertices) { int numFaces = profile.Faces.Count; List<Face> faces = new List<Face>(numFaces); // Initialize faces with parameter data for (int i = 0; i < numFaces; i++) { ProfileFace pf = profile.Faces[i]; Face face = new Face(); face.Vertices = new List<Vertex>(); face.Indices = new List<ushort>(); face.Edge = new List<int>(); face.BeginS = pf.Index; face.NumS = pf.Count; face.BeginT = 0; face.NumT = path.Points.Count; face.ID = i; // Set the type mask bits correctly if (prim.Data.ProfileHollow > 0f) face.Mask |= FaceMask.Hollow; if (profile.Open) face.Mask |= FaceMask.Open; if (pf.Cap) { face.Mask |= FaceMask.Cap; if (pf.Type == FaceType.PathBegin) face.Mask |= FaceMask.Top; else face.Mask |= FaceMask.Bottom; } else if (pf.Type == FaceType.ProfileBegin || pf.Type == FaceType.ProfileEnd) { face.Mask |= FaceMask.Flat; face.Mask |= FaceMask.End; } else { face.Mask |= FaceMask.Side; if (pf.Flat) face.Mask |= FaceMask.Flat; if (pf.Type == FaceType.InnerSide) { face.Mask |= FaceMask.Inner; if (pf.Flat && face.NumS > 2) face.NumS *= 2; // Flat inner faces have to copy vert normals } else { face.Mask |= FaceMask.Outer; } } faces.Add(face); } for (int i = 0; i < faces.Count; i++) { Face face = faces[i]; BuildFace(ref face, prim.Data, vertices, path, profile, prim.Textures.GetFace((uint)i)); faces[i] = face; } return faces; }
// 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); }
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; }
/// <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) { 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> /// 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; }
public void CheckVBO(Face face) { if (VertexVBO == -1) { Vertex[] vArray = face.Vertices.ToArray(); GL.GenBuffers(1, out VertexVBO); GL.BindBuffer(BufferTarget.ArrayBuffer, VertexVBO); GL.BufferData(BufferTarget.ArrayBuffer, (IntPtr)(vArray.Length * VertexSize), vArray, BufferUsageHint.StaticDraw); } if (IndexVBO == -1) { ushort[] iArray = face.Indices.ToArray(); GL.GenBuffers(1, out IndexVBO); GL.BindBuffer(BufferTarget.ElementArrayBuffer, IndexVBO); GL.BufferData(BufferTarget.ElementArrayBuffer, (IntPtr)(iArray.Length * sizeof(ushort)), iArray, BufferUsageHint.StaticDraw); } }
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)); } } }
/// <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 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; } }
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 UpdateMinMax(ref Face face, Vector3 position) { if (face.MinExtent.X > position.X) face.MinExtent.X = position.X; if (face.MinExtent.Y > position.Y) face.MinExtent.Y = position.Y; if (face.MinExtent.Z > position.Z) face.MinExtent.Z = position.Z; if (face.MaxExtent.X < position.X) face.MaxExtent.X = position.X; if (face.MaxExtent.Y < position.Y) face.MaxExtent.Y = position.Y; if (face.MaxExtent.Z < position.Z) face.MaxExtent.Z = position.Z; }
/// <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<Face> GenerateFaces(Primitive.TextureEntry te) { Face face = new Face(); face.Edge = new List<int>(); face.TextureFace = te.DefaultTexture; face.Vertices = GenerateVertices(); face.Indices = GenerateIndices(); List<Face> faces = new List<Face>(1); faces.Add(face); return faces; }
/// <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); }