/// <summary> /// Given a FacetedMesh, create a DisplayableRenderable (a list of RenderableMesh's with materials). /// This also creates underlying MesnInfo, MaterialInfo, and ImageInfo in the AssetFetcher. /// </summary> /// <param name="assetFetcher"></param> /// <param name="fmesh">The FacetedMesh to convert into Renderables</param> /// <param name="defaultTexture">If a face doesn't have a texture defined, use this one. /// This is an OMV.Primitive.TextureEntryFace that includes a lot of OpenSimulator material info.</param> /// <param name="primScale">Scaling for the base prim that is used when appliying any texture /// to the face (updating UV).</param> /// <returns></returns> private DisplayableRenderable ConvertFacetedMeshToDisplayable(IAssetFetcher assetFetcher, OMVR.FacetedMesh fmesh, OMV.Primitive.TextureEntryFace defaultTexture, OMV.Vector3 primScale) { RenderableMeshGroup ret = new RenderableMeshGroup(); ret.meshes.AddRange(fmesh.Faces.Where(face => face.Indices.Count > 0).Select(face => { return(ConvertFaceToRenderableMesh(face, assetFetcher, defaultTexture, primScale)); })); // ConvOAR.Globals.log.DebugFormat("{0} ConvertFacetedMeshToDisplayable: complete. numMeshes={1}", _logHeader, ret.meshes.Count); return(ret); }
public void Init() { _parms = new ConvoarParams(); _log = new LoggerConsole(); ConvOAR.Globals = new GlobalContext(_parms, _log); _assetService = new MemAssetService(); _converter = new BConverterOS(); _scene = _converter.CreateScene(_assetService, "convoar-test"); _assetFetcher = new OSAssetFetcher(_assetService); OMV.UUID defaultTextureID = new OMV.UUID("179cdabd-398a-9b6b-1391-4dc333ba321f"); _defaultTexture = new OMV.Primitive.TextureEntryFace(null); _defaultTexture.TextureID = defaultTextureID; }
// 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 void Init() { _log = new BLoggerConsole(); _params = new ConvoarParams(); ConvOAR.Globals = new GlobalContext() { log = _log, parms = _params }; _assetService = new MemAssetService(); _converter = new OarConverter(_log, _params); _scene = _converter.CreateScene(_assetService, "convoar-test"); _assetManager = new AssetManager(_assetService, _log, _params.OutputDir); OMV.UUID defaultTextureID = new OMV.UUID("179cdabd-398a-9b6b-1391-4dc333ba321f"); _defaultTexture = new OMV.Primitive.TextureEntryFace(null) { TextureID = defaultTextureID }; }
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"); }
// 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); }
/// <summary> /// Apply texture coordinate modifications from a /// <seealso cref="TextureEntryFace"/> to a list of vertices /// </summary> /// <param name="vertices">Vertex list to modify texture coordinates for</param> /// <param name="center">Center-point of the face</param> /// <param name="teFace">Face texture parameters</param> public void TransformTexCoords(List <OMVR.Vertex> vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace, Vector3 primScale) { // compute trig stuff up front float cosineAngle = (float)Math.Cos(teFace.Rotation); float sinAngle = (float)Math.Sin(teFace.Rotation); for (int ii = 0; ii < vertices.Count; ii++) { // tex coord comes to us as a number between zero and one // transform about the center of the texture Vertex vert = vertices[ii]; // aply planar tranforms to the UV first if applicable if (teFace.TexMapType == MappingType.Planar) { Vector3 binormal; float d = Vector3.Dot(vert.Normal, Vector3.UnitX); if (d >= 0.5f || d <= -0.5f) { binormal = Vector3.UnitY; if (vert.Normal.X < 0f) { binormal *= -1; } } else { binormal = Vector3.UnitX; if (vert.Normal.Y > 0f) { binormal *= -1; } } Vector3 tangent = binormal % vert.Normal; Vector3 scaledPos = vert.Position * primScale; vert.TexCoord.X = 1f + (Vector3.Dot(binormal, scaledPos) * 2f - 0.5f); vert.TexCoord.Y = -(Vector3.Dot(tangent, scaledPos) * 2f - 0.5f); } float repeatU = teFace.RepeatU; float repeatV = teFace.RepeatV; float tX = vert.TexCoord.X - 0.5f; float tY = vert.TexCoord.Y - 0.5f; vert.TexCoord.X = (tX * cosineAngle + tY * sinAngle) * repeatU + teFace.OffsetU + 0.5f; vert.TexCoord.Y = (-tX * sinAngle + tY * cosineAngle) * repeatV + teFace.OffsetV + 0.5f; vertices[ii] = vert; } }
public MaterialInfo(OMV.Primitive.TextureEntryFace defaultTexture) { faceTexture = new OMV.Primitive.TextureEntryFace(defaultTexture); }
/// <summary> /// Apply texture coordinate modifications from a /// <seealso cref="TextureEntryFace"/> to a list of vertices /// </summary> /// <param name="vertices">Vertex list to modify texture coordinates for</param> /// <param name="center">Center-point of the face</param> /// <param name="teFace">Face texture parameters</param> public void TransformTexCoords(List <OMVR.Vertex> vertices, OMV.Vector3 center, OMV.Primitive.TextureEntryFace teFace) { // compute trig stuff up front float cosineAngle = (float)Math.Cos(teFace.Rotation); float sinAngle = (float)Math.Sin(teFace.Rotation); // need a check for plainer vs default // just do default for now (I don't know what planar is) for (int ii = 0; ii < vertices.Count; ii++) { // tex coord comes to us as a number between zero and one // transform about the center of the texture OMVR.Vertex vert = vertices[ii]; // repeat, offset, rotate // float tX = (vert.TexCoord.X - 0.5f) * teFace.RepeatU + teFace.OffsetU; // float tY = (vert.TexCoord.Y - 0.5f) * teFace.RepeatV - teFace.OffsetV; // vert.TexCoord.X = (tX * cosineAngle - tY * sinAngle) + 0.5f; // vert.TexCoord.Y = (tX * sinAngle + tY * cosineAngle) + 0.5f; float tX = vert.TexCoord.X - 0.5f; float tY = vert.TexCoord.Y - 0.5f; // rotate, scale, offset vert.TexCoord.X = (tX * cosineAngle - tY * sinAngle) * teFace.RepeatU - teFace.OffsetU + 0.5f; vert.TexCoord.Y = (tX * sinAngle + tY * cosineAngle) * teFace.RepeatV - teFace.OffsetV + 0.5f; vertices[ii] = vert; } return; }
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; } }
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); }