// Find all the meshes in passed Displayable and add them to the lists indexed by their material // mesh hashes. private void MapMaterialsAndMeshes(BScene pBs, BInstance pInst, Displayable disp) { RenderableMeshGroup rmg = disp.renderable as RenderableMeshGroup; if (rmg != null) { foreach (RenderableMesh rMesh in rmg.meshes) { InvertedMesh imesh = new InvertedMesh(pBs, pInst, disp, rmg, rMesh); BHash meshHash = rMesh.mesh.GetBHash(); if (!sharedMeshes.ContainsKey(meshHash)) { sharedMeshes.Add(meshHash, new List <InvertedMesh>()); } sharedMeshes[meshHash].Add(imesh); BHash materialHash = rMesh.material.GetBHash(); if (!meshByMaterial.ContainsKey(materialHash)) { meshByMaterial.Add(materialHash, new List <InvertedMesh>()); } meshByMaterial[materialHash].Add(imesh); } } foreach (Displayable child in disp.children) { MapMaterialsAndMeshes(pBs, pInst, child); } }
private void DumpInstance(BInstance inst) { Displayable instDisplayable = inst.Representation; LogBProgress("{0} created instance. handle={1}, pos={2}, rot={3}", _logHeader, inst.handle, inst.Position, inst.Rotation); DumpDisplayable(inst.Representation, "Representation", 0); }
// Given a list of meshes, combine them into one mesh and return a containing BInstance. private BInstance CreateOneInstanceFromMeshes(BHash materialHash, List <InvertedMesh> meshes) { // Pick one of the meshes to be the 'root' mesh. // Someday may need to find the most center mesh to work from. InvertedMesh rootIMesh = meshes.First(); // The new instance will be at the location of the root mesh with no rotation BInstance inst = new BInstance(); inst.Position = rootIMesh.containingInstance.Position; inst.Rotation = OMV.Quaternion.Identity; inst.coordAxis = rootIMesh.containingInstance.coordAxis; try { // The mesh we're going to build MeshInfo meshInfo = new MeshInfo(); foreach (InvertedMesh imesh in meshes) { int indicesBase = meshInfo.vertexs.Count; // Go through the mesh, map all vertices to global coordinates then convert relative to root meshInfo.vertexs.AddRange(imesh.renderableMesh.mesh.vertexs.Select(vert => { OMVR.Vertex newVert = new OMVR.Vertex(); OMV.Vector3 worldPos = vert.Position; worldPos = worldPos * imesh.containingDisplayable.offsetRotation + imesh.containingDisplayable.offsetPosition; worldPos = worldPos * imesh.containingInstance.Rotation + imesh.containingInstance.Position; // Make new vert relative to the BInstance it's being added to newVert.Position = worldPos - inst.Position; newVert.Normal = vert.Normal * imesh.containingDisplayable.offsetRotation * imesh.containingInstance.Rotation; newVert.TexCoord = vert.TexCoord; return(newVert); })); meshInfo.indices.AddRange(imesh.renderableMesh.mesh.indices.Select(ind => ind + indicesBase)); } RenderableMesh newMesh = new RenderableMesh(); newMesh.num = 0; newMesh.material = rootIMesh.renderableMesh.material; // The material we share newMesh.mesh = meshInfo; RenderableMeshGroup meshGroup = new RenderableMeshGroup(); meshGroup.meshes.Add(newMesh); Displayable displayable = new Displayable(meshGroup); displayable.name = "combinedMaterialMeshes-" + materialHash.ToString(); inst.Representation = displayable; } catch (Exception e) { ConvOAR.Globals.log.ErrorFormat("{0} CreateInstanceFromSharedMaterialMeshes: exception: {1}", _logHeader, e); } return(inst); }
public InvertedMesh(BScene pBs, BInstance pInst, Displayable pDisp, DisplayableRenderable pDisprend, RenderableMesh pRm) { containingScene = pBs; containingInstance = pInst; containingDisplayable = pDisp; containingDisplayableRenderable = pDisprend; renderableMesh = pRm; // Compute the global position of the Displayable globalPosition = containingDisplayable.offsetPosition * containingInstance.Rotation + containingInstance.Position; globalRotation = containingDisplayable.offsetRotation * containingInstance.Rotation; }
// Add another level of parenting public InvertedMesh AddDisplayableLevel(InvertedMesh imesh, Displayable pDisp, DisplayableRenderable pDispRend) { InvertedMesh newIMesh = new InvertedMesh(imesh.containingScene, imesh.containingInstance, imesh.containingDisplayable, imesh.containingDisplayableRenderable, imesh.renderableMesh); globalPosition += pDisp.offsetPosition; globalRotation *= pDisp.offsetRotation; newIMesh.containingDisplayable = pDisp; newIMesh.containingDisplayableRenderable = pDispRend; return(newIMesh); }
// Adds this Displayable if it's not already in the list. // Return 'true' if the Displayable was added to the list. public bool AddUniqueDisplayable(Displayable disp) { bool ret = false; Displayable maybeDisp; BHash dispHash = disp.GetBHash(); lock (Displayables) { if (!Displayables.TryGetValue(dispHash, out maybeDisp)) { Displayables.Add(dispHash, disp); } } return(ret); }
// Utility routine to gather all the MeshInfo's from a Displayable and all its children. private static List <MeshInfo> CollectMeshesFromDisplayable(Displayable disp) { List <MeshInfo> meshInfos = new List <MeshInfo>(); if (disp.renderable is RenderableMeshGroup rmg) { meshInfos.AddRange( rmg.meshes.Select(aMesh => { return(aMesh.mesh); }) ); } disp.children.ForEach(child => { meshInfos.AddRange(CollectMeshesFromDisplayable(child)); }); return(meshInfos); }
private void DumpDisplayable(Displayable disp, string header, int level) { string spaces = " "; string spacer = spaces.Substring(0, level * 2); LogBProgress("{0}{1} displayable: name={2}, pos={3}, rot={4}", _logHeader, spacer, disp.name, disp.offsetPosition, disp.offsetRotation); RenderableMeshGroup rmg = disp.renderable as RenderableMeshGroup; if (rmg != null) { rmg.meshes.ForEach(mesh => { LogBProgress("{0}{1} mesh: mesh={2}. material={3}", _logHeader, spacer, mesh.mesh, mesh.material); }); } disp.children.ForEach(child => { DumpDisplayable(child, "Child", level + 1); }); }
private List <Displayable> PackMeshesIntoDisplayables(List <InvertedMesh> meshList, OMV.Vector3 gPos, CreateNameFunc createName) { return(meshList.Select(imesh => { /* * ConvOAR.Globals.log.DebugFormat("{0} CreateInstanceForSharedMeshes: hash={1}, instPos={2}, dispPos={3}, numVerts={4}", * _logHeader, imesh.renderableMesh.mesh.GetBHash(), * imesh.containingInstance.Position, * imesh.containingDisplayable.offsetPosition, * imesh.renderableMesh.mesh.vertexs.Count); */ RenderableMeshGroup mesh = new RenderableMeshGroup(); mesh.meshes.Add(imesh.renderableMesh); Displayable disp = new Displayable(mesh); disp.name = createName(imesh); disp.offsetPosition = imesh.globalPosition - gPos; disp.offsetRotation = imesh.globalRotation; disp.renderable = mesh; return disp; }).ToList()); }
// Creates Instances for the shared messes in this list and also takes the meshes out of 'meshByMaterial'. // Current algorithm: create one instance and add all shared meshes as children. // When the instances are created (or copied over), the meshes must be removed from the // 'meshByMaterial' structure so they are not combined with other material sharing meshes. private List <BInstance> CreateInstancesForSharedMeshes(List <InvertedMesh> meshList) { List <BInstance> ret = new List <BInstance>(); BInstance inst = new BInstance(); InvertedMesh rootMesh = meshList.First(); inst.Position = rootMesh.globalPosition; inst.Rotation = OMV.Quaternion.Identity; // Create Displayable for each identical mesh (so we can keep the pos and rot. // Take the root mesh out of the list and use it as the representation List <Displayable> repackagedMeshes = PackMeshesIntoDisplayables(meshList, inst.Position, imesh => "sharedMesh-" + imesh.renderableMesh.mesh.GetBHash().ToString() + "-" + imesh.renderableMesh.GetBHash().ToString()); Displayable rootDisplayable = repackagedMeshes.First(); repackagedMeshes.RemoveAt(0); inst.Representation = rootDisplayable; rootDisplayable.children = repackagedMeshes; ret.Add(inst); return(ret); }
// Create a mesh for the terrain of the current scene public static BInstance CreateTerrainMesh( Scene scene, PrimToMesh assetMesher, IAssetFetcher assetFetcher) { ITerrainChannel terrainDef = scene.Heightmap; int XSize = terrainDef.Width; int YSize = terrainDef.Height; float[,] heightMap = new float[XSize, YSize]; if (ConvOAR.Globals.parms.P <bool>("HalfRezTerrain")) { ConvOAR.Globals.log.DebugFormat("{0}: CreateTerrainMesh. creating half sized terrain sized <{1},{2}>", LogHeader, XSize / 2, YSize / 2); // Half resolution mesh that approximates the heightmap heightMap = new float[XSize / 2, YSize / 2]; for (int xx = 0; xx < XSize; xx += 2) { for (int yy = 0; yy < YSize; yy += 2) { float here = terrainDef.GetHeightAtXYZ(xx + 0, yy + 0, 26); float ln = terrainDef.GetHeightAtXYZ(xx + 1, yy + 0, 26); float ll = terrainDef.GetHeightAtXYZ(xx + 0, yy + 1, 26); float lr = terrainDef.GetHeightAtXYZ(xx + 1, yy + 1, 26); heightMap[xx / 2, yy / 2] = (here + ln + ll + lr) / 4; } } } else { ConvOAR.Globals.log.DebugFormat("{0}: CreateTerrainMesh. creating terrain sized <{1},{2}>", LogHeader, XSize / 2, YSize / 2); for (int xx = 0; xx < XSize; xx++) { for (int yy = 0; yy < YSize; yy++) { heightMap[xx, yy] = terrainDef.GetHeightAtXYZ(xx, yy, 26); } } } // Number found in RegionSettings.cs as DEFAULT_TERRAIN_TEXTURE_3 OMV.UUID convoarID = new OMV.UUID(ConvOAR.Globals.parms.P <string>("ConvoarID")); OMV.UUID defaultTextureID = new OMV.UUID("179cdabd-398a-9b6b-1391-4dc333ba321f"); OMV.Primitive.TextureEntryFace terrainFace = new OMV.Primitive.TextureEntryFace(null); terrainFace.TextureID = defaultTextureID; EntityHandleUUID terrainTextureHandle = new EntityHandleUUID(); MaterialInfo terrainMaterialInfo = new MaterialInfo(terrainFace); if (ConvOAR.Globals.parms.P <bool>("CreateTerrainSplat")) { // Use the OpenSim maptile generator to create a texture for the terrain var terrainRenderer = new TexturedMapTileRenderer(); Nini.Config.IConfigSource config = new Nini.Config.IniConfigSource(); terrainRenderer.Initialise(scene, config); var mapbmp = new Bitmap(terrainDef.Width, terrainDef.Height, System.Drawing.Imaging.PixelFormat.Format24bppRgb); terrainRenderer.TerrainToBitmap(mapbmp); // Place the newly created image into the Displayable caches ImageInfo terrainImageInfo = new ImageInfo(); terrainImageInfo.handle = terrainTextureHandle; terrainImageInfo.image = mapbmp; terrainImageInfo.resizable = false; // terrain image resolution is not reduced assetFetcher.Images.Add(new BHashULong(terrainTextureHandle.GetHashCode()), terrainTextureHandle, terrainImageInfo); // Store the new image into the asset system so it can be read later. assetFetcher.StoreTextureImage(terrainTextureHandle, scene.Name + " Terrain", convoarID, mapbmp); // Link this image to the material terrainFace.TextureID = terrainTextureHandle.GetUUID(); } else { // Use the default texture code for terrain terrainTextureHandle = new EntityHandleUUID(defaultTextureID); BHash terrainHash = new BHashULong(defaultTextureID.GetHashCode()); assetFetcher.GetImageInfo(terrainHash, () => { ImageInfo terrainImageInfo = new ImageInfo(); terrainImageInfo.handle = terrainTextureHandle; assetFetcher.FetchTextureAsImage(terrainTextureHandle) .Then(img => { terrainImageInfo.image = img; }); return(terrainImageInfo); }); } // The above has created a MaterialInfo for the terrain texture ConvOAR.Globals.log.DebugFormat("{0}: CreateTerrainMesh. calling MeshFromHeightMap", LogHeader); DisplayableRenderable terrainDisplayable = assetMesher.MeshFromHeightMap(heightMap, terrainDef.Width, terrainDef.Height, assetFetcher, terrainFace); BInstance terrainInstance = new BInstance(); Displayable terrainDisp = new Displayable(terrainDisplayable); terrainDisp.name = "Terrain"; terrainDisp.baseUUID = OMV.UUID.Random(); terrainInstance.Representation = terrainDisp; return(terrainInstance); }
public bool GetDisplayable(BHash hash, out Displayable disp) { return(Displayables.TryGetValue(hash, out disp)); }
// Convert a SceneObjectGroup into an instance with displayables public IPromise <BInstance> ConvertSogToInstance(SceneObjectGroup sog, IAssetFetcher assetFetcher, PrimToMesh mesher) { var prom = new Promise <BInstance>(); LogBProgress("{0} ConvertSogToInstance: name={1}, id={2}, SOPs={3}", _logHeader, sog.Name, sog.UUID, sog.Parts.Length); // Create meshes for all the parts of the SOG Promise <Displayable> .All( sog.Parts.Select(sop => { LogBProgress("{0} ConvertSOGToInstance: Calling CreateMeshResource for sog={1}, sop={2}", _logHeader, sog.UUID, sop.UUID); OMV.Primitive aPrim = sop.Shape.ToOmvPrimitive(); return(mesher.CreateMeshResource(sog, sop, aPrim, assetFetcher, OMVR.DetailLevel.Highest)); }) ) .Then(renderables => { // Remove any failed SOG/SOP conversions. List <Displayable> filteredRenderables = renderables.Where(rend => rend != null).ToList(); // 'filteredRenderables' are the DisplayRenderables for all the SOPs in the SOG // Get the root prim of the SOG List <Displayable> rootDisplayableList = filteredRenderables.Where(disp => { return(disp.baseSOP.IsRoot); }).ToList(); if (rootDisplayableList.Count != 1) { // There should be only one root prim ConvOAR.Globals.log.ErrorFormat("{0} ConvertSOGToInstance: Found not one root prim in SOG. ID={1}, numRoots={2}", _logHeader, sog.UUID, rootDisplayableList.Count); prom.Reject(new Exception(String.Format("Found more than one root prim in SOG. ID={0}", sog.UUID))); return(null); } // The root of the SOG Displayable rootDisplayable = rootDisplayableList.First(); // Collect all the children prims and add them to the root Displayable rootDisplayable.children = filteredRenderables.Where(disp => { return(!disp.baseSOP.IsRoot); }).Select(disp => { return(disp); }).ToList(); return(rootDisplayable); }) .Done(rootDisplayable => { // Add the Displayable into the collection of known Displayables for instancing assetFetcher.AddUniqueDisplayable(rootDisplayable); // Package the Displayable into an instance that is position in the world BInstance inst = new BInstance(); inst.Position = sog.AbsolutePosition; inst.Rotation = sog.GroupRotation; inst.Representation = rootDisplayable; if (ConvOAR.Globals.parms.P <bool>("LogBuilding")) { DumpInstance(inst); } prom.Resolve(inst); }, e => { ConvOAR.Globals.log.ErrorFormat("{0} Failed meshing of SOG. ID={1}: {2}", _logHeader, sog.UUID, e); prom.Reject(new Exception(String.Format("failed meshing of SOG. ID={0}: {1}", sog.UUID, e))); }); return(prom); }