public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data) { // timestart = Time.realtimeSinceStartup; data = _data; mesh = _mesh; textures = data.textures.ToArray(); BuildrPlan plan = data.plan; int facadeIndex = 0; numberOfFacades = 0; int numberOfVolumes = data.plan.numberOfVolumes; LogTimer("Start"); //define rectangles that represent the facades packedTexturePositions.Clear(); for (int v = 0; v < numberOfVolumes; v++) { BuildrVolume volume = plan.volumes[v]; int numberOfVolumePoints = volume.points.Count; for (int f = 0; f < numberOfVolumePoints; f++) { if (!volume.renderFacade[f]) { continue; } int indexA = f; int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; Vector2z p0 = plan.points[volume.points[indexA]]; Vector2z p1 = plan.points[volume.points[indexB]]; float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER; int floorBase = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]); int numberOfFloors = volume.numberOfFloors - floorBase; if (numberOfFloors < 1)//no facade - adjacent facade is taller and covers this one { continue; } float floorHeight = data.floorHeight; float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER; if (facadeHeight < 0) { facadeWidth = 0; facadeHeight = 0; } Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight); packedTexturePositions.Add(newFacadeRect); numberOfFacades++; } } //Build ROOF DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh(); dynMeshRoof.name = "Roof Mesh"; dynMeshRoof.subMeshCount = textures.Length; BuildrRoof.Build(dynMeshRoof, data, true); dynMeshRoof.CheckMaxTextureUVs(data); LogTimer("Roof A"); roofTextures.Clear(); roofTextureIndex.Clear(); foreach (BuildrRoofDesign roofDesign in data.roofs) { foreach (int textureIndex in roofDesign.textureValues) { if (!roofTextureIndex.Contains(textureIndex)) { BuildrTexture bTexture = data.textures[textureIndex]; Vector2 largestSubmeshPlaneSize = new Vector2(1, 1); Vector2 minWorldUvSize = dynMeshRoof.MinWorldUvSize(textureIndex); Vector2 maxWorldUvSize = dynMeshRoof.MaxWorldUvSize(textureIndex); largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x; largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y; int roofTextureWidth = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER); int roofTextureHeight = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER); Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight); packedTexturePositions.Add(newRoofTexutureRect); roofTextures.Add(bTexture); roofTextureIndex.Add(textureIndex); } } } //run a custom packer to define their postions textureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING); //determine the resize scale and apply that to the rects packedScale = 1; int numberOfRects = packedTexturePositions.Count; if (textureWidth > MAXIMUM_TEXTURESIZE) { packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth; for (int i = 0; i < numberOfRects; i++) { Rect thisRect = packedTexturePositions[i]; thisRect.x *= packedScale; thisRect.y *= packedScale; thisRect.width *= packedScale; thisRect.height *= packedScale; packedTexturePositions[i] = thisRect; //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]); } textureWidth = Mathf.RoundToInt(packedScale * textureWidth); } else { textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two } //Debug.Log("Texture Width "+textureWidth); //TODO: maybe restrict the resize to a power of two? LogTimer("Packed Rect Generated"); textureSize = textureWidth * textureWidth; colourArray = new Color32[textureSize]; //TestRectColours();//this test paints all the facades with rainbow colours - real pretty BuildTextures(); LogTimer("texture created"); Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true); packedTexture.filterMode = FilterMode.Bilinear; packedTexture.SetPixels32(colourArray); packedTexture.Apply(true, false); LogTimer("apply"); if (data.LODTextureAtlas != null) { Object.DestroyImmediate(data.LODTextureAtlas); } data.LODTextureAtlas = packedTexture; data.LODTextureAtlas.name = "Low Detail Texture"; //build the model with new uvs if (data.drawUnderside) { for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; Vector3[] newEndVerts = new Vector3[numberOfVolumePoints]; Vector2[] newEndUVs = new Vector2[numberOfVolumePoints]; for (int i = 0; i < numberOfVolumePoints; i++) { newEndVerts[i] = plan.points[volume.points[i]].vector3; newEndUVs[i] = Vector2.zero; } List <int> tris = new List <int>(data.plan.GetTrianglesBySectorBase(s)); tris.Reverse(); mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0); } } LogTimer("Floor"); //Build facades for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; for (int f = 0; f < numberOfVolumePoints; f++) { if (!volume.renderFacade[f]) { continue; } int indexA = f; int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; Vector3 p0 = plan.points[volume.points[indexA]].vector3; Vector3 p1 = plan.points[volume.points[indexB]].vector3; int floorBase = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]); int numberOfFloors = volume.numberOfFloors - floorBase; if (numberOfFloors < 1) { //no facade - adjacent facade is taller and covers this one continue; } float floorHeight = data.floorHeight; Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight); Vector3 wallHeight = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart; p0 += floorHeightStart; p1 += floorHeightStart; Vector3 w0 = p0; Vector3 w1 = p1; Vector3 w2 = w0 + wallHeight; Vector3 w3 = w1 + wallHeight; Rect facadeRect = packedTexturePositions[facadeIndex]; float imageSize = textureWidth; Vector2 uvMin = new Vector2(facadeRect.xMin / imageSize, facadeRect.yMin / imageSize); Vector2 uvMax = new Vector2(facadeRect.xMax / imageSize, facadeRect.yMax / imageSize); mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0); facadeIndex++; } } LogTimer("Facades"); //ROOF Textures int roofRectBase = numberOfFacades; List <Rect> newAtlasRects = new List <Rect>(); for (int i = roofRectBase; i < packedTexturePositions.Count; i++) { Rect uvRect = new Rect();//generate a UV based rectangle off the packed one uvRect.x = packedTexturePositions[i].x / textureWidth; uvRect.y = packedTexturePositions[i].y / textureWidth; uvRect.width = packedTexturePositions[i].width / textureWidth; uvRect.height = packedTexturePositions[i].height / textureWidth; newAtlasRects.Add(uvRect); } dynMeshRoof.Atlas(roofTextureIndex.ToArray(), newAtlasRects.ToArray(), data.textures.ToArray()); //Add the atlased mesh data to the main model data at submesh 0 mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0); LogTimer("Roof B"); data = null; mesh = null; textures = null; //atlasRects = null; LogTimer("Done"); System.GC.Collect(); }
public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data) { // timestart = Time.realtimeSinceStartup; data = _data; mesh = _mesh; textures = data.textures.ToArray(); BuildrPlan plan = data.plan; int facadeIndex = 0; numberOfFacades = 0; int numberOfVolumes = data.plan.numberOfVolumes; LogTimer("Start"); //define rectangles that represent the facades packedTexturePositions.Clear(); for (int v = 0; v < numberOfVolumes; v++) { BuildrVolume volume = plan.volumes[v]; int numberOfVolumePoints = volume.points.Count; for (int f = 0; f < numberOfVolumePoints; f++) { if (!volume.renderFacade[f]) continue; int indexA = f; int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; Vector2z p0 = plan.points[volume.points[indexA]]; Vector2z p1 = plan.points[volume.points[indexB]]; float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER; int floorBase = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]); int numberOfFloors = volume.numberOfFloors - floorBase; if (numberOfFloors < 1)//no facade - adjacent facade is taller and covers this one continue; float floorHeight = data.floorHeight; float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER; if (facadeHeight < 0) { facadeWidth = 0; facadeHeight = 0; } Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight); packedTexturePositions.Add(newFacadeRect); numberOfFacades++; } } //Build ROOF DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh(); dynMeshRoof.name = "Roof Mesh"; dynMeshRoof.subMeshCount = textures.Length; BuildrRoof.Build(dynMeshRoof, data, true); dynMeshRoof.CheckMaxTextureUVs(data); LogTimer("Roof A"); roofTextures.Clear(); roofTextureIndex.Clear(); foreach (BuildrRoofDesign roofDesign in data.roofs) { foreach (int textureIndex in roofDesign.textureValues) { if (!roofTextureIndex.Contains(textureIndex)) { BuildrTexture bTexture = data.textures[textureIndex]; Vector2 largestSubmeshPlaneSize = new Vector2(1,1); Vector2 minWorldUvSize = dynMeshRoof.MinWorldUvSize(textureIndex); Vector2 maxWorldUvSize = dynMeshRoof.MaxWorldUvSize(textureIndex); largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x; largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y; int roofTextureWidth = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER); int roofTextureHeight = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER); Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight); packedTexturePositions.Add(newRoofTexutureRect); roofTextures.Add(bTexture); roofTextureIndex.Add(textureIndex); } } } //run a custom packer to define their postions textureWidth = RectanglePack.Pack(packedTexturePositions,ATLAS_PADDING); //determine the resize scale and apply that to the rects packedScale = 1; int numberOfRects = packedTexturePositions.Count; if (textureWidth > MAXIMUM_TEXTURESIZE) { packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth; for (int i = 0; i < numberOfRects; i++) { Rect thisRect = packedTexturePositions[i]; thisRect.x *= packedScale; thisRect.y *= packedScale; thisRect.width *= packedScale; thisRect.height *= packedScale; packedTexturePositions[i] = thisRect; //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]); } textureWidth = Mathf.RoundToInt(packedScale * textureWidth); } else { textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two } //Debug.Log("Texture Width "+textureWidth); //TODO: maybe restrict the resize to a power of two? LogTimer("Packed Rect Generated"); textureSize = textureWidth * textureWidth; colourArray = new Color32[textureSize]; //TestRectColours();//this test paints all the facades with rainbow colours - real pretty BuildTextures(); LogTimer("texture created"); Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true); packedTexture.filterMode = FilterMode.Bilinear; packedTexture.SetPixels32(colourArray); packedTexture.Apply(true, false); LogTimer("apply"); if (data.LODTextureAtlas != null) Object.DestroyImmediate(data.LODTextureAtlas); data.LODTextureAtlas = packedTexture; data.LODTextureAtlas.name = "Low Detail Texture"; //build the model with new uvs if (data.drawUnderside) { for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; Vector3[] newEndVerts = new Vector3[numberOfVolumePoints]; Vector2[] newEndUVs = new Vector2[numberOfVolumePoints]; for (int i = 0; i < numberOfVolumePoints; i++) { newEndVerts[i] = plan.points[volume.points[i]].vector3; newEndUVs[i] = Vector2.zero; } List<int> tris = new List<int>(data.plan.GetTrianglesBySectorBase(s)); tris.Reverse(); mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0); } } LogTimer("Floor"); //Build facades for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; for (int f = 0; f < numberOfVolumePoints; f++) { if (!volume.renderFacade[f]) continue; int indexA = f; int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; Vector3 p0 = plan.points[volume.points[indexA]].vector3; Vector3 p1 = plan.points[volume.points[indexB]].vector3; int floorBase = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]); int numberOfFloors = volume.numberOfFloors - floorBase; if (numberOfFloors < 1) { //no facade - adjacent facade is taller and covers this one continue; } float floorHeight = data.floorHeight; Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight); Vector3 wallHeight = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart; p0 += floorHeightStart; p1 += floorHeightStart; Vector3 w0 = p0; Vector3 w1 = p1; Vector3 w2 = w0 + wallHeight; Vector3 w3 = w1 + wallHeight; Rect facadeRect = packedTexturePositions[facadeIndex]; float imageSize = textureWidth; Vector2 uvMin = new Vector2(facadeRect.xMin / imageSize, facadeRect.yMin / imageSize); Vector2 uvMax = new Vector2(facadeRect.xMax / imageSize, facadeRect.yMax / imageSize); mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0); facadeIndex++; } } LogTimer("Facades"); //ROOF Textures int roofRectBase = numberOfFacades; List<Rect> newAtlasRects = new List<Rect>(); for (int i = roofRectBase; i < packedTexturePositions.Count; i++) { Rect uvRect = new Rect();//generate a UV based rectangle off the packed one uvRect.x = packedTexturePositions[i].x / textureWidth; uvRect.y = packedTexturePositions[i].y / textureWidth; uvRect.width = packedTexturePositions[i].width / textureWidth; uvRect.height = packedTexturePositions[i].height / textureWidth; newAtlasRects.Add(uvRect); } dynMeshRoof.Atlas(roofTextureIndex.ToArray(), newAtlasRects.ToArray(), data.textures.ToArray()); //Add the atlased mesh data to the main model data at submesh 0 mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0); LogTimer("Roof B"); data = null; mesh = null; textures = null; //atlasRects = null; LogTimer("Done"); System.GC.Collect(); }
/// <summary> /// Generate the detail meshes and return the export object /// </summary> /// <param name="mesh"></param> /// <param name="data"></param> /// <returns></returns> public static BuildrDetailExportObject Build(DynamicMeshGenericMultiMaterialMesh mesh, BuildrData data) { BuildrDetailExportObject exportObject = new BuildrDetailExportObject(); List<Texture2D> detailTextures = new List<Texture2D>(); List<int> detailSubmeshesWithTextures = new List<int>(); int numberOfDetails = data.details.Count; mesh.Clear(); mesh.subMeshCount = numberOfDetails; for(int d = 0; d < numberOfDetails; d++) { BuildrDetail detail = data.details[d]; if(detail.mesh == null) continue; int faceIndex = detail.face; Vector3 position = Vector3.zero; BuildrPlan plan = data.plan; int numberOfVolumes = plan.numberOfVolumes; Vector2 faceUv = detail.faceUv; Quaternion faceAngle = Quaternion.identity; //Place the detail mesh if (detail.type == BuildrDetail.Types.Facade) { //find facade int facadeCount = 0; bool facadeFound = false; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; for (int p = 0; p < numberOfVolumePoints; p++) { if (facadeCount == faceIndex) { int indexA = p; int indexB = (p + 1) % numberOfVolumePoints; Vector3 p0 = plan.points[volume.points[indexA]].vector3; Vector3 p1 = plan.points[volume.points[indexB]].vector3; Vector3 basePosition = Vector3.Lerp(p0, p1, faceUv.x); Vector3 detailHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight * faceUv.y); Vector3 facadeCross = Vector3.Cross(Vector3.up, p1 - p0).normalized; Vector3 detailDepth = facadeCross * detail.faceHeight; faceAngle = Quaternion.LookRotation(facadeCross); position = basePosition + detailHeight + detailDepth; facadeFound = true; break; } facadeCount++; } if (facadeFound) break; } } else//roof detail { BuildrVolume volume = plan.volumes[Mathf.Clamp(0,numberOfVolumes-1,faceIndex)]; int numberOfVolumePoints = volume.points.Count; Vector3 minimumRoofPoint = plan.points[volume.points[0]].vector3; Vector3 maximumRoofPoint = minimumRoofPoint; for (int p = 1; p < numberOfVolumePoints; p++) { Vector3 p0 = plan.points[volume.points[p]].vector3; if (p0.x < minimumRoofPoint.x) minimumRoofPoint.x = p0.x; if (p0.z < minimumRoofPoint.y) minimumRoofPoint.y = p0.z; if (p0.x > maximumRoofPoint.x) maximumRoofPoint.x = p0.x; if (p0.z > maximumRoofPoint.y) maximumRoofPoint.y = p0.z; } position.x = Mathf.Lerp(minimumRoofPoint.x, maximumRoofPoint.x, faceUv.x); position.z = Mathf.Lerp(minimumRoofPoint.y, maximumRoofPoint.y, faceUv.y); position.y = volume.numberOfFloors * data.floorHeight + detail.faceHeight; } Quaternion userRotation = Quaternion.Euler(detail.userRotation); int vertexCount = detail.mesh.vertexCount; Vector3[] verts = new Vector3[vertexCount]; Quaternion rotate = faceAngle * userRotation; for (int i = 0; i < vertexCount; i++) { Vector3 sourceVertex = Vector3.Scale(detail.mesh.vertices[i], detail.scale); Vector3 outputVertex = (rotate) * sourceVertex + position; verts[i] = outputVertex; } mesh.AddData(verts, detail.mesh.uv, detail.mesh.triangles, d); detail.worldPosition = position; detail.worldRotation = rotate; if (detail.material.mainTexture != null) { #if UNITY_EDITOR string texturePath = AssetDatabase.GetAssetPath(detail.material.mainTexture); TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath); if (!textureImporter.isReadable) { Debug.LogWarning("The texture you have selected is not readable. Cannot render"); return exportObject; } detailTextures.Add((Texture2D)detail.material.mainTexture); detailSubmeshesWithTextures.Add(d); #endif } } if(detailtexture!=null) Object.DestroyImmediate(detailtexture); List<Mesh> outputMeshes = new List<Mesh>(); if (detailSubmeshesWithTextures.Count > 0) { Rect[] textureRects = BuildrTexturePacker2.Pack(out detailtexture, detailTextures.ToArray(), 512); if(detailSubmeshesWithTextures.Count > 0) mesh.Atlas(detailSubmeshesWithTextures.ToArray(), textureRects); mesh.CollapseSubmeshes(); mesh.Build(); int numberOfMeshes = mesh.meshCount; for (int i = 0; i < numberOfMeshes; i++) outputMeshes.Add(mesh[i].mesh); } exportObject.detailMeshes = outputMeshes.ToArray(); exportObject.texture = detailtexture; return exportObject; /*if (detailMat == null) detailMat = new Material(Shader.Find("Diffuse")); detailMat.mainTexture = detailtexture; List<Mesh> outputMeshes = new List<Mesh>(); for (int i = 0; i < numberOfMeshes; i++) { outputMeshes.Add(mesh[i].mesh); GameObject details = new GameObject("details " + i); details.AddComponent<MeshFilter>().mesh = mesh[i].mesh; details.AddComponent<MeshRenderer>().sharedMaterial = detailMat; detailGameobjects.Add(details); } } // Debug.Log("BuildR Detail Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec"); return detailGameobjects.ToArray();*/ }
/// <summary> /// Generate the detail meshes and return the export object /// </summary> /// <param name="mesh"></param> /// <param name="data"></param> /// <returns></returns> public static BuildrDetailExportObject Build(DynamicMeshGenericMultiMaterialMesh mesh, BuildrData data) { BuildrDetailExportObject exportObject = new BuildrDetailExportObject(); List <Texture2D> detailTextures = new List <Texture2D>(); List <int> detailSubmeshesWithTextures = new List <int>(); int numberOfDetails = data.details.Count; mesh.Clear(); mesh.subMeshCount = numberOfDetails; for (int d = 0; d < numberOfDetails; d++) { BuildrDetail detail = data.details[d]; if (detail.mesh == null) { continue; } int faceIndex = detail.face; Vector3 position = Vector3.zero; BuildrPlan plan = data.plan; int numberOfVolumes = plan.numberOfVolumes; Vector2 faceUv = detail.faceUv; Quaternion faceAngle = Quaternion.identity; //Place the detail mesh if (detail.type == BuildrDetail.Types.Facade) { //find facade int facadeCount = 0; bool facadeFound = false; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; for (int p = 0; p < numberOfVolumePoints; p++) { if (facadeCount == faceIndex) { int indexA = p; int indexB = (p + 1) % numberOfVolumePoints; Vector3 p0 = plan.points[volume.points[indexA]].vector3; Vector3 p1 = plan.points[volume.points[indexB]].vector3; Vector3 basePosition = Vector3.Lerp(p0, p1, faceUv.x); Vector3 detailHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight * faceUv.y); Vector3 facadeCross = Vector3.Cross(Vector3.up, p1 - p0).normalized; Vector3 detailDepth = facadeCross * detail.faceHeight; faceAngle = Quaternion.LookRotation(facadeCross); position = basePosition + detailHeight + detailDepth; facadeFound = true; break; } facadeCount++; } if (facadeFound) { break; } } } else//roof detail { BuildrVolume volume = plan.volumes[Mathf.Clamp(0, numberOfVolumes - 1, faceIndex)]; int numberOfVolumePoints = volume.points.Count; Vector3 minimumRoofPoint = plan.points[volume.points[0]].vector3; Vector3 maximumRoofPoint = minimumRoofPoint; for (int p = 1; p < numberOfVolumePoints; p++) { Vector3 p0 = plan.points[volume.points[p]].vector3; if (p0.x < minimumRoofPoint.x) { minimumRoofPoint.x = p0.x; } if (p0.z < minimumRoofPoint.y) { minimumRoofPoint.y = p0.z; } if (p0.x > maximumRoofPoint.x) { maximumRoofPoint.x = p0.x; } if (p0.z > maximumRoofPoint.y) { maximumRoofPoint.y = p0.z; } } position.x = Mathf.Lerp(minimumRoofPoint.x, maximumRoofPoint.x, faceUv.x); position.z = Mathf.Lerp(minimumRoofPoint.y, maximumRoofPoint.y, faceUv.y); position.y = volume.numberOfFloors * data.floorHeight + detail.faceHeight; } Quaternion userRotation = Quaternion.Euler(detail.userRotation); int vertexCount = detail.mesh.vertexCount; Vector3[] verts = new Vector3[vertexCount]; Quaternion rotate = faceAngle * userRotation; for (int i = 0; i < vertexCount; i++) { Vector3 sourceVertex = Vector3.Scale(detail.mesh.vertices[i], detail.scale); Vector3 outputVertex = (rotate) * sourceVertex + position; verts[i] = outputVertex; } mesh.AddData(verts, detail.mesh.uv, detail.mesh.triangles, d); detail.worldPosition = position; detail.worldRotation = rotate; if (detail.material.mainTexture != null) { #if UNITY_EDITOR string texturePath = AssetDatabase.GetAssetPath(detail.material.mainTexture); TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath); if (!textureImporter.isReadable) { Debug.LogWarning("The texture you have selected is not readable. Cannot render"); return(exportObject); } detailTextures.Add((Texture2D)detail.material.mainTexture); detailSubmeshesWithTextures.Add(d); #endif } } if (detailtexture != null) { Object.DestroyImmediate(detailtexture); } List <Mesh> outputMeshes = new List <Mesh>(); if (detailSubmeshesWithTextures.Count > 0) { Rect[] textureRects = BuildrTexturePacker2.Pack(out detailtexture, detailTextures.ToArray(), 512); if (detailSubmeshesWithTextures.Count > 0) { mesh.Atlas(detailSubmeshesWithTextures.ToArray(), textureRects); } mesh.CollapseSubmeshes(); mesh.Build(); int numberOfMeshes = mesh.meshCount; for (int i = 0; i < numberOfMeshes; i++) { outputMeshes.Add(mesh[i].mesh); } } exportObject.detailMeshes = outputMeshes.ToArray(); exportObject.texture = detailtexture; return(exportObject); /*if (detailMat == null) * detailMat = new Material(Shader.Find("Diffuse")); * detailMat.mainTexture = detailtexture; * List<Mesh> outputMeshes = new List<Mesh>(); * for (int i = 0; i < numberOfMeshes; i++) * { * outputMeshes.Add(mesh[i].mesh); * GameObject details = new GameObject("details " + i); * details.AddComponent<MeshFilter>().mesh = mesh[i].mesh; * details.AddComponent<MeshRenderer>().sharedMaterial = detailMat; * detailGameobjects.Add(details); * } * } * // Debug.Log("BuildR Detail Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec"); * return detailGameobjects.ToArray();*/ }