private static void GenerateFloorPlan(BuildrData data) { BuildrGenerateConstraints constraints = data.generatorConstraints; RandomGen rgen = constraints.rgen; BuildrPlan plan = ScriptableObject.CreateInstance <BuildrPlan>(); List <Vector2z> bounds = new List <Vector2z>(); Rect floorplanBounds = new Rect(-15, -15, 30, 30); if (constraints.constrainPlanByArea) { floorplanBounds = constraints.area; } bounds.Add(new Vector2z(rgen.OutputRange(-5, floorplanBounds.xMin), rgen.OutputRange(-5, floorplanBounds.yMin))); bounds.Add(new Vector2z(rgen.OutputRange(5, floorplanBounds.xMax), rgen.OutputRange(-5, floorplanBounds.yMin))); bounds.Add(new Vector2z(rgen.OutputRange(5, floorplanBounds.xMax), rgen.OutputRange(5, floorplanBounds.yMax))); bounds.Add(new Vector2z(rgen.OutputRange(-5, floorplanBounds.xMin), rgen.OutputRange(5, floorplanBounds.yMax))); if (rgen.output < 0.25f)//should we split the volume? { float ratio = rgen.OutputRange(0.25f, 0.75f); bounds.Insert(1, Vector2z.Lerp(bounds[0], bounds[1], ratio)); bounds.Insert(4, Vector2z.Lerp(bounds[3], bounds[4], ratio)); plan.AddVolume(new [] { bounds[0], bounds[1], bounds[4], bounds[5] }); plan.AddVolume(1, 2, new [] { bounds[2], bounds[3] }); } else { plan.AddVolume(bounds.ToArray()); } data.plan = plan; }
private static void GenerateFloorPlan(BuildrData data) { RandomGen rgen = constraints.rgen; BuildrPlan plan = ScriptableObject.CreateInstance <BuildrPlan>(); List <Vector2z> bounds = new List <Vector2z>(); bounds.Add(new Vector2z(rgen.OutputRange(-5, -15), rgen.OutputRange(-5, -15))); bounds.Add(new Vector2z(rgen.OutputRange(5, 15), rgen.OutputRange(-5, -15))); bounds.Add(new Vector2z(rgen.OutputRange(5, 15), rgen.OutputRange(5, 15))); bounds.Add(new Vector2z(rgen.OutputRange(-5, -15), rgen.OutputRange(5, 15))); if (rgen.output < 0.25f)//should we split the volume? { float ratio = rgen.OutputRange(0.25f, 0.75f); bounds.Insert(1, Vector2z.Lerp(bounds[0], bounds[1], ratio)); bounds.Insert(4, Vector2z.Lerp(bounds[3], bounds[4], ratio)); plan.AddVolume(new [] { bounds[0], bounds[1], bounds[4], bounds[5] }); plan.AddVolume(1, 2, new [] { bounds[2], bounds[3] }); } else { plan.AddVolume(bounds.ToArray()); } data.plan = plan; }
public void ResetData(bool keepPlan) { if (!keepPlan) { DestroyImmediate(plan); plan = ScriptableObject.CreateInstance <BuildrPlan>(); } facades.Clear(); roofs.Clear(); textures.Clear(); bays.Clear(); details.Clear(); }
private static void Steeple(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; int numberOfVolumePoints = volume.points.Count; Vector3[] basePoints = new Vector3[numberOfVolumePoints]; Vector3 centrePoint = Vector3.zero; for (int l = 0; l < numberOfVolumePoints; l++) { basePoints[l] = area.points[volume.points[l]].vector3 + volumeFloorHeight; centrePoint += area.points[volume.points[l]].vector3; } centrePoint = (centrePoint / numberOfVolumePoints) + volumeFloorHeight + ridgeVector; for (int l = 0; l < numberOfVolumePoints; l++) { int pointIndexA = l; int pointIndexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0; Vector3[] verts = new Vector3[3] { basePoints[pointIndexA], basePoints[pointIndexB], centrePoint }; float uvWdith = Vector3.Distance(basePoints[pointIndexA], basePoints[pointIndexB]); float uvHeight = design.height; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.tiles); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdith *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdith = Mathf.Ceil(uvWdith / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdith = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvs = new Vector2[3] { new Vector2(-uvWdith / 2, 0), new Vector2(uvWdith / 2, 0), new Vector2(0, uvHeight) }; int[] tri = new int[3] { 1, 0, 2 }; AddData(verts, uvs, tri, subMesh); } }
public void Init() { DestroyImmediate(plan); plan = ScriptableObject.CreateInstance <BuildrPlan>(); facades.Add(new BuildrFacadeDesign("default")); //set up two basic textures to use textures.Add(new BuildrTexture("bricks")); textures.Add(new BuildrTexture("window")); textures.Add(new BuildrTexture("roof")); roofs.Add(new BuildrRoofDesign("default")); bays.Add(new BuildrBay("default")); DestroyImmediate(generatorConstraints); generatorConstraints = ScriptableObject.CreateInstance <BuildrGenerateConstraints>(); generatorConstraints.Init(); }
private static void FlatRoof(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int volumeIndex = area.volumes.IndexOf(volume); int numberOfVolumePoints = volume.points.Count; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); //add top base of the flat roof Vector3[] newEndVerts = new Vector3[numberOfVolumePoints]; Vector2[] newEndUVs = new Vector2[numberOfVolumePoints]; int[] tris = new List<int>(area.GetTrianglesBySectorBase(volumeIndex)).ToArray(); int roofTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floor); BuildrTexture texture = data.textures[roofTextureID]; for (int i = 0; i < numberOfVolumePoints; i++) { Vector2z point = area.points[volume.points[i]]; newEndVerts[i] = point.vector3 + volumeFloorHeight; newEndUVs[i] = new Vector2(point.vector2.x / texture.textureUnitSize.x, point.vector2.y / texture.textureUnitSize.y); } AddData(newEndVerts, newEndUVs, tris, design.GetTexture(BuildrRoofDesign.textureNames.floor)); }
public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize) { if (data.details.Count == 0) { return; } Undo.RecordObject(data, "Detail Modified"); int numberOfFacades = data.facades.Count; int numberOfRoofs = data.roofs.Count; int numberOfTextures = data.textures.Count; if (numberOfFacades == 0 || numberOfRoofs == 0 || numberOfTextures == 0) { return; } Vector3 position = editMode.transform.position; BuildrPlan plan = data.plan; int numberOfVolumes = plan.numberOfVolumes; BuildrDetail bDetail = data.details[selectedDetail]; float volumeHeight = 0; Vector3 baseLeft = Vector3.zero; Vector3 baseRight = Vector3.zero; int faceIndex = bDetail.face; int facadeCounter = 0; for (int v = 0; v < numberOfVolumes; v++) { BuildrVolume volume = data.plan.volumes[v]; int volumeSize = volume.Count; Vector3 floorCentre = Vector3.zero; Handles.color = Color.white; for (int p = 0; p < volumeSize; p++) { int point = volume.points[p]; int indexB = volume.points[(p + 1) % volumeSize]; Vector3 fb0 = plan.points[point].vector3; Vector3 fb1 = plan.points[indexB].vector3; if (bDetail.face == facadeCounter && bDetail.type == BuildrDetail.Types.Facade) { baseLeft = fb0; baseRight = fb1; } floorCentre += baseLeft; List <Vector3> verts = new List <Vector3>(); volumeHeight = (volume.numberOfFloors * data.floorHeight); Vector3 volumeHeightVector = Vector3.up * volumeHeight; verts.Add(fb0 + position); verts.Add(fb1 + position); verts.Add(verts[1] + volumeHeightVector); verts.Add(verts[0] + volumeHeightVector); if (bDetail.face == facadeCounter && bDetail.type == BuildrDetail.Types.Facade) { //display something to highlight this facade Handles.DrawSolidRectangleWithOutline(verts.ToArray(), Color.clear, BuildrColours.MAGENTA); } Handles.color = BuildrColours.CYAN; if (v == bDetail.face && bDetail.type == BuildrDetail.Types.Roof) { Handles.DrawLine(verts[2], verts[3]); } if (editMode.showFacadeMarkers) { Handles.color = Color.white; Vector3 camDirection = Camera.current.transform.forward; Vector3 facadeDirection = Vector3.Cross((verts[0] - verts[1]), Vector3.up); GUIStyle facadeLabelStyle = new GUIStyle(); facadeLabelStyle.normal.textColor = Color.white; facadeLabelStyle.alignment = TextAnchor.MiddleCenter; facadeLabelStyle.fixedWidth = 75.0f; if (Vector3.Dot(camDirection, facadeDirection) < 0)//only display label when facade is facing camera { Vector3 centerPos = (verts[0] + verts[1]) * 0.5f; Vector3 labelPos = centerPos + facadeDirection.normalized; Handles.Label(labelPos, "facade " + facadeCounter, facadeLabelStyle); Handles.DrawLine(centerPos, labelPos); } } facadeCounter++; } } Vector3 handlePosition = bDetail.worldPosition + position;// new Vector3(basePos.x, volumeHeight * bDetail.faceUv.y, basePos.z); Vector3 baseDir = (baseRight - baseLeft).normalized; Vector3 baseCross = Vector3.Cross(Vector3.up, baseDir); Quaternion currentRot = Quaternion.Euler(bDetail.userRotation); Quaternion faceRotation = (bDetail.type == BuildrDetail.Types.Facade) ? Quaternion.LookRotation(baseCross) : Quaternion.identity; switch (Tools.current) { case Tool.Move: Vector3 dirX, dirY, dirZ; if (bDetail.type == BuildrDetail.Types.Facade) { dirX = baseDir; dirY = baseCross; dirZ = Vector3.up; } else { dirX = Vector3.right; dirY = Vector3.up; dirZ = Vector3.forward; } Vector3 newSliderPos; Handles.color = BuildrColours.RED; newSliderPos = Handles.Slider(handlePosition, dirX, handleSize * 0.666f, Handles.ArrowCap, 0.0f); Handles.color = BuildrColours.BLUE; newSliderPos = Handles.Slider(newSliderPos, dirZ, handleSize * 0.666f, Handles.ArrowCap, 0.0f); Handles.color = BuildrColours.GREEN; newSliderPos = Handles.Slider(newSliderPos, dirY, handleSize * 0.666f, Handles.ArrowCap, 0.0f); Vector3 sliderDiff = newSliderPos - handlePosition; if (sliderDiff != Vector3.zero) { float newXUV = 0, newYUV = 0, newHeight = bDetail.faceHeight; if (bDetail.type == BuildrDetail.Types.Facade) { float facadeWidth = Vector3.Distance(baseLeft, baseRight); float sliderDiffX = Mathf.Sqrt(sliderDiff.x * sliderDiff.x + sliderDiff.z * sliderDiff.z) * Mathf.Sign(Vector3.Dot(baseDir, sliderDiff)); newXUV = sliderDiffX / facadeWidth + bDetail.faceUv.x; newYUV = sliderDiff.y / volumeHeight + bDetail.faceUv.y; } else { BuildrVolume volume = plan.volumes[faceIndex]; int numberOfVolumePoints = volume.points.Count; Vector3 minPoint = plan.points[volume.points[0]].vector3; Vector3 maxPoint = plan.points[volume.points[0]].vector3; for (int p = 1; p < numberOfVolumePoints; p++) { Vector3 fp0 = plan.points[volume.points[p]].vector3; if (fp0.x < minPoint.x) { minPoint.x = fp0.x; } if (fp0.z < minPoint.z) { minPoint.z = fp0.z; } if (fp0.x > maxPoint.x) { maxPoint.x = fp0.x; } if (fp0.z > maxPoint.z) { maxPoint.z = fp0.z; } } float roofWidth = maxPoint.x - minPoint.x; float roofDepth = maxPoint.z - minPoint.z; newXUV = sliderDiff.x / roofWidth + bDetail.faceUv.x; newYUV = sliderDiff.z / roofDepth + bDetail.faceUv.y; newHeight += sliderDiff.y; } bDetail.faceUv = new Vector2(newXUV, newYUV); bDetail.faceHeight = newHeight; } break; case Tool.Rotate: currentRot = Handles.RotationHandle(currentRot, handlePosition); bDetail.userRotation = currentRot.eulerAngles; break; case Tool.Scale: bDetail.scale = Handles.ScaleHandle(bDetail.scale, handlePosition, currentRot * faceRotation, handleSize * 0.666f); break; } //draw mesh bounds if (bDetail.mesh != null) { Bounds meshBounds = bDetail.mesh.bounds; Quaternion rotation = bDetail.worldRotation; Vector3 p0 = rotation * (new Vector3(meshBounds.min.x, meshBounds.min.y, meshBounds.min.z)) + bDetail.worldPosition; Vector3 p1 = rotation * (new Vector3(meshBounds.max.x, meshBounds.min.y, meshBounds.min.z)) + bDetail.worldPosition; Vector3 p2 = rotation * (new Vector3(meshBounds.min.x, meshBounds.min.y, meshBounds.max.z)) + bDetail.worldPosition; Vector3 p3 = rotation * (new Vector3(meshBounds.max.x, meshBounds.min.y, meshBounds.max.z)) + bDetail.worldPosition; Vector3 p4 = rotation * (new Vector3(meshBounds.min.x, meshBounds.max.y, meshBounds.min.z)) + bDetail.worldPosition; Vector3 p5 = rotation * (new Vector3(meshBounds.max.x, meshBounds.max.y, meshBounds.min.z)) + bDetail.worldPosition; Vector3 p6 = rotation * (new Vector3(meshBounds.min.x, meshBounds.max.y, meshBounds.max.z)) + bDetail.worldPosition; Vector3 p7 = rotation * (new Vector3(meshBounds.max.x, meshBounds.max.y, meshBounds.max.z)) + bDetail.worldPosition; Handles.color = BuildrColours.BLUE; Handles.DrawLine(p0, p1); Handles.DrawLine(p0, p2); Handles.DrawLine(p1, p3); Handles.DrawLine(p2, p3); Handles.DrawLine(p0, p4); Handles.DrawLine(p1, p5); Handles.DrawLine(p2, p6); Handles.DrawLine(p3, p7); Handles.DrawLine(p4, p5); Handles.DrawLine(p4, p6); Handles.DrawLine(p5, p7); Handles.DrawLine(p6, p7); if (clickPlace) { Vector3 planeBase = Vector3.zero; Vector3 planeNormal = Vector3.up; Vector3 planeSize = Vector3.zero; if (bDetail.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 fp0 = plan.points[volume.points[indexA]].vector3; Vector3 fp1 = plan.points[volume.points[indexB]].vector3; planeBase = fp0; planeNormal = Vector3.Cross(Vector3.up, fp1 - fp0).normalized; planeSize.x = Vector3.Distance(fp0, fp1); planeSize.y = volume.numberOfFloors * data.floorHeight; facadeFound = true; break; } facadeCount++; } if (facadeFound) { break; } } } else { BuildrVolume volume = plan.volumes[faceIndex]; int numberOfVolumePoints = volume.points.Count; Vector3 minPoint = plan.points[volume.points[0]].vector3; Vector3 maxPoint = plan.points[volume.points[0]].vector3; for (int p = 1; p < numberOfVolumePoints; p++) { Vector3 fp0 = plan.points[volume.points[p]].vector3; if (fp0.x < minPoint.x) { minPoint.x = fp0.x; } if (fp0.z < minPoint.z) { minPoint.z = fp0.z; } if (fp0.x > maxPoint.x) { maxPoint.x = fp0.x; } if (fp0.z > maxPoint.z) { maxPoint.z = fp0.z; } } planeSize.x = maxPoint.x - minPoint.x; planeSize.z = maxPoint.z - minPoint.z; planeBase = minPoint; planeBase.y = (data.floorHeight * volume.numberOfFloors); } float distance; Plane buildingPlane = new Plane(planeNormal, planeBase); Ray ray = Camera.current.ScreenPointToRay(new Vector3(Event.current.mousePosition.x, Screen.height - Event.current.mousePosition.y - 30, 0)); if (buildingPlane.Raycast(ray, out distance)) { Vector3 mousePlanePoint = ray.GetPoint(distance); Quaternion mouseLookDirection = Quaternion.LookRotation(buildingPlane.normal); if (Handles.Button(mousePlanePoint, mouseLookDirection, handleSize * 0.1f, handleSize * 0.1f, Handles.CircleCap)) { float xUv, yUv; if (bDetail.type == BuildrDetail.Types.Facade) { Vector3 facadeBaseMousePoint = new Vector3(mousePlanePoint.x, 0, mousePlanePoint.z); xUv = Vector3.Distance(planeBase, facadeBaseMousePoint) / planeSize.x; yUv = (mousePlanePoint.y - planeBase.y) / planeSize.y; } else { xUv = (mousePlanePoint.x - planeBase.x) / planeSize.x; yUv = (mousePlanePoint.z - planeBase.z) / planeSize.z; } bDetail.faceUv = new Vector2(xUv, yUv); clickPlace = false; GUI.changed = true; } } } } if (GUI.changed) { EditorUtility.SetDirty(editMode); EditorUtility.SetDirty(data); editMode.UpdateRender(); } }
private static void Barrel(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3[] points = new Vector3[4]; //Vector3 ridgeVector; if (design.direction == 0) { points[0] = area.points[volume.points[0]].vector3 + volumeFloorHeight; points[1] = area.points[volume.points[3]].vector3 + volumeFloorHeight; points[2] = area.points[volume.points[1]].vector3 + volumeFloorHeight; points[3] = area.points[volume.points[2]].vector3 + volumeFloorHeight; } else { points[0] = area.points[volume.points[1]].vector3 + volumeFloorHeight; points[1] = area.points[volume.points[0]].vector3 + volumeFloorHeight; points[2] = area.points[volume.points[2]].vector3 + volumeFloorHeight; points[3] = area.points[volume.points[3]].vector3 + volumeFloorHeight; } int barrelSegments = design.barrelSegments + 1; Vector3[] bPoints = new Vector3[barrelSegments * 2]; for (int i = 0; i < barrelSegments; i++) { float lerp = (float)i / (float)(barrelSegments - 1); Vector3 height = Mathf.Sin(lerp * Mathf.PI) * design.height * Vector3.up; float cosLerp = 1 - (Mathf.Cos((lerp) * Mathf.PI) + 1) / 2; bPoints[i] = Vector3.Lerp(points[0], points[1], cosLerp) + height; bPoints[i + barrelSegments] = Vector3.Lerp(points[2], points[3], cosLerp) + height; } int topIterations = barrelSegments - 1; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flipped = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); for (int t = 0; t < topIterations; t++) AddPlane(design, bPoints[t + 1], bPoints[t], bPoints[t + barrelSegments + 1], bPoints[t + barrelSegments], subMesh, flipped);//top Vector3 centerA = Vector3.Lerp(points[0], points[1], 0.5f); Vector3 centerB = Vector3.Lerp(points[2], points[3], 0.5f); for (int e = 0; e < topIterations; e++) { float lerpA = ((float)(e) / (float)(topIterations)) * Mathf.PI; float lerpB = ((float)(e + 1) / (float)(topIterations)) * Mathf.PI; Vector2[] uvs = new Vector2[3]{ new Vector2(0.5f,0), new Vector2(1-(Mathf.Cos(lerpA)+1)/2,Mathf.Sin(lerpA)), new Vector2(1-(Mathf.Cos(lerpB)+1)/2,Mathf.Sin(lerpB)) }; Vector3[] verts = new Vector3[3] { centerA, bPoints[e], bPoints[e + 1] }; int[] tri = new int[3] { 0, 2, 1 }; AddData(verts, uvs, tri, design.GetTexture(BuildrRoofDesign.textureNames.window)); verts = new Vector3[3] { centerB, bPoints[e + barrelSegments], bPoints[e + 1 + barrelSegments] }; tri = new int[3] { 0, 1, 2 }; AddData(verts, uvs, tri, design.GetTexture(BuildrRoofDesign.textureNames.window)); } }
public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data) { data = _data; mesh = _mesh; BuildrPlan plan = data.plan; int facadeIndex = 0; int numberOfVolumes = data.plan.numberOfVolumes; 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]; Vector3 volumeHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight); for (int i = 0; i < numberOfVolumePoints; i++) { newEndVerts[i] = plan.points[volume.points[i]].vector3 + volumeHeight; newEndUVs[i] = Vector2.zero; } List <int> tris = new List <int>(data.plan.GetTrianglesBySectorBase(s)); mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0); } //Build ROOF //Build facades 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; Vector3 p0 = plan.points[volume.points[indexA]].vector3; Vector3 p1 = plan.points[volume.points[indexB]].vector3; 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; Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight); Vector3 wallHeight = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart; float facadeWidth = Vector3.Distance(p0, p1); p0 += floorHeightStart; p1 += floorHeightStart; Vector3 w0 = p0; Vector3 w1 = p1; Vector3 w2 = w0 + wallHeight; Vector3 w3 = w1 + wallHeight; Vector2 uvMin = new Vector2(0, 0); Vector2 uvMax = new Vector2(facadeWidth, floorHeight); mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0); facadeIndex++; } } data = null; mesh = null; }
private static void LeanTo(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; int[] pointIndexes = new int[4]; switch (design.direction) { case 0: pointIndexes = new int[4] { 0, 1, 2, 3 }; break; case 1: pointIndexes = new int[4] { 1, 2, 3, 0 }; break; case 2: pointIndexes = new int[4] { 2, 3, 0, 1 }; break; case 3: pointIndexes = new int[4] { 3, 0, 1, 2 }; break; } Vector3[] points = new Vector3[6]; points[0] = area.points[volume.points[pointIndexes[0]]].vector3 + volumeFloorHeight; points[1] = area.points[volume.points[pointIndexes[1]]].vector3 + volumeFloorHeight; points[2] = area.points[volume.points[pointIndexes[2]]].vector3 + volumeFloorHeight; points[3] = area.points[volume.points[pointIndexes[3]]].vector3 + volumeFloorHeight; points[4] = area.points[volume.points[pointIndexes[2]]].vector3 + volumeFloorHeight + ridgeVector; points[5] = area.points[volume.points[pointIndexes[3]]].vector3 + volumeFloorHeight + ridgeVector; //top int subMeshTop = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flippedTop = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, points[0], points[1], points[5], points[4], subMeshTop, flippedTop); //window int subMeshWindow = design.GetTexture(BuildrRoofDesign.textureNames.window); bool flippedWindow = design.IsFlipped(BuildrRoofDesign.textureNames.window); AddPlane(design, points[2], points[3], points[4], points[5], subMeshWindow, flippedWindow); //sides Vector3[] vertsA = new Vector3[3] { points[1], points[2], points[4] }; Vector3[] vertsB = new Vector3[3] { points[0], points[3], points[5] }; float uvWdith = Vector3.Distance(points[0], points[3]); float uvHeight = design.height; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.wall); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdith *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdith = Mathf.Ceil(uvWdith / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdith = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvs = new Vector2[3] { new Vector2(0, 0), new Vector2(uvWdith, 0), new Vector2(uvWdith, uvHeight) }; if (!design.IsFlipped(BuildrRoofDesign.textureNames.wall)) uvs = new Vector2[3] { new Vector2(uvWdith, 0), new Vector2(0, 0), new Vector2(uvHeight, uvWdith / 2) }; int[] triA = new int[3] { 1, 0, 2 }; int[] triB = new int[3] { 0, 1, 2 }; AddData(vertsA, uvs, triA, subMesh); AddData(vertsB, uvs, triB, subMesh); }
public static void SceneGUI(BuildrEditMode editMode, BuildrData _data, bool shouldSnap, float handleSize) { data = _data; Vector3 camDirection = Camera.current.transform.forward; Vector3 camPosition = Camera.current.transform.position; int numberOfFacades = data.facades.Count; int numberOfRoofs = data.roofs.Count; int numberOfTextures = data.textures.Count; if (numberOfFacades == 0 || numberOfRoofs == 0 || numberOfTextures == 0) { return; } Vector3 position = editMode.transform.position; float floorHeight = data.floorHeight; BuildrPlan area = data.plan; int numberOfVolumes = area.numberOfVolumes; int facadeCounter = 0; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = data.plan.volumes[s]; int volumeSize = volume.Count; Vector3 floorCentre = Vector3.zero; Handles.color = Color.white; for (int p = 0; p < volumeSize; p++) { int point = volume.points[p]; Vector3 pointPos = area.points[point].vector3; floorCentre += pointPos; List <Vector3> verts = new List <Vector3>(); int indexB = (p < volumeSize - 1) ? p + 1 : 0; Vector3 volumeHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight); verts.Add(pointPos + position); verts.Add(area.points[volume.points[indexB]].vector3 + position); verts.Add(verts[1] + volumeHeight); verts.Add(verts[0] + volumeHeight); if (s == selectedVolume && point == selectedPoint) { //display something to highlight this facade Handles.DrawSolidRectangleWithOutline(verts.ToArray(), Color.clear, BuildrColours.MAGENTA); } Handles.color = BuildrColours.CYAN; if (s == selectedRoofVolume) { Handles.DrawLine(verts[2], verts[3]); } if (editMode.showFacadeMarkers) { Handles.color = Color.white; Vector3 facadeDirection = Vector3.Cross((verts[0] - verts[1]), Vector3.up); GUIStyle facadeLabelStyle = new GUIStyle(); facadeLabelStyle.normal.textColor = Color.white; facadeLabelStyle.alignment = TextAnchor.MiddleCenter; facadeLabelStyle.fixedWidth = 75.0f; Vector3 centerPos = (verts[0] + verts[1]) * 0.5f; bool camVisible = Vector3.Dot(camDirection, centerPos - camPosition) > 0; bool facadeVisible = Vector3.Dot(camDirection, facadeDirection) < 0; if (camVisible && facadeVisible)//only display label when facade is facing camera and is in camera view { Vector3 labelPos = centerPos + facadeDirection.normalized; Handles.Label(labelPos, "facade " + facadeCounter, facadeLabelStyle); Handles.DrawLine(centerPos, labelPos); } } facadeCounter++; } floorCentre /= volumeSize; //Volume height/floor number slider Vector3 volumeHeightDir = Vector3.up * (volume.numberOfFloors * data.floorHeight); Vector3 volumePosition = floorCentre + position + volumeHeightDir; if (Vector3.Dot(camDirection, volumePosition - camPosition) > 0)//only display label when facade is facing camera { Handles.Label(volumePosition + (Vector3.up * (handleSize * 0.1f)), "volume " + s); Handles.Label(volumePosition, "number of floors " + volume.numberOfFloors); } Handles.color = Color.green; volume.height = Handles.Slider(volumePosition, Vector3.up).y - position.y; if (volume.height < data.floorHeight) { volume.height = data.floorHeight; } volume.numberOfFloors = Mathf.RoundToInt(volume.height / floorHeight); } }
public void Init() { plan = CreateInstance <BuildrPlan>(); rgen = new RandomGen((useSeed) ? (uint)_seed : (uint)Random.Range(0, int.MaxValue)); }
private static void BuildSimple(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data) { BuildrData data = _data; DynamicMeshGenericMultiMaterialMesh mesh = _mesh; BuildrPlan plan = data.plan; int facadeIndex = 0; int numberOfVolumes = data.plan.numberOfVolumes; //Build Floor 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); } } //Build ROOF DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh(); dynMeshRoof.subMeshCount = data.textures.Count; BuildrRoof.Build(dynMeshRoof, data, true); mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0); Vector3 foundationVector = Vector3.down * data.foundationHeight; //Build facades for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int numberOfVolumePoints = volume.points.Count; for (int l = 0; l < numberOfVolumePoints; l++) { int indexA = l; int indexB = (l < numberOfVolumePoints - 1) ? l + 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; if (floorBase == 0) { w0 += foundationVector; w1 += foundationVector; } mesh.AddPlane(w0, w1, w2, w3, Vector2.zero, Vector2.zero, 0); facadeIndex++; } } data = null; mesh = null; }
public void ResetData(bool keepPlan) { if(!keepPlan) { DestroyImmediate(plan); plan = ScriptableObject.CreateInstance<BuildrPlan>(); } facades.Clear(); roofs.Clear(); textures.Clear(); bays.Clear(); details.Clear(); }
public void Init() { DestroyImmediate(plan); plan = ScriptableObject.CreateInstance<BuildrPlan>(); facades.Add(new BuildrFacadeDesign("default")); //set up two basic textures to use textures.Add(new BuildrTexture("bricks")); textures.Add(new BuildrTexture("window")); textures.Add(new BuildrTexture("roof")); roofs.Add(new BuildrRoofDesign("default")); bays.Add(new BuildrBay("default")); DestroyImmediate(generatorConstraints); generatorConstraints = ScriptableObject.CreateInstance<BuildrGenerateConstraints>(); generatorConstraints.Init(); }
private static void Dormers(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfVolumePoints = volume.points.Count; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); for (int l = 0; l < numberOfVolumePoints; l++) { int indexA, indexB, indexA0, indexB0; Vector3 p0, p1, p00, p10; indexA = l; indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0; indexA0 = (l > 0) ? l - 1 : numberOfVolumePoints - 1; indexB0 = (l < numberOfVolumePoints - 2) ? l + 2 : l + 2 - numberOfVolumePoints; p0 = area.points[volume.points[indexA]].vector3; p1 = area.points[volume.points[indexB]].vector3; p00 = area.points[volume.points[indexA0]].vector3; p10 = area.points[volume.points[indexB0]].vector3; Vector3 facadeDirection = (p1 - p0).normalized; Vector3 facadeDirectionLeft = (p0 - p00).normalized; Vector3 facadeDirectionRight = (p10 - p1).normalized; Vector3 facadeNormal = Vector3.Cross(p1 - p0, Vector3.up).normalized; Vector3 facadeNormalLeft = Vector3.Cross(facadeDirectionLeft, Vector3.up); Vector3 facadeNormalRight = Vector3.Cross(facadeDirectionRight, Vector3.up); Vector3 leftDir = (facadeNormal + facadeNormalLeft).normalized; Vector3 rightDir = (facadeNormal + facadeNormalRight).normalized; float windowBottom = (design.height - design.dormerHeight) * design.dormerHeightRatio; float baseDepth = design.floorDepth; float cornerLeftRad = Vector3.Angle(facadeDirection, -facadeDirectionLeft) * Mathf.Deg2Rad / 2; float cornerRightRad = Vector3.Angle(-facadeDirection, facadeDirectionRight) * Mathf.Deg2Rad / 2; float cornerDepthLeft = baseDepth / Mathf.Sin(cornerLeftRad); float cornerDepthRight = baseDepth / Mathf.Sin(cornerRightRad); float topDepth = design.depth; float cornerTopDepthLeft = topDepth / Mathf.Sin(cornerLeftRad); float cornerTopDepthRight = topDepth / Mathf.Sin(cornerRightRad); float dormerDepth = design.depth * (design.dormerHeight / design.height); float windowBottomRat = Mathf.Lerp(0, 1 - design.dormerHeight / design.height, design.dormerHeightRatio); p0 += volumeFloorHeight + leftDir * cornerDepthLeft; p1 += volumeFloorHeight + rightDir * cornerDepthRight; float leftStartTopRad = Vector3.Angle(facadeDirectionLeft, facadeDirection) * Mathf.Deg2Rad * 0.5f; float leftStartMargin = cornerTopDepthLeft * Mathf.Sin(leftStartTopRad); float rightStartTopRad = Vector3.Angle(facadeDirection, facadeDirectionRight) * Mathf.Deg2Rad * 0.5f; float rightStartMargin = cornerTopDepthRight * Mathf.Sin(rightStartTopRad); Vector3 dormerStartPosition = leftDir * (windowBottomRat * cornerTopDepthLeft) + facadeDirection * (leftStartMargin); Vector3 dormerEndPosition = rightDir * (windowBottomRat * cornerTopDepthRight) - facadeDirection * (rightStartMargin + design.dormerWidth); float dormerPositionWidth = Vector3.Distance((p0 + dormerStartPosition), (p1 + dormerEndPosition)); int numberOfWindows = Mathf.FloorToInt((dormerPositionWidth) / (design.dormerWidth + design.minimumDormerSpacing)); float actualWindowSpacing = (dormerPositionWidth - (numberOfWindows * design.dormerWidth)) / (numberOfWindows + 1); numberOfWindows++;//add the final window Vector3 dormerWidthVector = facadeDirection * design.dormerWidth; Vector3 dormerHeightVectorA = Vector3.up * (design.dormerHeight - design.dormerRoofHeight); Vector3 dormerHeightVectorB = Vector3.up * design.dormerHeight; Vector3 dormerDepthVector = facadeNormal * dormerDepth; Vector3 dormerSpace = facadeDirection * (actualWindowSpacing + design.dormerWidth); Vector3 dormerSpacer = facadeDirection * (actualWindowSpacing); Vector3 dormerYPosition = Vector3.up * windowBottom; Vector3 w0, w1, w2, w3, w4, w5, w6, w7, w8, w9; for (int i = 0; i < numberOfWindows; i++) { w0 = p0 + dormerSpace * (i) + dormerStartPosition + dormerYPosition + dormerSpacer * 0.5f; w1 = w0 + dormerWidthVector; w2 = w0 + dormerHeightVectorA; w3 = w1 + dormerHeightVectorA; w4 = w0 + dormerWidthVector / 2 + dormerHeightVectorB; w5 = w0 + dormerDepthVector; w6 = w1 + dormerDepthVector; w7 = w2 + dormerDepthVector; w8 = w3 + dormerDepthVector; w9 = w4 + dormerDepthVector; int subMeshwindow = design.GetTexture(BuildrRoofDesign.textureNames.window); int subMeshwall = design.GetTexture(BuildrRoofDesign.textureNames.wall); int subMeshtiles = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flippedwall = design.IsFlipped(BuildrRoofDesign.textureNames.wall); bool flippedtiles = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, w1, w6, w3, w8, subMeshwall, flippedwall);//side AddPlane(design, w5, w0, w7, w2, subMeshwall, flippedwall);//side AddPlane(design, w3, w8, w4, w9, subMeshtiles, flippedtiles);//roof AddPlane(design, w7, w2, w9, w4, subMeshtiles, flippedtiles);//roof Vector3[] verts = new Vector3[5] { w0, w1, w2, w3, w4 }; float roofBottom = (design.dormerHeight - design.dormerRoofHeight) / design.dormerHeight; Vector2[] uvs = new Vector2[5]{ new Vector2(0,0), new Vector2(1,0), new Vector2(0,roofBottom), new Vector2(1,roofBottom), new Vector2(0.5f,1), }; int[] tris = new int[9] { 1, 0, 2, 1, 2, 3, 2, 4, 3 }; mesh.AddData(verts, uvs, tris, subMeshwindow); } } }
private static void Parapet(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int volumeIndex = area.volumes.IndexOf(volume); int numberOfVolumePoints = volume.points.Count; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); for (int l = 0; l < numberOfVolumePoints; l++) { int indexA, indexB, indexA0, indexB0; Vector3 p0, p1, p00, p10; indexA = l; indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0; indexA0 = (l > 0) ? l - 1 : numberOfVolumePoints - 1; indexB0 = (l < numberOfVolumePoints - 2) ? l + 2 : l + 2 - numberOfVolumePoints; int adjacentFloorHeight = area.GetFacadeFloorHeight(volumeIndex, volume.points[indexA], volume.points[indexB]); bool leftParapet = area.GetFacadeFloorHeight(volumeIndex, volume.points[indexA0], volume.points[indexA]) < numberOfFloors; bool rightParapet = area.GetFacadeFloorHeight(volumeIndex, volume.points[indexB], volume.points[indexB0]) < numberOfFloors; if (adjacentFloorHeight >= numberOfFloors) continue;//do not draw a roof edge p0 = area.points[volume.points[indexA]].vector3; p1 = area.points[volume.points[indexB]].vector3; p00 = area.points[volume.points[indexA0]].vector3; p10 = area.points[volume.points[indexB0]].vector3; float facadeWidth = Vector3.Distance(p0, p1); Vector3 facadeDirection = (p1 - p0).normalized; Vector3 facadeDirectionLeft = (p0 - p00).normalized; Vector3 facadeDirectionRight = (p10 - p1).normalized; Vector3 facadeNormal = Vector3.Cross(facadeDirection, Vector3.up); Vector3 facadeNormalLeft = Vector3.Cross(facadeDirectionLeft, Vector3.up); Vector3 facadeNormalRight = Vector3.Cross(facadeDirectionRight, Vector3.up); float parapetHeight = design.parapetHeight; float parapetFrontDepth = design.parapetFrontDepth; float parapetBackDepth = design.parapetBackDepth; Vector3 w0, w1, w2, w3, w4, w5, w6, w7; Vector3 pr = facadeDirection * facadeWidth; Vector3 pu = Vector3.up * parapetHeight; Vector3 pbdl, pbdr, pfdl, pfdr; if (leftParapet) { pbdl = -(facadeNormal + facadeNormalLeft).normalized * parapetFrontDepth; pfdl = (facadeNormal + facadeNormalLeft).normalized * parapetBackDepth; } else { pbdl = facadeDirectionLeft * parapetFrontDepth; pfdl = -facadeDirectionLeft * parapetBackDepth; } if (rightParapet) { pbdr = -(facadeNormal + facadeNormalRight).normalized * parapetFrontDepth; pfdr = (facadeNormal + facadeNormalRight).normalized * parapetBackDepth; } else { pbdr = -facadeDirectionRight * parapetFrontDepth; pfdr = facadeDirectionRight * parapetBackDepth; } p0 += volumeFloorHeight; p1 += volumeFloorHeight; w2 = p0 + pbdl;//front left w3 = p0 + pr + pbdr;//front right w0 = p0 + pfdl;//back left w1 = p0 + pr + pfdr;//back right w6 = p0 + pbdl + pu;//front left top w7 = p0 + pr + pbdr + pu;//front right top w4 = p0 + pfdl + pu;//back left top w5 = p0 + pr + pfdr + pu;//back right top int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.parapet); bool flipped = design.IsFlipped(BuildrRoofDesign.textureNames.parapet); AddPlane(design, w1, w0, w5, w4, subMesh, flipped);//front AddPlaneComplex(design, w6, w7, w4, w5, subMesh, flipped, facadeNormal);//top AddPlane(design, w2, w3, w6, w7, subMesh, flipped);//back if (parapetFrontDepth > 0) AddPlaneComplex(design, w3, w2, w1, w0, subMesh, flipped, facadeNormal);//bottom if (!leftParapet) AddPlane(design, w0, w2, w4, w6, subMesh, flipped);//left cap if (!rightParapet) AddPlane(design, w3, w1, w7, w5, subMesh, flipped);//left cap } }
private static void Gabled(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; Vector3[] basePoints = new Vector3[4]; if (design.direction == 0) { basePoints[0] = area.points[volume.points[0]].vector3 + volumeFloorHeight; basePoints[1] = area.points[volume.points[1]].vector3 + volumeFloorHeight; basePoints[2] = area.points[volume.points[2]].vector3 + volumeFloorHeight; basePoints[3] = area.points[volume.points[3]].vector3 + volumeFloorHeight; } else { basePoints[0] = area.points[volume.points[1]].vector3 + volumeFloorHeight; basePoints[1] = area.points[volume.points[2]].vector3 + volumeFloorHeight; basePoints[2] = area.points[volume.points[3]].vector3 + volumeFloorHeight; basePoints[3] = area.points[volume.points[0]].vector3 + volumeFloorHeight; } Vector3 centrePoint = Vector3.zero; for (int l = 0; l < 4; l++) centrePoint += area.points[volume.points[l]].vector3; centrePoint = (centrePoint / 4) + volumeFloorHeight + ridgeVector; Vector3 r0 = Vector3.Lerp(basePoints[0], basePoints[1], 0.5f) + ridgeVector; Vector3 r1 = Vector3.Lerp(basePoints[2], basePoints[3], 0.5f) + ridgeVector; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flipped = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, basePoints[0], r0, basePoints[3], r1, subMesh, flipped);//top AddPlane(design, basePoints[2], r1, basePoints[1], r0, subMesh, flipped);//top Vector3[] vertsA = new Vector3[3] { basePoints[0], basePoints[1], r0 }; Vector3[] vertsB = new Vector3[3] { basePoints[2], basePoints[3], r1 }; float uvWdithA = Vector3.Distance(basePoints[0], basePoints[1]); float uvWdithB = Vector3.Distance(basePoints[2], basePoints[3]); float uvHeight = design.height; subMesh = design.GetTexture(BuildrRoofDesign.textureNames.wall); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdithA *= (1.0f / texture.textureUnitSize.x); uvWdithB *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdithA = Mathf.Ceil(uvWdithA / uvunits.x) * uvunits.x; uvWdithB = Mathf.Ceil(uvWdithB / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdithA = texture.tiledX; uvWdithB = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvsA = new Vector2[3] { new Vector2(-uvWdithA / 2, 0), new Vector2(uvWdithA / 2, 0), new Vector2(0, uvHeight) }; Vector2[] uvsB = new Vector2[3] { new Vector2(-uvWdithB / 2, 0), new Vector2(uvWdithB / 2, 0), new Vector2(0, uvHeight) }; int[] tri = new int[3] { 1, 0, 2 }; AddData(vertsA, uvsA, tri, subMesh); AddData(vertsB, uvsB, tri, subMesh); }
private static void Hipped(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float baseHeight = data.floorHeight * numberOfFloors; float roofHeight = design.height; int numberOfVolumePoints = volume.points.Count; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.tiles); Vector2[] volumePoints = new Vector2[numberOfVolumePoints]; for(int i = 0; i < numberOfVolumePoints; i++) { volumePoints[i] = area.points[volume.points[i]].vector2; } Vector2[][] meshData = StraightSkeleton.Calculate(volumePoints); Vector2[] triData = meshData[0]; List<Vector2> interiorPoints = new List<Vector2>(meshData[1]); int numberOfVerts = triData.Length; Vector3[] verts = new Vector3[numberOfVerts]; Vector2[] uvs = new Vector2[numberOfVerts]; int[] tris = new int[numberOfVerts]; for(int i = 0; i < triData.Length; i+=3) { Vector2 pa = triData[i]; Vector2 pb = triData[i+1]; Vector2 pc = triData[i+2]; float ah = baseHeight + (interiorPoints.Contains(pa) ? roofHeight : 0); float bh = baseHeight + (interiorPoints.Contains(pb) ? roofHeight : 0); float ch = baseHeight + (interiorPoints.Contains(pc) ? roofHeight : 0); Vector3 v0 = new Vector3(pa.x, ah, pa.y); Vector3 v1 = new Vector3(pb.x, bh, pb.y); Vector3 v2 = new Vector3(pc.x, ch, pc.y); verts[i] = v0; verts[i+1] = v1; verts[i+2] = v2; Vector3 roofBaseDir = (interiorPoints.Contains(pc)) ? v1 - v0 : v2 - v1; Vector3 roofBaseNormal = Vector3.Cross(roofBaseDir, Vector3.up); Vector2[] uvsMansard = BuildrProjectUVs.Project(new Vector3[3] { v0, v1, v2 }, Vector2.zero, roofBaseNormal); uvs[i] = uvsMansard[0]; uvs[i + 1] = uvsMansard[1]; uvs[i + 2] = uvsMansard[2]; tris[i] = i; tris[i + 1] = i+2; tris[i + 2] = i+1; } AddData(verts,uvs,tris,subMesh); /*Vector3 ridgeVector = Vector3.up * design.height; Vector3[] basePoints = new Vector3[4]; if (design.direction == 0) { basePoints[0] = area.points[volume.points[0]].vector3 + volumeFloorHeight; basePoints[1] = area.points[volume.points[1]].vector3 + volumeFloorHeight; basePoints[2] = area.points[volume.points[2]].vector3 + volumeFloorHeight; basePoints[3] = area.points[volume.points[3]].vector3 + volumeFloorHeight; } else { basePoints[0] = area.points[volume.points[1]].vector3 + volumeFloorHeight; basePoints[1] = area.points[volume.points[2]].vector3 + volumeFloorHeight; basePoints[2] = area.points[volume.points[3]].vector3 + volumeFloorHeight; basePoints[3] = area.points[volume.points[0]].vector3 + volumeFloorHeight; } Vector3 centrePoint = Vector3.zero; for (int l = 0; l < 4; l++) centrePoint += area.points[volume.points[l]].vector3; centrePoint = (centrePoint / 4) + volumeFloorHeight + ridgeVector; Vector3 r0 = Vector3.Lerp(basePoints[0], basePoints[1], 0.5f) + ridgeVector; Vector3 r1 = Vector3.Lerp(basePoints[2], basePoints[3], 0.5f) + ridgeVector; Vector3 ridgeDirection = (r1 - r0); float roofLength = Vector3.Distance(r0, r1); float ridgeLengthA = Vector3.Distance(basePoints[0], basePoints[1]); if (ridgeLengthA > roofLength) ridgeLengthA = roofLength; float ridgeLengthB = Vector3.Distance(basePoints[2], basePoints[3]); if (ridgeLengthB > roofLength) ridgeLengthB = roofLength; r0 += ridgeDirection.normalized * ridgeLengthA / 2; r1 += -ridgeDirection.normalized * ridgeLengthB / 2; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flipped = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, basePoints[0], r0, basePoints[3], r1, subMesh, flipped);//top AddPlane(design, basePoints[2], r1, basePoints[1], r0, subMesh, flipped);//top Vector3[] vertsA = new Vector3[3] { basePoints[0], basePoints[1], r0 }; Vector3[] vertsB = new Vector3[3] { basePoints[2], basePoints[3], r1 }; float uvWdithA = Vector3.Distance(basePoints[0], basePoints[1]); float uvWdithB = Vector3.Distance(basePoints[2], basePoints[3]); float uvHeight = design.height; BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdithA *= (1.0f / texture.textureUnitSize.x); uvWdithB *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdithA = Mathf.Ceil(uvWdithA / uvunits.x) * uvunits.x; uvWdithB = Mathf.Ceil(uvWdithB / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdithA = texture.tiledX; uvWdithB = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvsA = new Vector2[3] { new Vector2(-uvWdithA / 2, 0), new Vector2(uvWdithA / 2, 0), new Vector2(0, uvHeight) }; Vector2[] uvsB = new Vector2[3] { new Vector2(-uvWdithB / 2, 0), new Vector2(uvWdithB / 2, 0), new Vector2(0, uvHeight) }; int[] tri = new int[3] { 1, 0, 2 }; AddData(vertsA, uvsA, tri, subMesh); AddData(vertsB, uvsB, tri, subMesh);*/ }
public static void InspectorGUI(BuildrEditMode editMode, BuildrData data) { BuildrDetail[] details = data.details.ToArray(); int numberOfDetails = details.Length; selectedDetail = Mathf.Clamp(selectedDetail, 0, numberOfDetails - 1); if (numberOfDetails == 0) { EditorGUILayout.HelpBox("There are no details to show", MessageType.Info); if (GUILayout.Button("Add New")) { data.details.Add(new BuildrDetail("new detail " + numberOfDetails)); numberOfDetails++; selectedDetail = numberOfDetails - 1; } return; } EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Detail", GUILayout.Width(75)); string[] detailNames = new string[numberOfDetails]; for (int t = 0; t < numberOfDetails; t++) { detailNames[t] = details[t].name; } selectedDetail = EditorGUILayout.Popup(selectedDetail, detailNames); EditorGUILayout.EndHorizontal(); BuildrDetail bDetail = details[selectedDetail]; EditorGUILayout.BeginHorizontal(); EditorGUILayout.Space(); if (GUILayout.Button("Add New", GUILayout.Width(81))) { data.details.Add(new BuildrDetail("new detail " + numberOfDetails)); numberOfDetails++; selectedDetail = numberOfDetails - 1; } if (GUILayout.Button("Duplicate", GUILayout.Width(90))) { data.details.Add(bDetail.Duplicate()); numberOfDetails++; selectedDetail = numberOfDetails - 1; } if (GUILayout.Button("Delete", GUILayout.Width(71))) { if (EditorUtility.DisplayDialog("Deleting Building Detail Entry", "Are you sure you want to delete this detail?", "Delete", "Cancel")) { data.details.Remove(bDetail); selectedDetail = 0; GUI.changed = true; return; } } EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); details = data.details.ToArray(); detailNames = new string[numberOfDetails]; for (int t = 0; t < numberOfDetails; t++) { detailNames[t] = details[t].name; } bDetail = details[selectedDetail];//reassign EditorGUILayout.BeginHorizontal(); EditorGUILayout.BeginVertical(); bDetail.name = EditorGUILayout.TextField("Name", bDetail.name); bDetail.mesh = (Mesh)EditorGUILayout.ObjectField("Mesh", bDetail.mesh, typeof(Mesh), false); EditorGUIUtility.LookLikeControls(); bDetail.material.mainTexture = (Texture)EditorGUILayout.ObjectField("Texture", bDetail.material.mainTexture, typeof(Texture), false, GUILayout.Height(140)); if (bDetail.material.mainTexture != null) { string texturePath = AssetDatabase.GetAssetPath(bDetail.material.mainTexture); TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath); if (!textureImporter.isReadable) { EditorGUILayout.HelpBox("The texture you have selected is not readable." + "\nPlease select the readable checkbox under advanced texture settings." + "\nOr move this texture to the BuildR texture folder and reimport.", MessageType.Error); } } BuildrPlan plan = data.plan; int numberOfVolumes = plan.numberOfVolumes; int numberOfFaces = 0; List <int> faceSeletionsList = new List <int>(); List <string> faceSeletionsStringList = new List <string>(); if (bDetail.type == BuildrDetail.Types.Facade) { for (int s = 0; s < numberOfVolumes; s++) { int numberOfPoints = plan.volumes[s].Count; numberOfFaces += numberOfPoints; for (int p = 0; p < numberOfPoints; p++) { int index = faceSeletionsList.Count; faceSeletionsStringList.Add("facade " + index); faceSeletionsList.Add(index); } } } else { bDetail.face = Mathf.Clamp(0, numberOfVolumes - 1, bDetail.face); for (int s = 0; s < numberOfVolumes; s++) { int index = faceSeletionsList.Count; faceSeletionsStringList.Add("roof " + index); faceSeletionsList.Add(index); } } if (!clickPlace) { if (GUILayout.Button("Place Detail with Mouse")) { clickPlace = true; } } else { if (GUILayout.Button("Cancel Place Detail")) { clickPlace = false; } } BuildrDetail.Types bDetailtype = (BuildrDetail.Types)EditorGUILayout.EnumPopup("Face Type", bDetail.type); if (bDetailtype != bDetail.type) { bDetail.type = bDetailtype; } int[] faceSelections = faceSeletionsList.ToArray(); string[] faceSelectionString = faceSeletionsStringList.ToArray(); int bDetailface = EditorGUILayout.IntPopup("Selected Face", bDetail.face, faceSelectionString, faceSelections); if (bDetailface != bDetail.face) { bDetail.face = bDetailface; } Vector2 bDetailfaceUv = EditorGUILayout.Vector2Field("Face UV", bDetail.faceUv); if (bDetailfaceUv != bDetail.faceUv) { bDetail.faceUv = bDetailfaceUv; } float bDetailfaceHeight = EditorGUILayout.FloatField("Face Height", bDetail.faceHeight); if (bDetailfaceHeight != bDetail.faceHeight) { bDetail.faceHeight = bDetailfaceHeight; } Vector3 bDetailuserRotation = EditorGUILayout.Vector3Field("Rotation", bDetail.userRotation); if (bDetailuserRotation != bDetail.userRotation) { bDetail.userRotation = bDetailuserRotation; } Vector3 bDetailscale = EditorGUILayout.Vector3Field("Object Scale", bDetail.scale); if (bDetailscale != bDetail.scale) { bDetail.scale = bDetailscale; } EditorGUILayout.EndVertical(); EditorGUILayout.BeginVertical(GUILayout.Width(120)); if (bDetail.mesh != null) { Texture2D previewMeshImage = AssetPreview.GetAssetPreview(bDetail.mesh); GUILayout.Label(previewMeshImage); } else { Texture2D previewMeshImage = new Texture2D(118, 118); GUILayout.Label(previewMeshImage); GUILayout.Label("No Mesh Selected"); } if (bDetail.material.mainTexture != null) { Texture previewMeshImage = bDetail.material.mainTexture; GUILayout.Label(previewMeshImage, GUILayout.Width(128), GUILayout.Height(128)); } else { Texture2D previewMeshImage = new Texture2D(118, 118); GUILayout.Label(previewMeshImage); GUILayout.Label("No Texture Selected"); } EditorGUILayout.EndVertical(); EditorGUILayout.EndHorizontal(); }
public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, bool ignoreParapets) { data = _data; mesh = _mesh; textures = data.textures.ToArray(); BuildrPlan plan = data.plan; int numberOfVolumes = data.plan.numberOfVolumes; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; BuildrRoofDesign design = data.roofs[volume.roofDesignID]; BuildrRoofDesign.styles style = design.style; if (volume.points.Count != 4) if (design.style == BuildrRoofDesign.styles.leanto || design.style == BuildrRoofDesign.styles.sawtooth || design.style == BuildrRoofDesign.styles.barrel) style = BuildrRoofDesign.styles.flat;//ignore style and just do a flat roof if (volume.points.Count != 4 && design.style == BuildrRoofDesign.styles.gabled) style = BuildrRoofDesign.styles.hipped;//ignore style and just do a hipped roof switch (style) { case BuildrRoofDesign.styles.flat: FlatRoof(volume, design); break; case BuildrRoofDesign.styles.mansard: Mansard(volume, design); if (design.hasDormers) Dormers(volume, design); break; case BuildrRoofDesign.styles.gabled: Gabled(volume, design); break; case BuildrRoofDesign.styles.hipped: Hipped(volume, design); break; case BuildrRoofDesign.styles.leanto: LeanTo(volume, design); break; case BuildrRoofDesign.styles.sawtooth: Sawtooth(volume, design); break; case BuildrRoofDesign.styles.barrel: Barrel(volume, design); break; case BuildrRoofDesign.styles.steepled: Steeple(volume, design); break; } if (design.parapet && !ignoreParapets) Parapet(volume, design); } data = null; mesh = null; textures = null; }
public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex) { data = _data; mesh = _mesh; mesh.name = "Interior Mesh Volume " + volumeIndex; textures = data.textures.ToArray(); if (!data.renderInteriors) { return; } float largestDepthValue = 0;//deepest value of a bay design in the building float tallestBay = 0; foreach (BuildrBay bay in data.bays) { largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value tallestBay = Mathf.Max(tallestBay, bay.openingHeight + (data.floorHeight - bay.openingHeight) * bay.openingHeightRatio); } foreach (BuildrFacadeDesign facade in data.facades) { if (facade.type != BuildrFacadeDesign.types.simple) { continue; } largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value if (facade.simpleBay.isOpening) { tallestBay = Mathf.Max(tallestBay, facade.simpleBay.openingHeight + (data.floorHeight - facade.simpleBay.openingHeight) * facade.simpleBay.openingHeightRatio); } } BuildrFacadeDesign facadeDesign = data.facades[0]; BuildrPlan plan = data.plan; BuildrVolume volume = plan.volumes[volumeIndex]; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 floorHeightVector = Vector3.up * floorHeight; float ceilingHeight = tallestBay + (floorHeight - tallestBay) * data.interiorCeilingHeight; //Calculate the internal floor plan points int numberOfVolumePoints = volume.points.Count; Vector2z[] interiorVolumePoints = new Vector2z[numberOfVolumePoints]; for (int i = 0; i < numberOfVolumePoints; i++) { Vector3 lastPoint = plan.points[volume.points[(i > 0) ? i - 1 : numberOfVolumePoints - 1]].vector3; Vector3 thisPoint = plan.points[volume.points[i]].vector3; Vector3 nextPoint = plan.points[volume.points[(i + 1) % numberOfVolumePoints]].vector3; Vector3 normalA = Vector3.Cross(thisPoint - lastPoint, Vector3.up).normalized; Vector3 normalB = Vector3.Cross(nextPoint - thisPoint, Vector3.up).normalized; Vector2z facadeALine = new Vector2z(thisPoint - lastPoint); Vector2z facadeBLine = new Vector2z(thisPoint - nextPoint); //Calculate facade inner origins for floors Vector3 facadeOriginV3A = lastPoint + normalA * largestDepthValue; Vector3 facadeOriginV3B = nextPoint + normalB * largestDepthValue; Vector2z facadeOriginA = new Vector2z(facadeOriginV3A); Vector2z facadeOriginB = new Vector2z(facadeOriginV3B); Vector2z facadeLineIntersection = BuildrUtils.FindIntersection(facadeALine, facadeOriginA, facadeBLine, facadeOriginB); interiorVolumePoints[i] = facadeLineIntersection; } List <Vector2z> interiorVolumePointList = new List <Vector2z>(interiorVolumePoints); List <Rect> volumeCores = new List <Rect>(); List <int> linkedPoints = new List <int>(); foreach (Rect core in plan.cores) { Vector2z coreCenter = new Vector2z(core.center); if (BuildrUtils.PointInsidePoly(coreCenter, interiorVolumePoints)) { volumeCores.Add(core); } } int numberOfVolumeCores = volumeCores.Count; bool print = plan.volumes.IndexOf(volume) == 3; for (int c = 0; c < numberOfVolumeCores; c++) { int numberOfInteriorPoints = interiorVolumePointList.Count; Rect coreBounds = volumeCores[c]; Vector2z coreCenter = new Vector2z(coreBounds.center); Vector2z coreBL = new Vector2z(coreBounds.xMin, coreBounds.yMin); Vector2z coreBR = new Vector2z(coreBounds.xMax, coreBounds.yMin); Vector2z coreTL = new Vector2z(coreBounds.xMin, coreBounds.yMax); Vector2z coreTR = new Vector2z(coreBounds.xMax, coreBounds.yMax); Vector2z[] corePointArray; corePointArray = new[] { coreBL, coreBR, coreTR, coreTL }; //Find the nearest legal cut we can make to join the core and interior point poly int connectingPoint = -1; float connectingPointDistance = Mathf.Infinity; for (int p = 0; p < numberOfInteriorPoints; p++) { if (linkedPoints.Contains(p)) { continue; } Vector2z thisPoint = interiorVolumePointList[p]; float thisPointDistance = Vector2z.SqrMag(thisPoint, coreCenter); if (thisPointDistance < connectingPointDistance) { bool legalCut = true; for (int pc = 0; pc < numberOfInteriorPoints; pc++) { Vector2z p0 = interiorVolumePointList[pc]; Vector2z p1 = interiorVolumePointList[(pc + 1) % numberOfInteriorPoints]; if (BuildrUtils.FastLineIntersection(coreCenter, thisPoint, p0, p1))//check against all lines that this new cut doesn't intersect { if (print) { Debug.Log("FLI " + pc + " " + coreCenter + " " + thisPoint + " " + p0 + " " + p1); } legalCut = false; break; } } if (legalCut) { connectingPoint = p; connectingPointDistance = thisPointDistance; } } } if (connectingPoint == -1) { Debug.Log("Buildr Could not place core"); continue; } Vector2z chosenPoint = interiorVolumePointList[connectingPoint]; int connectingCorePoint = 0; float connectingCorePointDistance = Mathf.Infinity; // Vector2z.SqrMag(corePointArray[0], chosenPoint); for (int cp = 0; cp < 4; cp++) //find the core point to make the cut { float thisCorePointDistance = Vector2z.SqrMag(corePointArray[cp], chosenPoint); if (thisCorePointDistance < connectingCorePointDistance) { connectingCorePoint = cp; connectingCorePointDistance = thisCorePointDistance; } } interiorVolumePointList.Insert(connectingPoint, chosenPoint); //loop back on the floorplan to close it for (int acp = 0; acp < 5; acp++) //loop back on itself to close the core { interiorVolumePointList.Insert(connectingPoint + 1, corePointArray[(connectingCorePoint + acp) % 4]); } for (int i = 0; i < linkedPoints.Count; i++) { if (linkedPoints[i] > connectingPoint) { linkedPoints[i] += 7; } } linkedPoints.AddRange(new[] { connectingPoint, connectingPoint + 1, connectingPoint + 2, connectingPoint + 3, connectingPoint + 4, connectingPoint + 5, connectingPoint + 6 }); // linkedPoints.AddRange(new []{connectingPoint,connectingPoint+6}); } // if(linkedPoints.Count > 0) // Debug.Log(linkedPoints.Count+" "+linkedPoints[0]); Vector2z[] interiorPointListCore = interiorVolumePointList.ToArray(); for (int f = 0; f < numberOfVolumePoints; f++) { ///WALLS int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints); int indexA = f; int indexB = (f + 1) % numberOfVolumePoints; int indexBP = (f + 2) % numberOfVolumePoints; Vector3 p0m = plan.points[volume.points[indexAM]].vector3; Vector3 p0 = plan.points[volume.points[indexA]].vector3; Vector3 p1 = plan.points[volume.points[indexB]].vector3; Vector3 p1p = plan.points[volume.points[indexBP]].vector3; Vector3 p0interior = interiorVolumePoints[indexA].vector3; Vector3 p1interior = interiorVolumePoints[indexB].vector3; float facadeWidth = Vector3.Distance(p0, p1) - largestDepthValue * 2.0f; Vector3 facadeDirection = (p1 - p0).normalized; Vector3 facadeCross = Vector3.Cross(facadeDirection, Vector3.up); Vector3 lastFacadeDirection = (p0 - p0m).normalized; Vector3 nextFacadeDirection = (p1p - p1).normalized; //only bother with facade directions when facade may intersect inverted geometry float facadeDirDotL = Vector3.Dot(-facadeDirection, lastFacadeDirection); float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection); if (facadeDirDotL <= 0 || facadeCrossDotL <= 0) { lastFacadeDirection = -facadeCross; } float facadeDirDotN = Vector3.Dot(-facadeDirection, nextFacadeDirection); float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection); if (facadeDirDotN <= 0 || facadeCrossDotN <= 0) { nextFacadeDirection = facadeCross; } int floorBase = plan.GetFacadeFloorHeight(volumeIndex, volume.points[indexA], volume.points[indexB]); BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]); int floorPatternSize = 0; List <int> facadePatternReference = new List <int>(); //this contains a list of all the facade style indices to refence when looking for the appropriate style per floor int patternCount = 0; foreach (BuildrVolumeStylesUnit styleUnit in styleUnits) //need to knw how big all the styles are together so we can loop through them { floorPatternSize += styleUnit.floors; for (int i = 0; i < styleUnit.floors; i++) { facadePatternReference.Add(patternCount); } patternCount++; } facadePatternReference.Reverse(); int rows = numberOfFloors; Vector2 facadeUV = Vector2.zero; for (int r = 0; r < rows; r++) { float currentFloorHeight = floorHeight * r; Vector3 currentFloorHeightVector = Vector3.up * (data.floorHeight * r); Vector3 facadeFloorBaseVector = p0 + Vector3.up * currentFloorHeight; Vector3 ceilingVector = Vector3.up * ceilingHeight; if (r < floorBase) { //no facade rendered //facade gap filler //interior gap points Vector3 i0 = p1 - facadeDirection.normalized * largestDepthValue; Vector3 i1 = p0 + facadeDirection.normalized * largestDepthValue; Vector3 w0 = i0 + currentFloorHeightVector; Vector3 w1 = i1 + currentFloorHeightVector; Vector3 w2 = w0 + facadeCross * largestDepthValue; Vector3 w3 = w1 + facadeCross * largestDepthValue; Vector3 w4 = w0 + ceilingVector; Vector3 w5 = w1 + ceilingVector; Vector3 w6 = w2 + ceilingVector; Vector3 w7 = w3 + ceilingVector; Vector3 w8 = p1interior + currentFloorHeightVector; Vector3 w9 = p0interior + currentFloorHeightVector; Vector3 w10 = w8 + ceilingVector; Vector3 w11 = w9 + ceilingVector; //floor AddData(new[] { w0, w1, w2, w3 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.FloorTexture(r), false); //ceiling AddData(new[] { w5, w4, w7, w6 }, new[] { 0, 1, 2, 1, 3, 2 }, volume.CeilingTexture(r), false); //sides int wallSubmesh = volume.WallTexture(r); AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight)); AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector3.zero, new Vector2(largestDepthValue, floorHeight)); //other gaps float uvWidth1 = Vector3.Distance(w2, w8); AddPlane(w2, w8, w6, w10, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth1, floorHeight)); float uvWidth2 = Vector3.Distance(w3, w9); AddPlane(w9, w3, w11, w7, wallSubmesh, false, Vector3.zero, new Vector2(uvWidth2, floorHeight)); continue; } //Get the facade style id //need to loop through the facade designs floor by floor until we get to the right one int modFloor = ((r - floorBase) % floorPatternSize); facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID]; bool isBlankWall = !facadeDesign.hasWindows; if (facadeDesign.type == BuildrFacadeDesign.types.patterned) { if (data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0) { data.illegal = true; return; } BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]]; if (firstBay.openingWidth > facadeWidth) { isBlankWall = true; } if (facadeDesign.bayPattern.Count == 0) { isBlankWall = true; } } else { if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth) { isBlankWall = true; } } if (!isBlankWall) { float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles int numberOfBays = 0; BuildrBay[] bayDesignPattern; int numberOfBayDesigns; if (facadeDesign.type == BuildrFacadeDesign.types.patterned) { numberOfBayDesigns = facadeDesign.bayPattern.Count; bayDesignPattern = new BuildrBay[numberOfBayDesigns]; for (int i = 0; i < numberOfBayDesigns; i++) { bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]]; } } else { bayDesignPattern = new[] { facadeDesign.simpleBay }; numberOfBayDesigns = 1; } //start with first window width - we'll be adding to this until we have filled the facade width int it = 100; while (true) { int patternModIndex = numberOfBays % numberOfBayDesigns; float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth; if (patternSize + patternAddition < facadeWidth) { patternSize += patternAddition; numberOfBays++; } else { break; } it--; if (it < 0) { break; } } Vector3 windowBase = facadeFloorBaseVector; facadeUV.x = 0; facadeUV.y += floorHeight; float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays; for (int c = 0; c < numberOfBays; c++) { BuildrBay bayStyle; BuildrBay lastBay; BuildrBay nextBay; bool firstColumn = c == 0; bool lastColumn = c == numberOfBays - 1; if (facadeDesign.type == BuildrFacadeDesign.types.patterned) { int numberOfBayStyles = facadeDesign.bayPattern.Count; bayStyle = bayDesignPattern[c % numberOfBayStyles]; int lastBayIndex = (c > 0) ? (c - 1) % numberOfBayStyles : 0; lastBay = bayDesignPattern[lastBayIndex]; nextBay = bayDesignPattern[(c + 1) % numberOfBayStyles]; } else { bayStyle = facadeDesign.simpleBay; lastBay = facadeDesign.simpleBay; nextBay = facadeDesign.simpleBay; } float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing; float leftWidth = actualWindowSpacing * bayStyle.openingWidthRatio; float rightWidth = actualWindowSpacing - leftWidth; float openingWidth = bayStyle.openingWidth; if (firstColumn) { leftWidth += largestDepthValue; } if (lastColumn) { rightWidth += largestDepthValue; } BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)]; Vector2 columnuvunits = columnTexture.tileUnitUV; float openingHeight = bayStyle.openingHeight; if (columnTexture.patterned) { openingHeight = Mathf.Ceil(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y; } if (bayStyle.openingHeight == floorHeight) { bayStyle.openingHeight = floorHeight; } float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio); if (columnTexture.patterned) { rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y; } float rowTopHeight = (floorHeight - rowBottomHeight - openingHeight); bool previousBayIdentical = bayStyle == lastBay; bool nextBayIdentical = bayStyle == nextBay; if (previousBayIdentical && !firstColumn) { leftWidth = actualWindowSpacing;//if next design is identical - add the two parts together the reduce polycount } Vector3 w0, w1, w2, w3; int wallSubmesh = volume.WallTexture(r); bool wallFlipped = false; if (!bayStyle.isOpening) { float bayWidthSize = openingWidth + actualWindowSpacing; if (firstColumn || lastColumn) { bayWidthSize += largestDepthValue; } Vector3 bayWidth = facadeDirection * bayWidthSize; Vector3 bayHeight = Vector3.up * floorHeight; Vector3 bayDepth = facadeCross * largestDepthValue; w0 = windowBase + bayDepth; w1 = windowBase + bayWidth + bayDepth; w2 = windowBase + bayHeight + bayDepth; w3 = windowBase + bayWidth + bayHeight + bayDepth; Vector2 bayOpeningUVEnd = facadeUV + new Vector2(openingWidth + actualWindowSpacing, floorHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, facadeUV, bayOpeningUVEnd); windowBase = windowBase + bayWidth; //move base vertor to next bay facadeUV.x += openingWidth + actualWindowSpacing; continue; //bay filled - move onto next bay } var verts = new Vector3[16]; verts[0] = windowBase; verts[1] = verts[0] + leftWidth * facadeDirection; verts[2] = verts[1] + openingWidth * facadeDirection; verts[3] = verts[2] + rightWidth * facadeDirection; windowBase = (nextBayIdentical) ? verts[2] : verts[3];//move to next window - if next design is identical - well add the two parts together the reduce polycount facadeUV.x += (nextBayIdentical) ? openingWidth : openingWidth + rightWidth; Vector3 rowBottomVector = Vector3.up * rowBottomHeight; verts[4] = verts[0] + rowBottomVector; verts[5] = verts[1] + rowBottomVector; verts[6] = verts[2] + rowBottomVector; verts[7] = verts[3] + rowBottomVector; Vector3 openingVector = Vector3.up * openingHeight; verts[8] = verts[4] + openingVector; verts[9] = verts[5] + openingVector; verts[10] = verts[6] + openingVector; verts[11] = verts[7] + openingVector; Vector3 rowTopVector = Vector3.up * rowTopHeight; verts[12] = verts[8] + rowTopVector; verts[13] = verts[9] + rowTopVector; verts[14] = verts[10] + rowTopVector; verts[15] = verts[11] + rowTopVector; //Realign facade end points if (firstColumn) { verts[0] = p0interior - facadeCross * largestDepthValue + currentFloorHeightVector; verts[4] = verts[0] + rowBottomVector; verts[8] = verts[4] + openingVector; verts[12] = verts[8] + rowTopVector; } if (lastColumn) { verts[3] = p1interior - facadeCross * largestDepthValue + currentFloorHeightVector; verts[7] = verts[3] + rowBottomVector; verts[11] = verts[7] + openingVector; verts[15] = verts[11] + rowTopVector; } Vector3 openingDepthVector = facadeCross * bayStyle.openingDepth; Vector3 wallDepthVecotr = facadeCross * largestDepthValue; ///WINDOWS int windowSubmesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture); bool windowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture); w0 = verts[10] + openingDepthVector; w1 = verts[9] + openingDepthVector; w2 = verts[6] + openingDepthVector; w3 = verts[5] + openingDepthVector; Vector2 windowUVStart = new Vector2(0, 0); Vector2 windowUVEnd = new Vector2(openingWidth, openingHeight); if (bayStyle.renderBack && !data.cullBays) { AddPlane(w0, w1, w2, w3, windowSubmesh, windowFlipped, windowUVStart, windowUVEnd); } ///COLUMNS //Column Face if (leftWidth > 0)//Column Face Left { w0 = verts[4] + wallDepthVecotr; w1 = verts[5] + wallDepthVecotr; w2 = verts[8] + wallDepthVecotr; w3 = verts[9] + wallDepthVecotr; Vector2 leftColumnUVStart = facadeUV + new Vector2(0, rowBottomHeight); Vector2 leftColumnUVEnd = leftColumnUVStart + new Vector2(leftWidth, openingHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, leftColumnUVStart, leftColumnUVEnd); } if ((!nextBayIdentical || lastColumn) && rightWidth > 0)//Column Right { w0 = verts[6] + wallDepthVecotr; w1 = verts[7] + wallDepthVecotr; w2 = verts[10] + wallDepthVecotr; w3 = verts[11] + wallDepthVecotr; Vector2 rightColumnUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight); Vector2 rightColumnUVEnd = rightColumnUVStart + new Vector2(rightWidth, openingHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, rightColumnUVStart, rightColumnUVEnd); } ///ROWS //Row Bottom if (rowBottomHeight > 0) { w0 = verts[1] + wallDepthVecotr; w1 = verts[2] + wallDepthVecotr; w2 = verts[5] + wallDepthVecotr; w3 = verts[6] + wallDepthVecotr; Vector2 bottomRowUVStart = facadeUV + new Vector2(leftWidth, 0); Vector2 bottomRowUVEnd = bottomRowUVStart + new Vector2(openingWidth, rowBottomHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, bottomRowUVStart, bottomRowUVEnd); } //Row Top if (rowTopHeight > 0) { w0 = verts[9] + wallDepthVecotr; w1 = verts[10] + wallDepthVecotr; w2 = verts[13] + wallDepthVecotr; w3 = verts[14] + wallDepthVecotr; Vector2 topRowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight + openingHeight); Vector2 topRowUVEnd = topRowUVStart + new Vector2(openingWidth, rowTopHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, topRowUVStart, topRowUVEnd); } //Cross Left Bottom w0 = verts[0] + wallDepthVecotr; w1 = verts[1] + wallDepthVecotr; w2 = verts[4] + wallDepthVecotr; w3 = verts[5] + wallDepthVecotr; Vector2 crossLBUVStart = facadeUV + new Vector2(0, 0); Vector2 crossLBUVEnd = crossLBUVStart + new Vector2(leftWidth, rowBottomHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLBUVStart, crossLBUVEnd); //Cross Left Top w0 = verts[8] + wallDepthVecotr; w1 = verts[9] + wallDepthVecotr; w2 = verts[12] + wallDepthVecotr; w3 = verts[13] + wallDepthVecotr; Vector2 crossLTUVStart = facadeUV + new Vector2(0, rowBottomHeight + openingHeight); Vector2 crossLTUVEnd = crossLTUVStart + new Vector2(leftWidth, rowTopHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossLTUVStart, crossLTUVEnd); if ((!nextBayIdentical || lastColumn) && rightWidth > 0) { //Cross Right Bottom w0 = verts[2] + wallDepthVecotr; w1 = verts[3] + wallDepthVecotr; w2 = verts[6] + wallDepthVecotr; w3 = verts[7] + wallDepthVecotr; Vector2 crossRBUVStart = facadeUV + new Vector2(leftWidth + openingWidth, 0); Vector2 crossRBUVEnd = crossRBUVStart + new Vector2(rightWidth, rowBottomHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRBUVStart, crossRBUVEnd); //Cross Right Top w0 = verts[10] + wallDepthVecotr; w1 = verts[11] + wallDepthVecotr; w2 = verts[14] + wallDepthVecotr; w3 = verts[15] + wallDepthVecotr; Vector2 crossRTUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight + openingHeight); Vector2 crossRTUVEnd = crossRTUVStart + new Vector2(rightWidth, rowTopHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, wallFlipped, crossRTUVStart, crossRTUVEnd); } } } else { // windowless wall Vector3 interiorStart = p0interior + currentFloorHeightVector; Vector3 interiorEnd = p1interior + currentFloorHeightVector; // Vector3 wallVector = (facadeDirection * facadeWidth); Vector3 wallHeightVector = Vector3.up * floorHeight; Vector3 w0 = interiorStart; Vector3 w1 = interiorEnd; Vector3 w2 = interiorStart + wallHeightVector; Vector3 w3 = interiorEnd + wallHeightVector; BuildrTexture texture = textures[facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture)]; var uvSize = new Vector2(facadeWidth * (1.0f / texture.textureUnitSize.x), floorHeight * (1.0f / texture.textureUnitSize.y)); Vector2 uvunits = texture.tileUnitUV; uvSize.x = Mathf.Ceil(uvSize.x / uvunits.x) * uvunits.x; uvSize.y = Mathf.Ceil(uvSize.y / uvunits.y) * uvunits.y; int wallSubmesh = 0; bool flipped = false; Vector2 wallUVStart = facadeUV; Vector2 wallUVEnd = facadeUV + new Vector2(facadeWidth, floorHeight); AddPlane(w0, w1, w2, w3, wallSubmesh, flipped, wallUVStart, wallUVEnd); } } } ///FLOORS AND CEILING int numberOfBasements = volume.numberOfBasementFloors; int numberOfFloorPoints = interiorVolumePoints.Length; int[] baseFloorPlanTriangles = EarClipper.Triangulate(interiorVolumePoints); int baseFloorVectors = interiorVolumePoints.Length; var newEndVerts = new Vector3[baseFloorVectors]; Vector3 basementBaseDrop = -floorHeightVector * numberOfBasements; for (int i = 0; i < baseFloorVectors; i++) { newEndVerts[i] = interiorVolumePoints[i].vector3 + basementBaseDrop; } var tris = new List <int>(baseFloorPlanTriangles); //Bottom Floor int floorSubmesh = volume.FloorTexture(-numberOfBasements); AddData(newEndVerts, baseFloorPlanTriangles, floorSubmesh, false); //Top Ceiling if (true)//Todo: add conditional for roof opening { Vector3 ceilingHeightVector = floorHeightVector * (numberOfFloors - 1 + numberOfBasements) + Vector3.up * ceilingHeight; for (int i = 0; i < baseFloorVectors; i++) { newEndVerts[i] += ceilingHeightVector; } tris.Reverse(); AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(numberOfFloors - 1), false); } //inner floors int[] floorPlanTriangles = EarClipper.Triangulate(interiorPointListCore); int numberOfFloorVectors = interiorPointListCore.Length; for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors; floorIndex++) { Vector3 floorVectorHeight = floorHeightVector * floorIndex; newEndVerts = new Vector3[numberOfFloorVectors]; for (int i = 0; i < numberOfFloorVectors; i++) { newEndVerts[i] = interiorPointListCore[i].vector3 + floorVectorHeight; } tris = new List <int>(floorPlanTriangles); //Floor if (floorIndex > -numberOfBasements) { AddData(newEndVerts, tris.ToArray(), volume.FloorTexture(floorIndex), false); } //Ceiling if (floorIndex < numberOfFloors - 1) { Vector3 ceilingHeightVector = Vector3.up * ceilingHeight; for (int i = 0; i < numberOfFloorVectors; i++) { newEndVerts[i] += ceilingHeightVector; } tris.Reverse(); AddData(newEndVerts, tris.ToArray(), volume.CeilingTexture(floorIndex), false); } //basement walls if (floorIndex < 0) { for (int f = 0; f < numberOfFloorPoints; f++) { Vector3 basementVector = floorHeightVector * floorIndex; int indexA = f; int indexB = (f + 1) % numberOfFloorPoints; Vector3 p0 = interiorVolumePoints[indexA].vector3 + basementVector; Vector3 p1 = interiorVolumePoints[indexB].vector3 + basementVector; Vector3 p2 = p0 + floorHeightVector; Vector3 p3 = p1 + floorHeightVector; Vector2 uv1 = new Vector2(Vector3.Distance(p0, p1), floorHeight); AddPlane(p0, p1, p2, p3, volume.WallTexture(floorIndex), false, Vector2.zero, uv1); } } } //Core walls for (int c = 0; c < numberOfVolumeCores; c++) { Rect coreBounds = volumeCores[c]; Vector3 coreBL = new Vector3(coreBounds.xMin, 0, coreBounds.yMin); Vector3 coreBR = new Vector3(coreBounds.xMax, 0, coreBounds.yMin); Vector3 coreTL = new Vector3(coreBounds.xMin, 0, coreBounds.yMax); Vector3 coreTR = new Vector3(coreBounds.xMax, 0, coreBounds.yMax); for (int floorIndex = -numberOfBasements; floorIndex < numberOfFloors - 1; floorIndex++) { Vector3 c0 = floorHeightVector * floorIndex + Vector3.up * ceilingHeight; Vector3 f0 = floorHeightVector * floorIndex + Vector3.up * floorHeight; float gapHeight = floorHeight - ceilingHeight; AddPlane(coreBL + c0, coreBR + c0, coreBL + f0, coreBR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight)); AddPlane(coreBR + c0, coreTR + c0, coreBR + f0, coreTR + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight)); AddPlane(coreTR + c0, coreTL + c0, coreTR + f0, coreTL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight)); AddPlane(coreTL + c0, coreBL + c0, coreTL + f0, coreBL + f0, 0, false, Vector2.zero, new Vector2(coreBounds.width, gapHeight)); } } }
public static void SceneGUI(BuildrEditMode editMode, BuildrData data, bool shouldSnap, float handleSize) { if (editMode.fullMesh == null) { return; } Rect HUDRect = new Rect(0, 0, 300, 300); Handles.BeginGUI(); GUILayout.BeginArea(HUDRect); EditorGUILayout.LabelField("Buildr"); EditorGUILayout.LabelField("Vertices: " + editMode.fullMesh.vertexCount); EditorGUILayout.LabelField("Triangles " + editMode.fullMesh.triangleCount / 3); GUILayout.EndArea(); Handles.EndGUI(); bool isLegal = !(data.plan.illegalPoints.Length > 0); if (isLegal) { isLegal = editMode.transform.localScale == Vector3.one; } if (isLegal) { return; } int numberOfFacades = data.facades.Count; int numberOfRoofs = data.roofs.Count; int numberOfTextures = data.textures.Count; if (numberOfFacades == 0 || numberOfRoofs == 0 || numberOfTextures == 0) { return; } Vector3 position = editMode.transform.position; BuildrPlan area = data.plan; int numberOfVolumes = area.numberOfVolumes; int facadeCounter = 0; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = data.plan.volumes[s]; int volumeSize = volume.Count; Vector3 floorCentre = Vector3.zero; Handles.color = Color.red; for (int p = 0; p < volumeSize; p++) { int point = volume.points[p]; Vector3 pointPos = area.points[point].vector3; floorCentre += pointPos; List <Vector3> verts = new List <Vector3>(); int indexB = (p < volumeSize - 1) ? p + 1 : 0; Vector3 volumeHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight); verts.Add(pointPos + position); verts.Add(area.points[volume.points[indexB]].vector3 + position); verts.Add(verts[1] + volumeHeight); verts.Add(verts[0] + volumeHeight); Handles.DrawSolidRectangleWithOutline(verts.ToArray(), new Color(1, 0, 0, 0.2f), Color.red); Handles.DrawLine(verts[2], verts[3]); facadeCounter++; } } }
//TODO: functions to find out minimum footprint of stairwell for checking against cores? public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, int volumeIndex, StairModes stairMode, bool zeroMesh) { data = _data; mesh = _mesh; mesh.name = "Stairs Mesh Volume " + volumeIndex; textures = data.textures.ToArray(); // BuildrFacadeDesign facadeDesign = data.facades[0]; BuildrPlan plan = data.plan; BuildrVolume volume = plan.volumes[volumeIndex]; float floorHeight = data.floorHeight; // Vector3 floorHeightVector = Vector3.up * floorHeight; if (!volume.generateStairs) { return; } //Calculate the internal floor plan points int numberOfVolumePoints = volume.points.Count; Vector2z[] volumePoints = new Vector2z[numberOfVolumePoints]; for (int i = 0; i < numberOfVolumePoints; i++) { volumePoints[i] = plan.points[volume.points[i]]; } List <Rect> volumeCores = new List <Rect>(); // List<int> linkedPoints = new List<int>(); foreach (Rect core in plan.cores) { Vector2z coreCenter = new Vector2z(core.center); if (BuildrUtils.PointInsidePoly(coreCenter, volumePoints)) { volumeCores.Add(core); } } int numberOfVolumeCores = volumeCores.Count; int numberOfFloors = volume.numberOfFloors + volume.numberOfBasementFloors; float basementBaseHeight = (volume.numberOfBasementFloors) * floorHeight;//plus one for the initial floor float staircaseWidth = volume.staircaseWidth; float stairwellWidth = staircaseWidth * 2.5f; float stairwellDepth = staircaseWidth * 2 + Mathf.Sqrt(floorHeight + floorHeight); float staircaseThickness = Mathf.Sqrt(volume.stepHeight * volume.stepHeight + volume.stepHeight * volume.stepHeight); Vector3 flightVector = floorHeight * Vector3.up; Vector3 staircaseWidthVector = staircaseWidth * Vector3.right; Vector3 staircaseDepthVector = stairwellDepth * 0.5f * Vector3.forward; Vector3 stairHeightVector = staircaseThickness * Vector3.up; Vector3 landingDepthVector = staircaseWidth * Vector3.forward; //Texture submeshes int floorSubmesh = volume.stairwellFloorTexture; int stepSubmesh = volume.stairwellStepTexture; int wallSubmesh = volume.stairwellWallTexture; int ceilingSubmesh = volume.stairwellCeilingTexture; volume.stairBaseVector.Clear(); for (int c = 0; c < numberOfVolumeCores; c++) { Rect coreBounds = volumeCores[c]; Vector3 stairBaseVector = new Vector3(-stairwellWidth / 2, 0, -stairwellDepth / 2); Vector3 stairPosition = new Vector3(coreBounds.xMin, -basementBaseHeight, coreBounds.yMin) - stairBaseVector; for (int f = 0; f < numberOfFloors; f++) { Vector3 flightBaseVector = stairBaseVector + (flightVector * f); if (!zeroMesh) { flightBaseVector += stairPosition; } Vector3 landingStart0 = flightBaseVector; Vector3 landingStart1 = landingStart0 + staircaseWidthVector * 2.5f; Vector3 landingStart2 = landingStart0 + landingDepthVector; Vector3 landingStart3 = landingStart1 + landingDepthVector; Vector3 landingStart4 = landingStart0 - stairHeightVector; Vector3 landingStart5 = landingStart1 - stairHeightVector; Vector3 landingStart6 = landingStart2 - stairHeightVector; Vector3 landingStart7 = landingStart3 - stairHeightVector; if (f > 0) { AddPlane(landingStart1, landingStart0, landingStart3, landingStart2, floorSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth)); //top AddPlane(landingStart4, landingStart5, landingStart6, landingStart7, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth)); //bottom AddPlane(landingStart0, landingStart1, landingStart4, landingStart5, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness)); //frontside AddPlane(landingStart3, landingStart2, landingStart7, landingStart6, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness)); //backside AddPlane(landingStart0, landingStart4, landingStart2, landingStart6, wallSubmesh, false, Vector2.zero, new Vector2(staircaseThickness, staircaseWidth)); //sideleft AddPlane(landingStart5, landingStart1, landingStart7, landingStart3, wallSubmesh, false, Vector2.zero, new Vector2(staircaseThickness, staircaseWidth)); //sideright } if (f < numberOfFloors - 1) { Vector3 bottom0 = landingStart2; Vector3 bottom1 = landingStart2 + staircaseWidthVector; Vector3 bottom2 = bottom0 - stairHeightVector; Vector3 bottom3 = bottom1 - stairHeightVector; Vector3 top0 = bottom0 + (flightVector * 0.5f) + staircaseDepthVector; Vector3 top1 = bottom1 + (flightVector * 0.5f) + staircaseDepthVector; Vector3 top2 = top0 - stairHeightVector; Vector3 top3 = top1 - stairHeightVector; Vector3 bottomB0 = top1 + Vector3.right * staircaseWidth * 0.5f; Vector3 bottomB1 = bottomB0 + staircaseWidthVector; Vector3 bottomB2 = bottomB0 - stairHeightVector; Vector3 bottomB3 = bottomB1 - stairHeightVector; Vector3 topB0 = bottomB0 + (flightVector * 0.5f) - staircaseDepthVector; Vector3 topB1 = bottomB1 + (flightVector * 0.5f) - staircaseDepthVector; Vector3 topB2 = topB0 - stairHeightVector; Vector3 topB3 = topB1 - stairHeightVector; float stairHypontenuse = Vector3.Distance(bottom0, top0); int numberOfSteps = Mathf.CeilToInt((floorHeight / 2.0f) / volume.stepHeight); switch (stairMode) { case StairModes.Flat: //flight A AddPlane(bottom1, bottom0, top1, top0, stepSubmesh, false, Vector2.zero, new Vector2(1, numberOfSteps)); //step face AddPlane(bottom3, bottom1, top3, top1, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, stairHypontenuse)); //underside AddPlane(bottom0, bottom2, top0, top2, wallSubmesh, false, new Vector2(bottom2.z, bottom2.y), new Vector2(top0.z, top0.y)); //left side AddPlane(bottom2, bottom3, top2, top3, wallSubmesh, false, new Vector2(bottom3.z, bottom3.y), new Vector2(top2.z, top2.y)); //right side //flight B AddPlane(bottomB0, bottomB1, topB0, topB1, stepSubmesh, false, Vector2.zero, new Vector2(1, numberOfSteps)); //step face AddPlane(bottomB1, bottomB3, topB1, topB3, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, stairHypontenuse)); //underside AddPlane(bottomB2, bottomB0, topB2, topB0, wallSubmesh, false, Vector2.zero, Vector2.one); //left side AddPlane(bottomB3, bottomB2, topB3, topB2, wallSubmesh, false, Vector2.zero, Vector2.one); //right side break; case StairModes.Stepped: float stepHypontenuse = stairHypontenuse / numberOfSteps; float stairAngle = Mathf.Atan2(floorHeight, stairwellDepth); float stepDepth = Mathf.Cos(stairAngle) * stepHypontenuse; float skipStep = (stepDepth / (numberOfSteps - 1)); stepDepth += skipStep; float stepRiser = Mathf.Sin(stairAngle) * stepHypontenuse; //flight one float lerpIncrement = 1.0f / numberOfSteps; float lerpIncrementB = 1.0f / (numberOfSteps - 1); for (int s = 0; s < numberOfSteps - 1; s++) { float lerpValue = lerpIncrement * s; Vector3 skipStepVector = Vector3.forward * (skipStep * s); Vector3 s0 = Vector3.Lerp(bottom1, top1, lerpValue) + skipStepVector; Vector3 s1 = Vector3.Lerp(bottom0, top0, lerpValue) + skipStepVector; Vector3 s2 = s0 + Vector3.up * stepRiser; Vector3 s3 = s1 + Vector3.up * stepRiser; Vector3 s4 = s2 + Vector3.forward * stepDepth; Vector3 s5 = s3 + Vector3.forward * stepDepth; AddPlane(s0, s1, s2, s3, wallSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth)); AddPlane(s2, s3, s4, s5, stepSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth)); //sides float lerpValueB = lerpIncrementB * s; Vector3 s6 = Vector3.Lerp(bottom3, top3, lerpValueB); Vector3 s7 = Vector3.Lerp(bottom3, top3, lerpValueB + lerpIncrementB); AddPlane(s2, s4, s6, s7, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness)); Vector3 s8 = Vector3.Lerp(bottom2, top2, lerpValueB); Vector3 s9 = Vector3.Lerp(bottom2, top2, lerpValueB + lerpIncrementB); AddPlane(s5, s3, s9, s8, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness)); } AddPlane(bottom2, bottom3, top2, top3, ceilingSubmesh, false, Vector2.zero, Vector2.one); //flight two for (int s = 0; s < numberOfSteps - 1; s++) { float lerpValue = lerpIncrement * s; Vector3 skipStepVector = -Vector3.forward * (skipStep * s); Vector3 s0 = Vector3.Lerp(bottomB0, topB0, lerpValue) + skipStepVector; Vector3 s1 = Vector3.Lerp(bottomB1, topB1, lerpValue) + skipStepVector; Vector3 s2 = s0 + Vector3.up * stepRiser; Vector3 s3 = s1 + Vector3.up * stepRiser; Vector3 s4 = s2 - Vector3.forward * stepDepth; Vector3 s5 = s3 - Vector3.forward * stepDepth; AddPlane(s0, s1, s2, s3, wallSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth)); AddPlane(s2, s3, s4, s5, stepSubmesh, false, Vector2.zero, new Vector2(1, staircaseWidth)); float lerpValueB = lerpIncrementB * s; //sides Vector3 s6 = Vector3.Lerp(bottomB2, topB2, lerpValueB); Vector3 s7 = Vector3.Lerp(bottomB2, topB2, lerpValueB + lerpIncrementB); AddPlane(s2, s4, s6, s7, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness)); Vector3 s8 = Vector3.Lerp(bottomB3, topB3, lerpValueB); Vector3 s9 = Vector3.Lerp(bottomB3, topB3, lerpValueB + lerpIncrementB); AddPlane(s5, s3, s9, s8, wallSubmesh, false, Vector2.zero, new Vector2(stepDepth, staircaseThickness)); } AddPlane(bottomB3, bottomB2, topB3, topB2, ceilingSubmesh, false, Vector2.zero, Vector2.one); break; } Vector3 landingEnd0 = top0 + landingDepthVector; Vector3 landingEnd1 = bottomB1 + landingDepthVector; Vector3 landingEnd2 = landingEnd0 - stairHeightVector; Vector3 landingEnd3 = landingEnd1 - stairHeightVector; Vector3 landingEnd4 = top0 - stairHeightVector; Vector3 landingEnd5 = bottomB1 - stairHeightVector; AddPlane(bottomB1, top0, landingEnd1, landingEnd0, floorSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth)); //top AddPlane(landingEnd4, landingEnd5, landingEnd2, landingEnd3, ceilingSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseWidth)); //bottom AddPlane(top0, bottomB1, landingEnd4, landingEnd5, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness)); //frontside AddPlane(landingEnd1, landingEnd0, landingEnd3, landingEnd2, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth * 2.5f, staircaseThickness)); //backside AddPlane(landingEnd0, top0, landingEnd2, landingEnd4, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, staircaseThickness)); //sideleft AddPlane(bottomB1, landingEnd1, landingEnd5, landingEnd3, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth, staircaseThickness)); //sideright } } //Center wall float coreHeight = (numberOfFloors * floorHeight); Vector3 coreHeightVector = Vector3.up * coreHeight; Vector3 corePosition = (zeroMesh) ? Vector3.zero : stairPosition; Vector3 w0 = new Vector3(-staircaseWidth / 4.0f, 0, -(stairwellDepth - (staircaseWidth * 2)) / 2.0f) + corePosition; Vector3 w1 = w0 + Vector3.right * staircaseWidth / 2; Vector3 w2 = w0 + staircaseDepthVector; Vector3 w3 = w1 + staircaseDepthVector; Vector3 w4 = w0 + coreHeightVector; Vector3 w5 = w1 + coreHeightVector; Vector3 w6 = w2 + coreHeightVector; Vector3 w7 = w3 + coreHeightVector; AddPlane(w1, w0, w5, w4, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth / 2, coreHeight)); // AddPlane(w3, w1, w7, w5, wallSubmesh, false, Vector2.zero, new Vector2(stairwellDepth / 2, coreHeight)); // AddPlane(w2, w3, w6, w7, wallSubmesh, false, Vector2.zero, new Vector2(staircaseWidth / 2, coreHeight)); // AddPlane(w0, w2, w4, w6, wallSubmesh, false, Vector2.zero, new Vector2(stairwellDepth / 2, coreHeight)); // int it = 100; while (volume.stairBaseVector.Count < mesh.meshCount) { if (zeroMesh) { volume.stairBaseVector.Add(stairPosition); } else { volume.stairBaseVector.Add(Vector3.zero); } it--; if (it == 0) { break; } } if (c < numberOfVolumeCores - 1) { mesh.ForceNewMesh(); } } }
private static void BuildTextures() { List <TexturePaintObject> buildSourceTextures = new List <TexturePaintObject>(); foreach (BuildrTexture btexture in data.textures)//Gather the source textures, resized into Color32 arrays { TexturePaintObject texturePaintObject = new TexturePaintObject(); texturePaintObject.pixels = ((Texture2D)btexture.texture).GetPixels32(); texturePaintObject.width = btexture.texture.width; texturePaintObject.height = btexture.texture.height; texturePaintObject.tiles = new Vector2(btexture.tiledX, btexture.tiledY); if (btexture.tiled) { int resizedTextureWidth = Mathf.RoundToInt(btexture.textureUnitSize.x * PIXELS_PER_METER * packedScale); int resizedTextureHeight = Mathf.RoundToInt(btexture.textureUnitSize.y * PIXELS_PER_METER * packedScale); texturePaintObject.pixels = TextureScale.NearestNeighbourSample(texturePaintObject.pixels, texturePaintObject.width, texturePaintObject.height, resizedTextureWidth, resizedTextureHeight); texturePaintObject.width = resizedTextureWidth; texturePaintObject.height = resizedTextureHeight; } else { texturePaintObject.tiled = false; } buildSourceTextures.Add(texturePaintObject); } LogTimer("Gather Source into Arrays"); TexturePaintObject[] sourceTextures = buildSourceTextures.ToArray(); textures = data.textures.ToArray(); BuildrFacadeDesign facadeDesign = data.facades[0]; BuildrPlan plan = data.plan; int numberOfVolumes = data.plan.numberOfVolumes; int facadeNumber = 0; 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, indexB; Vector3 p0, p1; indexA = f; indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0; p0 = plan.points[volume.points[indexA]].vector3; p1 = plan.points[volume.points[indexB]].vector3; Rect packedPosition = packedTexturePositions[facadeNumber]; float facadeWidth = Vector3.Distance(p0, p1); 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; BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]); int floorPatternSize = 0; List <int> facadePatternReference = new List <int>(); //this contains a list of all the facade style indices to refence when looking for the appropriate style per floor int patternCount = 0; foreach (BuildrVolumeStylesUnit styleUnit in styleUnits) //need to knw how big all the styles are together so we can loop through them { floorPatternSize += styleUnit.floors; for (int i = 0; i < styleUnit.floors; i++) { facadePatternReference.Add(patternCount); } patternCount++; } facadePatternReference.Reverse(); int rows = numberOfFloors; Vector2 bayBase = Vector2.zero; float currentFloorBase = 0; for (int r = 0; r < rows; r++) { currentFloorBase = floorHeight * r; int modFloor = (r % floorPatternSize); facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID]; bool isBlankWall = !facadeDesign.hasWindows; if (facadeDesign.type == BuildrFacadeDesign.types.patterned) { BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]]; if (firstBay.openingWidth > facadeWidth) { isBlankWall = true; } if (facadeDesign.bayPattern.Count == 0) { isBlankWall = true; } } else { if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth) { isBlankWall = true; } } if (!isBlankWall) { float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles int numberOfBays = 0; BuildrBay[] bays; int numberOfBayDesigns = 0; if (facadeDesign.type == BuildrFacadeDesign.types.patterned) { numberOfBayDesigns = facadeDesign.bayPattern.Count; bays = new BuildrBay[numberOfBayDesigns]; for (int i = 0; i < numberOfBayDesigns; i++) { bays[i] = data.bays[facadeDesign.bayPattern[i]]; } } else { bays = new[] { facadeDesign.simpleBay }; numberOfBayDesigns = 1; } //start with first window width - we'll be adding to this until we have filled the facade width int it = 100; while (true) { int patternModIndex = numberOfBays % numberOfBayDesigns; float patternAddition = bays[patternModIndex].openingWidth + bays[patternModIndex].minimumBayWidth; if (patternSize + patternAddition < facadeWidth) { patternSize += patternAddition; numberOfBays++; } else { break; } it--; if (it < 0) { break; } } float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays; float windowXBase = 0; for (int c = 0; c < numberOfBays; c++) { BuildrBay bayStyle; if (facadeDesign.type == BuildrFacadeDesign.types.patterned) { int numberOfBayStyles = facadeDesign.bayPattern.Count; bayStyle = bays[c % numberOfBayStyles]; } else { bayStyle = facadeDesign.simpleBay; } float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing; float leftSpace = actualWindowSpacing * bayStyle.openingWidthRatio; float rightSpace = actualWindowSpacing - leftSpace; float openingSpace = bayStyle.openingWidth; Vector3 bayDimensions; int subMesh; bool flipped; if (!bayStyle.isOpening) { subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.WallTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.WallTexture); bayBase.x = windowXBase; bayBase.y = currentFloorBase; float bayWidth = (openingSpace + actualWindowSpacing); float bayHeight = floorHeight; bayDimensions = new Vector2(bayWidth, bayHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); windowXBase += bayWidth; //move base vertor to next bay continue; //bay filled - move onto next bay } float rowBottomHeight = ((floorHeight - bayStyle.openingHeight) * bayStyle.openingHeightRatio); float rowTopHeight = (floorHeight - rowBottomHeight - bayStyle.openingHeight); //Window subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture); bayBase.x = windowXBase + leftSpace; bayBase.y = currentFloorBase + rowBottomHeight; bayDimensions = new Vector2(bayStyle.openingWidth, bayStyle.openingHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); //Column Left if (leftSpace > 0) { subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture); bayBase.x = windowXBase; bayBase.y = currentFloorBase + rowBottomHeight; bayDimensions = new Vector2(leftSpace, bayStyle.openingHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); } //Column Right if (rightSpace > 0) { subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture); bayBase.x = windowXBase + leftSpace + openingSpace; bayBase.y = currentFloorBase + rowBottomHeight; bayDimensions = new Vector2(rightSpace, bayStyle.openingHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); } //Row Bottom if (rowBottomHeight > 0) { subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture); bayBase.x = windowXBase + leftSpace; bayBase.y = currentFloorBase; bayDimensions = new Vector2(openingSpace, rowBottomHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); } //Row Top if (rowTopHeight > 0) { subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture); bayBase.x = windowXBase + leftSpace; bayBase.y = currentFloorBase + rowBottomHeight + bayStyle.openingHeight; bayDimensions = new Vector2(openingSpace, rowTopHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); } //Cross Left if (leftSpace > 0) { //Cross Left Bottom subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture); bayBase.x = windowXBase; bayBase.y = currentFloorBase; bayDimensions = new Vector2(leftSpace, rowBottomHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); //Cross Left Top subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture); bayBase.x = windowXBase; bayBase.y = currentFloorBase + rowBottomHeight + bayStyle.openingHeight; bayDimensions = new Vector2(leftSpace, rowTopHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); } //Cross Right if (rightSpace > 0) { //Cross Left Bottom subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture); bayBase.x = windowXBase + leftSpace + openingSpace; bayBase.y = currentFloorBase; bayDimensions = new Vector2(rightSpace, rowBottomHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); //Cross Left Top subMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture); flipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture); bayBase.x = windowXBase + leftSpace + openingSpace; bayBase.y = currentFloorBase + rowBottomHeight + bayStyle.openingHeight; bayDimensions = new Vector2(rightSpace, rowTopHeight); DrawFacadeTexture(sourceTextures, bayBase, bayDimensions, subMesh, flipped, packedPosition); } windowXBase += leftSpace + openingSpace + rightSpace;//move base vertor to next bay } } else { // windowless wall int subMesh = facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture); bool flipped = facadeDesign.simpleBay.IsFlipped(BuildrBay.TextureNames.WallTexture); bayBase.x = 0; bayBase.y = currentFloorBase; Vector2 dimensions = new Vector2(facadeWidth, floorHeight); DrawFacadeTexture(sourceTextures, bayBase, dimensions, subMesh, flipped, packedPosition); } } facadeNumber++; } } LogTimer("generate facade textures"); //add roof textures int numberOfroofTextures = roofTextures.Count; int scaledPadding = Mathf.FloorToInt(ATLAS_PADDING * packedScale); for (int i = 0; i < numberOfroofTextures; i++) { Rect roofTexturePosition = packedTexturePositions[i + facadeNumber]; BuildrTexture bTexture = roofTextures[i]; int roofTextureWidth = bTexture.texture.width; int roofTextureHeight = bTexture.texture.height; int targetTextureWidth = Mathf.RoundToInt(roofTexturePosition.width); int targetTextureHeight = Mathf.RoundToInt(roofTexturePosition.height); if (bTexture.maxUVTile == Vector2.zero) { LogTimer("BuildTextures: Skip texture " + bTexture.name + " as it appears it's not used"); continue; } int sourceTextureWidth = Mathf.RoundToInt(targetTextureWidth / (bTexture.tiled ? bTexture.maxUVTile.x : bTexture.tiledX)); int sourceTextureHeight = Mathf.RoundToInt(targetTextureHeight / (bTexture.tiled ? bTexture.maxUVTile.y : bTexture.tiledY)); int sourceTextureSize = sourceTextureWidth * sourceTextureHeight; if (sourceTextureSize == 0) { //Debug.Log(sourceTextureWidth+" "+sourceTextureHeight+" "+bTexture.tiledX+" "+bTexture.maxUVTile+" "+bTexture.tiledX+","+bTexture.tiledY); continue; } Color32[] roofColourArray = TextureScale.NearestNeighbourSample(((Texture2D)bTexture.texture).GetPixels32(), roofTextureWidth, roofTextureHeight, sourceTextureWidth, sourceTextureHeight); //Color32[] roofColourArray = bTexture.texture.GetPixels32(); for (int x = 0; x < targetTextureWidth; x++) { for (int y = 0; y < targetTextureHeight; y++) { int drawX = Mathf.FloorToInt(x + roofTexturePosition.x); int drawY = Mathf.FloorToInt(y + roofTexturePosition.y); int colourIndex = drawX + drawY * textureWidth; int sx = x % sourceTextureWidth; int sy = y % sourceTextureHeight; int sourceIndex = sx + sy * sourceTextureWidth; if (sourceIndex >= sourceTextureSize) { Debug.Log("Source Index too big " + sx + " " + sy + " " + sourceTextureWidth + " " + sourceTextureSize + " " + bTexture.maxUVTile + " " + bTexture.name); } Color32 sourceColour = roofColourArray[sourceIndex]; if (colourIndex >= textureSize) { Debug.Log("Output Index Too big " + drawX + " " + drawY + " " + colourIndex + " " + textureSize + " " + roofTexturePosition); } colourArray[colourIndex] = sourceColour; //Padding if (x == 0) { for (int p = 0; p < scaledPadding; p++) { colourArray[colourIndex - p] = sourceColour; } } if (x == targetTextureWidth - 1) { for (int p = 0; p < scaledPadding; p++) { colourArray[colourIndex + p] = sourceColour; } } if (y == 0) { for (int p = 0; p < scaledPadding; p++) { colourArray[colourIndex - (p * textureWidth)] = sourceColour; } } if (y == targetTextureHeight - 1) { for (int p = 0; p < scaledPadding; p++) { colourArray[colourIndex + (p * textureWidth)] = sourceColour; } } } } } LogTimer("generate roof textures"); }
public static void InspectorGUI(BuildrEditMode editMode, BuildrData _data) { data = _data; Undo.RecordObject(data, "Building Modified"); BuildrPlan plan = data.plan; int numberOfFacadeFaces = 0; int numberOfVolumes = plan.numberOfVolumes; int numberOfFacadeDesigns = data.facades.Count; if (numberOfVolumes == 0) { EditorGUILayout.HelpBox("There are no defined volumes, go to Floorplan and define one", MessageType.Error); return; } int numberOfFacades = data.facades.Count; int numberOfRoofs = data.roofs.Count; int numberOfTextures = data.textures.Count; bool legalBuilding = true; if (numberOfFacades == 0) { EditorGUILayout.HelpBox("There are no facade designs to render building, go to Facades to define a default one", MessageType.Error); legalBuilding = false; } if (numberOfRoofs == 0) { EditorGUILayout.HelpBox("There are no roof designs to render building, go to Facades to define a default one", MessageType.Error); legalBuilding = false; } if (numberOfTextures == 0) { EditorGUILayout.HelpBox("There are no textures to render building, go to Textures to define a default one", MessageType.Error); legalBuilding = false; } if (!legalBuilding) { return; } //Building Name EditorGUILayout.Space(); EditorGUILayout.Space(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Name", GUILayout.Width(200)); data.name = EditorGUILayout.TextField(data.name, GUILayout.Width(200)); EditorGUILayout.EndHorizontal(); //Floor Height EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Floor height", GUILayout.Width(200)); data.floorHeight = EditorGUILayout.FloatField(data.floorHeight, GUILayout.Width(50)); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Number of Floors", GUILayout.Width(200)); int[] volumeSeletionsList = new int[numberOfVolumes]; string[] volumeSeletionsStringList = new string[numberOfVolumes]; for (int s = 0; s < numberOfVolumes; s++) { volumeSeletionsStringList[s] = ("volume " + s); volumeSeletionsList[s] = (s); } selectedFloorNumberVolume = EditorGUILayout.IntPopup(selectedFloorNumberVolume, volumeSeletionsStringList, volumeSeletionsList, GUILayout.Width(100)); int numberOfFloors = EditorGUILayout.IntField(data.plan.volumes[selectedFloorNumberVolume].numberOfFloors); if (GUILayout.Button("^")) { numberOfFloors++; } if (GUILayout.Button("v")) { numberOfFloors--; } data.plan.volumes[selectedFloorNumberVolume].numberOfFloors = Mathf.Max(numberOfFloors, 1); EditorGUILayout.EndHorizontal(); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Show Facade Markers", GUILayout.Width(200)); editMode.showFacadeMarkers = EditorGUILayout.Toggle(editMode.showFacadeMarkers, GUILayout.Width(200)); EditorGUILayout.EndHorizontal(); EditorGUILayout.Space(); GUIStyle titlesyle = new GUIStyle(GUI.skin.label); titlesyle.fixedHeight = 60; titlesyle.fixedWidth = 400; titlesyle.alignment = TextAnchor.UpperCenter; titlesyle.fontStyle = FontStyle.Bold; titlesyle.normal.textColor = Color.white; EditorGUILayout.LabelField("Facade Design", titlesyle); Texture2D facadeTexture = new Texture2D(1, 1); facadeTexture.SetPixel(0, 0, BuildrColours.MAGENTA); facadeTexture.Apply(); Rect sqrPos = new Rect(0, 0, 0, 0); if (Event.current.type == EventType.Repaint) { sqrPos = GUILayoutUtility.GetLastRect(); } GUI.DrawTexture(sqrPos, facadeTexture); EditorGUI.LabelField(sqrPos, "Facade Design", titlesyle); //create/display the facade selector List <int> facadeSeletionsList = new List <int>(); List <int> facadeRenderList = new List <int>(); List <string> facadeSeletionsStringList = new List <string>(); for (int s = 0; s < numberOfVolumes; s++) { int numberOfPoints = plan.volumes[s].Count; numberOfFacadeFaces += numberOfPoints; for (int p = 0; p < numberOfPoints; p++) { int index = facadeSeletionsList.Count; facadeSeletionsStringList.Add("facade " + index); facadeSeletionsList.Add(index); facadeRenderList.Add(p); } } int[] facadeSelections = facadeSeletionsList.ToArray(); string[] facadeSelectionString = facadeSeletionsStringList.ToArray(); selectedFacade = EditorGUILayout.IntPopup("Selected Facade", selectedFacade, facadeSelectionString, facadeSelections, GUILayout.Width(400)); //grab the selected facade int facadeCount = 0; int selectedVolumePoint = 0; for (int s = 0; s < numberOfVolumes; s++) { int numberOfPoints = plan.volumes[s].Count; for (int p = 0; p < numberOfPoints; p++) { if (selectedFacade == facadeCount) { selectedVolume = s; selectedVolumePoint = p; selectedPoint = plan.volumes[s].points[p]; } facadeCount++; } } BuildrVolume volume = plan.volumes[selectedVolume]; BuildrVolumeStylesUnit[] styles = volume.styles.GetContents(); bool renderFacade = volume.renderFacade[selectedVolumePoint]; volume.renderFacade[selectedVolumePoint] = EditorGUILayout.Toggle("Render Facade", renderFacade); //ensure the selected style isn't out of bounds int numberOfStyles = styles.Length; if (selectedStyle >= numberOfStyles) { selectedStyle = 0; } //compose a list of style ids from the volume style library List <int> entryNum = new List <int>(); for (int s = 0; s < numberOfStyles; s++) { if (selectedPoint == styles[s].facadeID) { entryNum.Add(s); } } int numberOfFacadeStyles = entryNum.Count; if (GUILayout.Button("Add style to facade", GUILayout.Width(400))) { volume.styles.AddStyle(0, selectedPoint, 1); } GUILayout.BeginHorizontal("box"); GUILayout.BeginHorizontal("box"); EditorGUILayout.LabelField("Style", GUILayout.Width(160)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal("box"); GUILayout.Label("Floors", GUILayout.Width(78)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal("box"); GUILayout.Label("Position", GUILayout.Width(54)); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal("box"); GUILayout.Label(" ", GUILayout.Width(55)); GUILayout.EndHorizontal(); GUILayout.EndHorizontal(); for (int s = 0; s < numberOfFacadeStyles; s++) { int index = entryNum[s]; BuildrVolumeStylesUnit styleUnit = styles[index]; GUILayout.BeginHorizontal("box"); GUILayout.BeginHorizontal("box"); string[] facadeNames = new string[numberOfFacadeDesigns]; for (int f = 0; f < numberOfFacadeDesigns; f++) { facadeNames[f] = data.facades[f].name; } int selectedFacadeDesign = EditorGUILayout.Popup(styleUnit.styleID, facadeNames, GUILayout.Width(160)); if (selectedFacadeDesign != styleUnit.styleID) { volume.styles.ModifyStyle(index, selectedFacadeDesign); } GUILayout.EndHorizontal(); GUILayout.BeginHorizontal("box"); int currentFloors = styleUnit.floors; currentFloors = EditorGUILayout.IntField(currentFloors, GUILayout.Width(20)); if (GUILayout.Button("+", GUILayout.Width(25))) { currentFloors++; } EditorGUI.BeginDisabledGroup(currentFloors < 2); if (GUILayout.Button("-", GUILayout.Width(25))) { currentFloors--; } EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal("box"); EditorGUI.BeginDisabledGroup((s < 1)); { if (GUILayout.Button("^", GUILayout.Width(25))) { volume.styles.MoveEntry(entryNum[s], entryNum[s - 1] + 1); GUI.changed = true; } } EditorGUI.EndDisabledGroup(); EditorGUI.BeginDisabledGroup((s > numberOfFacadeStyles - 2)); { if (GUILayout.Button("v", GUILayout.Width(25))) { volume.styles.MoveEntry(entryNum[s], entryNum[s + 1] + 1); GUI.changed = true; } } EditorGUI.EndDisabledGroup(); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal("box"); if (GUILayout.Button("remove", GUILayout.Width(55))) { volume.styles.RemoveStyle(index); } GUILayout.EndHorizontal(); GUILayout.EndHorizontal(); if (currentFloors != styleUnit.floors) { volume.styles.ModifyFloors(index, currentFloors); GUI.changed = true; } } EditorGUILayout.Space(); titlesyle = new GUIStyle(GUI.skin.label); titlesyle.fixedHeight = 60; titlesyle.fixedWidth = 400; titlesyle.alignment = TextAnchor.UpperCenter; titlesyle.fontStyle = FontStyle.Bold; titlesyle.normal.textColor = Color.black; EditorGUILayout.LabelField("Roof Design", titlesyle); facadeTexture = new Texture2D(1, 1); facadeTexture.SetPixel(0, 0, BuildrColours.CYAN); facadeTexture.Apply(); sqrPos = new Rect(0, 0, 0, 0); if (Event.current.type == EventType.Repaint) { sqrPos = GUILayoutUtility.GetLastRect(); } GUI.DrawTexture(sqrPos, facadeTexture); EditorGUI.LabelField(sqrPos, "Roof Design", titlesyle); //create/display the roof selector volumeSeletionsList = new int[numberOfVolumes]; volumeSeletionsStringList = new string[numberOfVolumes]; for (int s = 0; s < numberOfVolumes; s++) { volumeSeletionsStringList[s] = ("volume " + s); volumeSeletionsList[s] = (s); } selectedRoofVolume = EditorGUILayout.IntPopup("Selected Volume", selectedRoofVolume, volumeSeletionsStringList, volumeSeletionsList, GUILayout.Width(400)); string[] roofNames = new string[numberOfRoofs]; int[] roofList = new int[numberOfRoofs]; for (int r = 0; r < numberOfRoofs; r++) { roofList[r] = r; roofNames[r] = data.roofs[r].name; } volume = data.plan.volumes[selectedRoofVolume]; volume.roofDesignID = EditorGUILayout.IntPopup("Selected Roof Design", volume.roofDesignID, roofNames, roofList, GUILayout.Width(400)); }
private static void Mansard(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfVolumePoints = volume.points.Count; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); //add top base of the flat roof Vector3[] topVerts = new Vector3[numberOfVolumePoints]; Vector2[] topUVs = new Vector2[numberOfVolumePoints]; int topTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floorB); BuildrTexture texture = textures[topTextureID]; for (int l = 0; l < numberOfVolumePoints; l++) { int indexA, indexB, indexA0, indexB0; Vector3 p0, p1, p00, p10; indexA = l; indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0; indexA0 = (l > 0) ? l - 1 : numberOfVolumePoints - 1; indexB0 = (l < numberOfVolumePoints - 2) ? l + 2 : l + 2 - numberOfVolumePoints; p0 = area.points[volume.points[indexA]].vector3; p1 = area.points[volume.points[indexB]].vector3; p00 = area.points[volume.points[indexA0]].vector3; p10 = area.points[volume.points[indexB0]].vector3; float facadeWidth = Vector3.Distance(p0, p1); Vector3 facadeDirection = (p1 - p0).normalized; Vector3 facadeDirectionLeft = (p0 - p00).normalized; Vector3 facadeDirectionRight = (p10 - p1).normalized; Vector3 facadeNormal = Vector3.Cross(facadeDirection, Vector3.up); Vector3 facadeNormalLeft = Vector3.Cross(facadeDirectionLeft, Vector3.up); Vector3 facadeNormalRight = Vector3.Cross(facadeDirectionRight, Vector3.up); float roofHeight = design.height; float baseDepth = design.floorDepth; float cornerLeftRad = Vector3.Angle(facadeDirection, -facadeDirectionLeft) * Mathf.Deg2Rad / 2; float cornerRightRad = Vector3.Angle(-facadeDirection, facadeDirectionRight) * Mathf.Deg2Rad / 2; float cornerDepthLeft = baseDepth / Mathf.Sin(cornerLeftRad); float cornerDepthRight = baseDepth / Mathf.Sin(cornerRightRad); float topDepth = design.depth; float cornerTopDepthLeft = topDepth / Mathf.Sin(cornerLeftRad); float cornerTopDepthRight = topDepth / Mathf.Sin(cornerRightRad); Vector3 pr = facadeDirection * facadeWidth; Vector3 leftDir = (facadeNormal + facadeNormalLeft).normalized; Vector3 rightDir = (facadeNormal + facadeNormalRight).normalized; p0 += volumeFloorHeight; p1 += volumeFloorHeight; Vector3 w0, w1, w2, w3, w4, w5; w0 = p0; w1 = p0 + pr; w2 = w0 + leftDir * cornerDepthLeft; w3 = w1 + rightDir * cornerDepthRight; w4 = w2 + leftDir * cornerTopDepthLeft + Vector3.up * roofHeight; w5 = w3 + rightDir * cornerTopDepthRight + Vector3.up * roofHeight; Vector3[] verts = new Vector3[6] { w0, w1, w2, w3, w4, w5 }; // List<Vector2> uvs = new List<Vector2>(); Vector2[] uvsFloor = BuildrProjectUVs.Project(new Vector3[4] { w0, w1, w2, w3 }, Vector2.zero, facadeNormal); if(baseDepth == 0) uvsFloor[3].x = facadeWidth; Vector2[] uvsMansard = BuildrProjectUVs.Project(new Vector3[3] { w2, w4, w5 }, uvsFloor[2], facadeNormal); Vector3[] vertsA = new Vector3[4] { verts[0], verts[1], verts[2], verts[3] }; Vector2[] uvsA = new Vector2[4] { uvsFloor[0], uvsFloor[1], uvsFloor[2], uvsFloor[3] }; int[] trisA = new int[6] { 1, 0, 2, 1, 2, 3 }; int subMeshA = design.GetTexture(BuildrRoofDesign.textureNames.floor); mesh.AddData(vertsA, uvsA, trisA, subMeshA); Vector3[] vertsB = new Vector3[4] { verts[2], verts[3], verts[4], verts[5] }; Vector2[] uvsB = new Vector2[4] { uvsFloor[2], uvsFloor[3], uvsMansard[1], uvsMansard[2] }; int[] trisB = new int[6] { 0, 2, 1, 1, 2, 3 }; int subMeshB = design.GetTexture(BuildrRoofDesign.textureNames.tiles); mesh.AddData(vertsB, uvsB, trisB, subMeshB); //modify point for the top geometry Vector2z point = area.points[volume.points[l]]; topVerts[l] = point.vector3 + volumeFloorHeight + Vector3.up * roofHeight + leftDir * (cornerDepthLeft + cornerTopDepthLeft); topUVs[l] = new Vector2(topVerts[l].x / texture.textureUnitSize.x, topVerts[l].z / texture.textureUnitSize.y); } Vector2z[] topVertV2z = new Vector2z[topVerts.Length]; for (int i = 0; i < topVerts.Length; i++) topVertV2z[i] = new Vector2z(topVerts[i]); int[] topTris = EarClipper.Triangulate(topVertV2z); AddData(topVerts, topUVs, topTris, topTextureID);//top }
private static void GenerateFacades(BuildrData data) { BuildrGenerateConstraints constraints = data.generatorConstraints; RandomGen rgen = constraints.rgen; //generate bays //blank BuildrBay blankBay = new BuildrBay("Blank"); blankBay.isOpening = false; data.bays.Add(blankBay); //door BuildrBay doorBay = new BuildrBay("Door"); doorBay.openingHeight = data.floorHeight * 0.9f; doorBay.openingHeightRatio = 0.0f; float doorWidth = (doorTexture.texture.width / (float)doorTexture.texture.height) * doorBay.openingHeight; doorBay.openingWidth = doorWidth; doorBay.openingDepth = rgen.OutputRange(0.0f, 0.3f); doorBay.SetTexture(BuildrBay.TextureNames.OpeningBackTexture, data.textures.IndexOf(doorTexture)); data.bays.Add(doorBay); //ground window BuildrBay groundWindow = new BuildrBay("Ground Window"); groundWindow.openingWidth = rgen.OutputRange(constraints.openingMinimumWidth, constraints.openingMaximumWidth); groundWindow.openingHeight = rgen.OutputRange(constraints.openingMinimumHeight, Mathf.Min(data.floorHeight, constraints.openingMinimumHeight)); groundWindow.openingDepth = rgen.OutputRange(constraints.openingMinimumDepth, constraints.openingMaximumDepth); groundWindow.openingHeightRatio = 0.8f; data.bays.Add(groundWindow); // BuildrTexture groundFloorWindowTexture = windowTexture.Duplicate("groundWindowTexture"); groundFloorWindowTexture.tiled = false; groundFloorWindowTexture.tiledX = Mathf.RoundToInt(groundWindow.openingWidth / groundWindow.openingHeight); int groundtextureIndex = data.textures.IndexOf(groundFloorWindowTexture); // data.textures.Add(groundFloorWindowTexture); groundWindow.SetTexture(BuildrBay.TextureNames.OpeningBackTexture, groundtextureIndex); //other windows BuildrBay windowBay = new BuildrBay("Window"); data.bays.Add(windowBay); //util window BuildrBay utilBay = new BuildrBay("Utility Window"); data.bays.Add(utilBay); //generate facades BuildrFacadeDesign basicFacadeDesign = new BuildrFacadeDesign("default"); basicFacadeDesign.simpleBay.openingWidth = rgen.OutputRange(constraints.openingMinimumWidth, constraints.openingMaximumWidth); basicFacadeDesign.simpleBay.openingHeight = rgen.OutputRange(constraints.openingMinimumHeight, Mathf.Min(data.floorHeight, constraints.openingMinimumHeight)); basicFacadeDesign.simpleBay.openingDepth = rgen.OutputRange(constraints.openingMinimumDepth, constraints.openingMaximumDepth); // float roughBaySize = basicFacadeDesign.simpleBay.openingHeight + basicFacadeDesign.simpleBay.openingWidth; basicFacadeDesign.simpleBay.minimumBayWidth = rgen.OutputRange(constraints.minimumBayMaximumWidth, constraints.minimumBayMaximumWidth); data.facades.Add(basicFacadeDesign); //ground floor with and without door BuildrFacadeDesign groundFloorDoor = new BuildrFacadeDesign("Ground Floor With Door"); groundFloorDoor.type = BuildrFacadeDesign.types.patterned; int patternSize = rgen.OutputRange(1, 8); for (int i = 0; i < patternSize; i++) { groundFloorDoor.bayPattern.Add(rgen.output > 0.2f?2:0); } groundFloorDoor.bayPattern.Insert(rgen.OutputRange(0, patternSize), 1);//insert door into pattern data.facades.Add(groundFloorDoor); //couple of main facades //utility/back wall facade //maybe attic version BuildrPlan plan = data.plan; for (int v = 0; v < plan.numberOfVolumes; v++) { BuildrVolume volume = plan.volumes[v]; int numberOfFloors = volume.numberOfFloors; volume.styles.Clear(); for (int f = 0; f < volume.points.Count; f++) { int facadeIndex = volume.points[f]; volume.styles.AddStyle(0, facadeIndex, numberOfFloors - 1); volume.styles.AddStyle(1, facadeIndex, 1); } } }
private static void Sawtooth(BuildrVolume volume, BuildrRoofDesign design) { BuildrPlan area = data.plan; int numberOfFloors = volume.numberOfFloors; float floorHeight = data.floorHeight; Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight); Vector3 ridgeVector = Vector3.up * design.height; int[] pointIndexes = new int[4]; switch (design.direction) { case 0: pointIndexes = new int[4] { 0, 1, 2, 3 }; break; case 1: pointIndexes = new int[4] { 1, 2, 3, 0 }; break; case 2: pointIndexes = new int[4] { 2, 3, 0, 1 }; break; case 3: pointIndexes = new int[4] { 3, 0, 1, 2 }; break; } Vector3[] basepoints = new Vector3[4]; Vector3[] points = new Vector3[6]; for (int i = 0; i < design.sawtoothTeeth; i++) { Vector3 toothBaseMovementA = (area.points[volume.points[pointIndexes[3]]].vector3 - area.points[volume.points[pointIndexes[0]]].vector3).normalized; float roofDepthA = Vector3.Distance(area.points[volume.points[pointIndexes[3]]].vector3, area.points[volume.points[pointIndexes[0]]].vector3); float toothDepthA = roofDepthA / design.sawtoothTeeth; Vector3 toothVectorA = toothBaseMovementA * toothDepthA; Vector3 toothBaseMovementB = (area.points[volume.points[pointIndexes[2]]].vector3 - area.points[volume.points[pointIndexes[1]]].vector3).normalized; float roofDepthB = Vector3.Distance(area.points[volume.points[pointIndexes[2]]].vector3, area.points[volume.points[pointIndexes[1]]].vector3); float toothDepthB = roofDepthB / design.sawtoothTeeth; Vector3 toothVectorB = toothBaseMovementB * toothDepthB; basepoints[0] = area.points[volume.points[pointIndexes[0]]].vector3 + toothVectorA * i; basepoints[1] = area.points[volume.points[pointIndexes[1]]].vector3 + toothVectorB * i; basepoints[2] = basepoints[1] + toothVectorB; basepoints[3] = basepoints[0] + toothVectorA; points[0] = basepoints[0] + volumeFloorHeight; points[1] = basepoints[1] + volumeFloorHeight; points[2] = basepoints[2] + volumeFloorHeight; points[3] = basepoints[3] + volumeFloorHeight; points[4] = basepoints[2] + volumeFloorHeight + ridgeVector; points[5] = basepoints[3] + volumeFloorHeight + ridgeVector; //top int subMeshTop = design.GetTexture(BuildrRoofDesign.textureNames.tiles); bool flippedTop = design.IsFlipped(BuildrRoofDesign.textureNames.tiles); AddPlane(design, points[0], points[1], points[5], points[4], subMeshTop, flippedTop); //window int subMeshWindow = design.GetTexture(BuildrRoofDesign.textureNames.window); bool flippedWindow = design.IsFlipped(BuildrRoofDesign.textureNames.window); AddPlane(design, points[2], points[3], points[4], points[5], subMeshWindow, flippedWindow); //sides Vector3[] vertsA = new Vector3[3] { points[1], points[2], points[4] }; Vector3[] vertsB = new Vector3[3] { points[0], points[3], points[5] }; float uvWdith = Vector3.Distance(points[0], points[3]); float uvHeight = design.height; int subMesh = design.GetTexture(BuildrRoofDesign.textureNames.wall); BuildrTexture texture = textures[subMesh]; if (texture.tiled) { uvWdith *= (1.0f / texture.textureUnitSize.x); uvHeight *= (1.0f / texture.textureUnitSize.y); if (texture.patterned) { Vector2 uvunits = texture.tileUnitUV; uvWdith = Mathf.Ceil(uvWdith / uvunits.x) * uvunits.x; uvHeight = Mathf.Ceil(uvHeight / uvunits.y) * uvunits.y; } } else { uvWdith = texture.tiledX; uvHeight = texture.tiledY; } Vector2[] uvs = new Vector2[3] { new Vector2(0, 0), new Vector2(uvWdith, 0), new Vector2(uvWdith, uvHeight) }; int[] triA = new int[3] { 1, 0, 2 }; int[] triB = new int[3] { 0, 1, 2 }; AddData(vertsA, uvs, triA, subMesh); AddData(vertsB, uvs, triB, subMesh); } }
public BuildrPlan Duplicate() { BuildrPlan newplan = (BuildrPlan)Instantiate(this); return(newplan); }
public static void SceneGUI(BuildrEditMode editMode, BuildrPlan plan, bool shouldSnap, float handleSize) { Vector3 position = editMode.transform.position; Plane buildingPlane = new Plane(Vector3.up, position); float distance; Vector3 mousePlanePoint = Vector3.zero; Camera sceneCamera = Camera.current; Ray ray = sceneCamera.ScreenPointToRay(new Vector3(Event.current.mousePosition.x, Screen.height - Event.current.mousePosition.y - 30, 0)); if (buildingPlane.Raycast(ray, out distance)) { mousePlanePoint = ray.GetPoint(distance); } Quaternion mouseLookDirection = Quaternion.LookRotation(-ray.direction); //Draw the floorplan outline int numberOfVolumes = plan.numberOfVolumes; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volumeLinks = plan.volumes[s]; int volumeSize = volumeLinks.Count; for (int l = 0; l < volumeSize; l++) { Handles.color = Color.white; Vector3[] wallPositions = plan.GetWallVectors(s, l); Handles.DrawLine(wallPositions[0] + position, wallPositions[1] + position); } } //draw outlines of building cores int numberOfCores = plan.cores.Count; for(int c = 0; c < numberOfCores; c++) { Rect coreOutline = plan.cores[c]; Vector3 coreCenter = new Vector3(coreOutline.center.x,0,coreOutline.center.y); Handles.Label(coreCenter + position, "Core " + (c + 1)); Vector3 coreBL = new Vector3(coreOutline.xMin,0, coreOutline.yMin) + position; Vector3 coreBR = new Vector3(coreOutline.xMax,0, coreOutline.yMin) + position; Vector3 coreTL = new Vector3(coreOutline.xMin,0, coreOutline.yMax) + position; Vector3 coreTR = new Vector3(coreOutline.xMax,0, coreOutline.yMax) + position; Handles.DrawLine(coreBL,coreBR); Handles.DrawLine(coreBR,coreTR); Handles.DrawLine(coreTR,coreTL); Handles.DrawLine(coreTL,coreBL); } //Draw red lines over illegal point/lines int numberOfIllegalPoints = plan.numberOfIllegalPoints; if (numberOfIllegalPoints > 0) { Handles.color = Color.red; Vector2z[] illegalPoints = plan.illegalPoints; for (int i = 0; i < numberOfIllegalPoints - 1; i += 2) { Vector3 a, b; a = illegalPoints[i].vector3 + position; b = illegalPoints[i + 1].vector3 + position; Handles.DrawLine(a, b); } } SceneView.focusedWindow.wantsMouseMove = false; Vector3 vertA; Vector3 vertB; int selectedPoint; switch (editMode.mode) { case BuildrEditMode.modes.floorplan: Vector3 sliderPos = Vector3.zero; int numberOfPoints = plan.points.Count; int numberOfSelectedPoints = editMode.selectedPoints.Count; //Per point scene gui for (int i = 0; i < numberOfPoints; i++) { Vector2z point = plan.points[i]; Vector3 pointPos = point.vector3 + position; float pointHandleSize = HandleUtility.GetHandleSize(pointPos); bool selected = editMode.selectedPoints.Contains(i); if (selected) { Handles.color = Color.green; //Handles.Label(pointPos, "point "+i); sliderPos += point.vector3; if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap)) { editMode.selectedPoints.Remove(i); } } else { Handles.color = Color.white; if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.05f, pointHandleSize * 0.05f, Handles.DotCap)) { if (!shouldSnap) editMode.selectedPoints.Clear(); editMode.selectedPoints.Add(i); } } float pointDot = Vector3.Dot(sceneCamera.transform.forward, pointPos - sceneCamera.transform.position); if(pointDot > 0.0f) { Handles.color = Color.white; GUIStyle pointLabelStyle = new GUIStyle(); pointLabelStyle.normal.textColor = Color.white; pointLabelStyle.fontStyle = FontStyle.Bold; pointLabelStyle.alignment = TextAnchor.MiddleCenter; pointLabelStyle.fixedWidth = 50.0f; Handles.Label(pointPos + Vector3.up * 2, "point " + i, pointLabelStyle); } } //draw plan dimensions if (editMode.showDimensionLines) { Handles.color = Color.white; for (int v = 0; v < numberOfVolumes; v++) { BuildrVolume volume = plan.volumes[v]; int volumeSize = volume.Count; for (int l = 0; l < volumeSize; l++) { if (plan.GetConnectingVolumeIndex(v, volume.points[l], volume.points[(l + 1) % volumeSize]) != -1) continue; vertA = plan.points[volume.points[l]].vector3 + position; vertB = plan.points[volume.points[(l + 1) % volumeSize]].vector3 + position; float wallWidth = Vector3.Distance(vertA, vertB); Vector3 facadeDirection = Vector3.Cross((vertA - vertB), Vector3.up).normalized; Vector3 labelPos = (vertA + vertB) * 0.5f + facadeDirection; GUIStyle widthStyle = new GUIStyle(); widthStyle.normal.textColor = Color.white; widthStyle.alignment = TextAnchor.MiddleCenter; widthStyle.fixedWidth = 50.0f; Handles.Label(labelPos, wallWidth.ToString("F2") + "m", widthStyle); if (wallWidth > 3)//draw guidelines { float gapSpace = (HandleUtility.GetHandleSize(labelPos) * 0.5f) / wallWidth; Vector3 lineStopA = Vector3.Lerp(vertA, vertB, (0.5f - gapSpace)) + facadeDirection; Vector3 lineStopB = Vector3.Lerp(vertA, vertB, (0.5f + gapSpace)) + facadeDirection; Handles.DrawLine(vertA + facadeDirection, lineStopA); Handles.DrawLine(vertA + facadeDirection, vertA); Handles.DrawLine(vertB + facadeDirection, lineStopB); Handles.DrawLine(vertB + facadeDirection, vertB); } } } } //selected point scene gui if (numberOfSelectedPoints > 0) { // Undo.SetSnapshotTarget(plan, "Floorplan Node Moved"); sliderPos /= numberOfSelectedPoints; Vector3 dirX = (sliderPos.x < 0) ? Vector3.right : Vector3.left; Vector3 dirZ = (sliderPos.z < 0) ? Vector3.forward : Vector3.back; sliderPos += position; Vector3 newSliderPos; Handles.color = Color.red; newSliderPos = Handles.Slider(sliderPos, dirX, HandleUtility.GetHandleSize(sliderPos) * 0.666f, Handles.ArrowCap, 0.0f); Handles.color = Color.blue; newSliderPos = Handles.Slider(newSliderPos, dirZ, HandleUtility.GetHandleSize(newSliderPos) * 0.666f, Handles.ArrowCap, 0.0f); Vector3 sliderDiff = newSliderPos - sliderPos; for (int i = 0; i < numberOfPoints; i++) { if (editMode.selectedPoints.Contains(i)) { if(sliderDiff != Vector3.zero) { Vector2z point = plan.points[i]; point.vector3 += sliderDiff; if(editMode.snapFloorplanToGrid) { Vector3 snappedPoint = point.vector3; snappedPoint.x -= snappedPoint.x % editMode.floorplanGridSize; snappedPoint.z -= snappedPoint.z % editMode.floorplanGridSize; point.vector3 = snappedPoint; } } } } } //core gui for(int c = 0; c < numberOfCores; c++) { // Undo.SetSnapshotTarget(plan, "Core Node Moved"); Rect coreOutline = plan.cores[c]; Vector3 coreLeft = new Vector3(coreOutline.xMin, 0, (coreOutline.yMin + coreOutline.yMax)/2); Vector3 coreRight = new Vector3(coreOutline.xMax, 0, (coreOutline.yMin + coreOutline.yMax)/2); Vector3 coreBottom = new Vector3((coreOutline.xMin + coreOutline.xMax) / 2, 0, coreOutline.yMin); Vector3 coreTop = new Vector3((coreOutline.xMin + coreOutline.xMax) / 2, 0, coreOutline.yMax); Vector3 newCoreLeft = Handles.Slider(coreLeft + position, Vector3.left, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f); Vector3 newCoreRight = Handles.Slider(coreRight + position, Vector3.right, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f); Vector3 newCoreBottom = Handles.Slider(coreBottom + position, Vector3.back, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f); Vector3 newCoreTop = Handles.Slider(coreTop + position, Vector3.forward, HandleUtility.GetHandleSize(coreLeft) * 0.666f, Handles.ArrowCap, 0.0f); newCoreLeft -= position; newCoreRight -= position; newCoreBottom -= position; newCoreTop -= position; if (coreLeft != newCoreLeft) coreOutline.xMin = Mathf.Min(newCoreLeft.x, coreOutline.xMax - 1.0f); if (coreRight != newCoreRight) coreOutline.xMax = Mathf.Max(newCoreRight.x, coreOutline.xMin + 1.0f); if (coreBottom != newCoreBottom) coreOutline.yMin = Mathf.Min(newCoreBottom.z, coreOutline.yMax - 1.0f); if (coreTop != newCoreTop) coreOutline.yMax = Mathf.Max(newCoreTop.z, coreOutline.yMin + 1.0f); plan.cores[c] = coreOutline; } break; case BuildrEditMode.modes.addNewVolume: Vector3 basePoint = mousePlanePoint; Vector3 width = Vector3.right * 10; Vector3 height = Vector3.forward * 10; Vector3[] verts = new Vector3[4] { basePoint - width - height, basePoint + width - height, basePoint + width + height, basePoint + height - width }; Handles.DrawSolidRectangleWithOutline(verts, new Color(0.2f, 0.4f, 0.9f, 0.5f), new Color(0.1f, 0.2f, 1.0f, 0.85f)); Handles.Label(mousePlanePoint, "Click to place a new volume"); if (Handles.Button(basePoint, Quaternion.identity, 0, 10, Handles.CircleCap)) { // Undo.RegisterUndo(plan.GetUndoObjects(), "Add new volume"); plan.AddVolume(verts, -position); editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); } break; case BuildrEditMode.modes.addNewVolumeByDraw: if (editMode.startVolumeDraw == Vector3.zero) { Handles.Label(mousePlanePoint, "Click to select the start point of this volume"); if (Handles.Button(mousePlanePoint, Quaternion.identity, handleSize * 0.1f, handleSize * 0.1f, Handles.CircleCap)) { editMode.startVolumeDraw = mousePlanePoint; } } else { Vector3 baseDrawPoint = editMode.startVolumeDraw; Vector3 finishDrawPoint = mousePlanePoint; Vector3[] drawVerts = new Vector3[4]; drawVerts[0] = new Vector3(baseDrawPoint.x, 0, baseDrawPoint.z); drawVerts[1] = new Vector3(finishDrawPoint.x, 0, baseDrawPoint.z); drawVerts[2] = new Vector3(finishDrawPoint.x, 0, finishDrawPoint.z); drawVerts[3] = new Vector3(baseDrawPoint.x, 0, finishDrawPoint.z); Handles.DrawSolidRectangleWithOutline(drawVerts, new Color(0.2f, 0.4f, 0.9f, 0.5f), new Color(0.1f, 0.2f, 1.0f, 0.85f)); Handles.Label(mousePlanePoint, "Click to finish and add a new volume"); if (Handles.Button(mousePlanePoint, Quaternion.identity, 0, 10, Handles.CircleCap)) { // Undo.RegisterUndo(plan.GetUndoObjects(), "Add new volume"); plan.AddVolume(drawVerts, -position); editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); } } break; case BuildrEditMode.modes.addNewVolumeByPoints: int numberOfDrawnPoints = editMode.volumeDrawPoints.Count; bool allowNewPoint = true; for (int p = 0; p < numberOfDrawnPoints; p++) { Vector3 point = editMode.volumeDrawPoints[p]; if (p == 0 && Vector3.Distance(point, mousePlanePoint) < 3 && numberOfDrawnPoints >= 3) { allowNewPoint = false;//hovering over the first point - don't add a new point - ready to complete the volume plan Handles.color = Color.green; } Vector3 lookDirection = -(point - Camera.current.transform.position); int p2 = (p + 1) % numberOfDrawnPoints; if (p < numberOfDrawnPoints - 1 || !allowNewPoint)//don't draw last line Handles.DrawLine(point, editMode.volumeDrawPoints[p2]); float pointhandleSize = HandleUtility.GetHandleSize(point); if (Handles.Button(point, Quaternion.LookRotation(lookDirection), pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap)) { if (p == 0 && numberOfDrawnPoints >= 3) { plan.AddVolume(editMode.volumeDrawPoints.ToArray(), -position); editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); GUI.changed = true; return; } } } if (allowNewPoint) { bool isLegal = true; if (numberOfDrawnPoints >= 1) { Vector2z newPoint = new Vector2z(mousePlanePoint); Vector2z lastPoint = new Vector2z(editMode.volumeDrawPoints[numberOfDrawnPoints - 1]); for (int op = 0; op < numberOfDrawnPoints - 1; op++)//don't do the final line { int op2 = (op + 1) % numberOfDrawnPoints; if (BuildrUtils.FastLineIntersection(newPoint, lastPoint, new Vector2z(editMode.volumeDrawPoints[op]), new Vector2z(editMode.volumeDrawPoints[op2]))) isLegal = false; } for (int v = 0; v < numberOfVolumes; v++) { BuildrVolume volume = plan.volumes[v]; int volumeSize = volume.Count; for (int l = 0; l < volumeSize; l++) { int vp1 = l; int vp2 = (l + 1) % volumeSize; Vector2z v2zPos = new Vector2z(position); Vector2z p1 = newPoint - v2zPos; Vector2z p2 = lastPoint - v2zPos; Vector2z p3 = plan.points[volume.points[vp1]]; Vector2z p4 = plan.points[volume.points[vp2]]; if (BuildrUtils.FastLineIntersection(p1, p2, p3, p4)) isLegal = false; } } Handles.Label(mousePlanePoint, "Click to add another point to the volume wall"); if (!isLegal) Handles.color = Color.red; Handles.DrawLine(lastPoint.vector3, newPoint.vector3); } else { Handles.Label(mousePlanePoint, "Click to add the first point in this volume wall"); } Handles.color = Color.white; if (Handles.Button(mousePlanePoint, mouseLookDirection, 0, 10, Handles.CircleCap)) { if (isLegal) { // Undo.RegisterUndo(plan.GetUndoObjects(), "Add new wall line for new volume"); editMode.volumeDrawPoints.Add(mousePlanePoint); EditorUtility.SetDirty(plan); } else { EditorUtility.DisplayDialog("Error", "Wall lines cannot intersect other wall lines", "ok, sorry"); } } } else { Handles.Label(mousePlanePoint, "Click to complete the volume wall plan"); } break; case BuildrEditMode.modes.removeVolume: for (int v = 0; v < numberOfVolumes; v++) { BuildrVolume volume = plan.volumes[v]; int volumeSize = volume.Count; Vector3 centerPoint = Vector3.zero; for (int l = 0; l < volumeSize; l++) { centerPoint += plan.points[volume.points[l]].vector3; } centerPoint /= volumeSize; centerPoint += position; Handles.color = Color.red; float centerPointHandleSize = HandleUtility.GetHandleSize(centerPoint); if (Handles.Button(centerPoint, Quaternion.identity, centerPointHandleSize * 0.1f, centerPointHandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterUndo(plan.GetUndoObjects(), "Remove volume"); // Undo.RegisterSceneUndo("Remove Volume"); plan.RemoveVolume(volume); numberOfVolumes--; v--; editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); } } break; case BuildrEditMode.modes.mergeVolumes: List<int> usedPointsA = new List<int>(); List<int> usedPointsB = new List<int>(); for (int v = 0; v < numberOfVolumes; v++) { BuildrVolume volume = plan.volumes[v]; int volumeSize = volume.Count; for (int p = 0; p < volumeSize; p++) { int a = volume.points[p]; int b = volume.points[(p + 1) % volumeSize]; bool alreadyDrawn = false; foreach (int pa in usedPointsA) { if (pa == a || pa == b) { int pb = usedPointsB[usedPointsA.IndexOf(pa)]; if (pb == a || pb == b) { alreadyDrawn = true; break; } } } if (!alreadyDrawn) { usedPointsA.Add(a); usedPointsA.Add(b); usedPointsB.Add(b); usedPointsB.Add(a); int otherV = plan.GetConnectingVolumeIndex(v, a, b); if (otherV == -1) continue;//it's not connected to another volume vertA = plan.points[a].vector3 + position; vertB = plan.points[b].vector3 + position; Vector3 diff = vertA - vertB; Vector3 facadeDirection = Vector3.Cross(diff, Vector3.up).normalized; Vector3 midPoint = Vector3.Lerp(vertA, vertB, 0.5f); float mergeHandleSize = HandleUtility.GetHandleSize(midPoint) * 0.1f; Vector3 outPointA = midPoint + (facadeDirection * mergeHandleSize * 6); Vector3 outPointB = midPoint - (facadeDirection * mergeHandleSize * 6); Handles.ArrowCap(0, outPointA, Quaternion.LookRotation(-facadeDirection), mergeHandleSize * 4); Handles.ArrowCap(0, outPointB, Quaternion.LookRotation(facadeDirection), mergeHandleSize * 4); GUIStyle pointLabelStyle = new GUIStyle(); pointLabelStyle.normal.textColor = Color.white; pointLabelStyle.fontStyle = FontStyle.Bold; pointLabelStyle.alignment = TextAnchor.MiddleCenter; pointLabelStyle.fixedWidth = 50.0f; Handles.Label(midPoint + Vector3.up * mergeHandleSize * 3, "Merge", pointLabelStyle); if (Handles.Button(midPoint, Quaternion.identity, mergeHandleSize, mergeHandleSize, Handles.DotCap)) { // Undo.RegisterSceneUndo("Merge Volume"); int otherVolume = plan.GetConnectingVolumeIndex(v, a, b); plan.MergeVolumes(v, otherVolume); numberOfVolumes--; editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); } } } } break; //SUB VOLUME FUNCTIONS case BuildrEditMode.modes.splitwall: SceneView.focusedWindow.wantsMouseMove = true; float pointDistance = 999; int wallIndex = -1; int volumeIndex = -1; Vector3 closestPoint = Vector3.zero; Vector3 usePoint = Vector3.zero; vertA = Vector3.zero; vertB = Vector3.zero; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volumeLinks = plan.volumes[s]; int volumeSize = volumeLinks.Count; for (int l = 0; l < volumeSize; l++) { Vector3[] wallVectors = plan.GetWallVectors(s, l); closestPoint = BuildrUtils.ClosestPointOnLine(wallVectors[0] + position, wallVectors[1] + position, mousePlanePoint); float thisDist = Vector3.Distance(closestPoint, mousePlanePoint); if (thisDist < pointDistance) { wallIndex = l; volumeIndex = s; vertA = wallVectors[0]; vertB = wallVectors[1]; usePoint = closestPoint; pointDistance = thisDist; editMode.selectedPoints.Clear(); } Handles.color = Color.white; float wallHandleSize = HandleUtility.GetHandleSize(wallVectors[0] + position); Handles.DotCap(0, wallVectors[0] + position, Quaternion.identity, wallHandleSize * 0.05f); } } if (wallIndex != -1 && pointDistance < 5 && volumeIndex != -1) { float pointHandleSize = HandleUtility.GetHandleSize(usePoint); if (Handles.Button(usePoint, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterUndo(plan.GetUndoObjects(), "Split Wall"); int newPointID = plan.AddWallPoint(usePoint - position, wallIndex, volumeIndex); editMode.selectedPoints.Clear(); editMode.selectedPoints.Add(newPointID); editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); } Handles.color = Color.white; GUIStyle widthStyle = new GUIStyle(); widthStyle.normal.textColor = Color.white; widthStyle.alignment = TextAnchor.MiddleCenter; widthStyle.fixedWidth = 50.0f; Vector3 facadeDirection = Vector3.Cross((vertA - vertB), Vector3.up).normalized; float wallWidthA = Vector3.Distance(vertA, usePoint); Vector3 labelPosA = (vertA + usePoint) * 0.5f + facadeDirection; Handles.Label(labelPosA, wallWidthA.ToString("F2") + "m", widthStyle); if (wallWidthA > 3)//draw guidelines { float gapSpace = (pointHandleSize * 0.5f) / wallWidthA; Vector3 lineStopA = Vector3.Lerp(vertA, usePoint, (0.5f - gapSpace)) + facadeDirection; Vector3 lineStopB = Vector3.Lerp(vertA, usePoint, (0.5f + gapSpace)) + facadeDirection; Handles.DrawLine(vertA + facadeDirection, lineStopA); Handles.DrawLine(vertA + facadeDirection, vertA); Handles.DrawLine(usePoint + facadeDirection, lineStopB); Handles.DrawLine(usePoint + facadeDirection, usePoint); } float wallWidthB = Vector3.Distance(usePoint, vertB); Vector3 labelPosB = (usePoint + vertB) * 0.5f + facadeDirection; Handles.Label(labelPosB, wallWidthB.ToString("F2") + "m", widthStyle); if (wallWidthB > 3)//draw guidelines { float gapSpace = (pointHandleSize * 0.5f) / wallWidthB; Vector3 lineStopA = Vector3.Lerp(vertB, usePoint, (0.5f - gapSpace)) + facadeDirection; Vector3 lineStopB = Vector3.Lerp(vertB, usePoint, (0.5f + gapSpace)) + facadeDirection; Handles.DrawLine(vertB + facadeDirection, lineStopA); Handles.DrawLine(vertB + facadeDirection, vertB); Handles.DrawLine(usePoint + facadeDirection, lineStopB); Handles.DrawLine(usePoint + facadeDirection, usePoint); } } Handles.color = Color.white; break; case BuildrEditMode.modes.removewall: int index = 0; foreach (Vector2z point in plan.points) { Handles.color = Color.white; Vector3 pointPos = point.vector3 + position; float pointHandleSize = HandleUtility.GetHandleSize(pointPos); if (Handles.Button(pointPos, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterSceneUndo("Delete Wall Point"); plan.RemovePoint(index); editMode.SetMode(BuildrEditMode.modes.floorplan); break; } index++; } break; case BuildrEditMode.modes.extrudewallselect: Handles.color = Color.blue; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int volumeSize = volume.Count; for (int l = 0; l < volumeSize; l++) { int a = volume.points[l]; int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0]; if (plan.GetConnectingVolumeIndex(s, a, b) == -1)//if the volume wall has not been connected to two volumes yet... { Vector3[] pIndexes = plan.GetWallVectors(s, l); Vector3 pA = pIndexes[0]; Vector3 pB = pIndexes[1]; Vector3 pC = (pA + pB) / 2 + position; float pointHandleSize = HandleUtility.GetHandleSize(pC); if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterSceneUndo("Extrude wall"); int wallIndexA = l; int newPointAIndex = plan.AddWallPoint(pA, wallIndexA, s); int wallIndexB = l + 1; int newPointBIndex = plan.AddWallPoint(pB, wallIndexB, s); editMode.SetMode(BuildrEditMode.modes.floorplan); editMode.selectedPoints.Clear(); editMode.selectedPoints.Add(newPointAIndex); editMode.selectedPoints.Add(newPointBIndex); break; } } } } Handles.color = Color.white; break; case BuildrEditMode.modes.addVolumeByPoint: Handles.color = Color.blue; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int volumeSize = volume.Count; for (int l = 0; l < volumeSize; l++) { int a = volume.points[l]; int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0]; if (plan.GetConnectingVolumeIndex(s, a, b) == -1)//if the volume wall has not been connected to two volumes yet... { Vector3[] pointVectors = plan.GetWallVectors(s, l); Vector3 pA = pointVectors[0]; Vector3 pB = pointVectors[1]; Vector3 pC = (pA + pB) / 2 + position; float pointHandleSize = HandleUtility.GetHandleSize(pC); if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap)) { Vector2z[] newPoints = new Vector2z[1]; float pointDist = Vector3.Distance(pA, pB); Vector3 newPointPos = Vector3.Cross(pA - pB, Vector3.up).normalized * pointDist; newPoints[0] = new Vector2z(pC + newPointPos); int indexa, indexb; indexa = volume.points[l]; if (l < volumeSize - 1) indexb = volume.points[l + 1]; else indexb = volume.points[0]; plan.AddVolume(indexa, indexb, newPoints); editMode.SetMode(BuildrEditMode.modes.floorplan); break; } } } } Handles.color = Color.white; break; case BuildrEditMode.modes.addVolumeByWall: Handles.color = Color.blue; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; int volumeSize = volume.Count; for (int l = 0; l < volumeSize; l++) { int a = volume.points[l]; int b = (l < volume.points.Count - 1) ? volume.points[l + 1] : volume.points[0]; if (plan.GetConnectingVolumeIndex(s, a, b) == -1) { Vector3[] pIndexes = plan.GetWallVectors(s, l); Vector3 pA = pIndexes[0]; Vector3 pB = pIndexes[1]; Vector3 pC = (pA + pB) / 2 + position; float pointHandleSize = HandleUtility.GetHandleSize(pC); if (Handles.Button(pC, Quaternion.identity, pointHandleSize * 0.1f, pointHandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterSceneUndo("Add volume by wall"); Vector2z[] newPoints = new Vector2z[2]; float pointDist = Vector3.Distance(pA, pB); Vector3 newPointPos = Vector3.Cross(pA - pB, Vector3.up).normalized * pointDist; newPoints[0] = new Vector2z(pA + newPointPos); newPoints[1] = new Vector2z(pB + newPointPos); int indexa, indexb; indexa = volume.points[l]; if (l < volumeSize - 1) indexb = volume.points[l + 1]; else indexb = volume.points[0]; plan.AddVolume(indexa, indexb, newPoints); editMode.SetMode(BuildrEditMode.modes.floorplan); break; } } } } Handles.color = Color.white; break; case BuildrEditMode.modes.addPointToVolume: numberOfPoints = plan.numberOfPoints; if (editMode.selectedPoint == -1) { for (int p = 0; p < numberOfPoints; p++) { Vector2z point = plan.points[p]; Handles.color = Color.white; Vector3 pointPos = point.vector3 + position; float pointhandleSize = HandleUtility.GetHandleSize(pointPos); if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterSceneUndo("Select Wall Point"); editMode.selectedPoint = p; break; } } } else { selectedPoint = editMode.selectedPoint; Vector2z startPoint = plan.points[selectedPoint]; Vector2z endPoint = new Vector2z(mousePlanePoint - position); bool isLegal = true; for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; if (!volume.Contains(selectedPoint)) continue; int volumeSize = volume.Count; for (int l = 0; l < volumeSize; l++) { int a = volume.points[l]; int b = volume.points[(l + 1) % volumeSize]; if (a == selectedPoint || b == selectedPoint) continue; if (BuildrUtils.FastLineIntersection(startPoint, endPoint, plan.points[a], plan.points[b])) isLegal = false; } } Handles.color = isLegal ? Color.white : Color.red; Handles.DrawLine(startPoint.vector3 + position, endPoint.vector3 + position); } break; case BuildrEditMode.modes.splitVolume: numberOfPoints = plan.numberOfPoints; selectedPoint = editMode.selectedPoint; if (selectedPoint == -1) { for (int p = 0; p < numberOfPoints; p++) { Vector2z point = plan.points[p]; Handles.color = Color.white; Vector3 pointPos = point.vector3 + position; float pointhandleSize = HandleUtility.GetHandleSize(pointPos); if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterSceneUndo("Select Wall Point"); editMode.selectedPoint = p; break; } } } else { for (int s = 0; s < numberOfVolumes; s++) { BuildrVolume volume = plan.volumes[s]; if (!volume.Contains(selectedPoint)) continue; int volumeSize = volume.Count; for (int l = 0; l < volumeSize; l++) { int o = volume.points[l]; int a = selectedPoint; int selectedVolumePoint = volume.IndexOf(selectedPoint); int b = volume.points[(selectedVolumePoint + 1) % volumeSize]; int volb = (selectedVolumePoint - 1) % volumeSize; if (volb == -1) volb = volumeSize - 1; int c = volume.points[volb]; if (o == a || o == b || o == c) continue; Vector3 pointPos = plan.points[o].vector3 + position; bool isLegal = true; for (int j = 0; j < volumeSize; j++) { int ob = volume.points[j]; int oc = volume.points[(j + 1) % volumeSize]; if (ob == selectedPoint || oc == selectedPoint || ob == o || oc == o) continue; if (BuildrUtils.FastLineIntersection(plan.points[selectedPoint], plan.points[o], plan.points[ob], plan.points[oc])) isLegal = false; } Vector2z pA = plan.points[a]; Vector2z pB = plan.points[b]; Vector2z pC = plan.points[c]; Vector2z pO = plan.points[o]; float startAng, endAng, mouseAng, ang; Vector3 cross; Vector2z diff; diff = pC - pA; ang = Vector2.Angle(Vector2.up, diff.vector2); cross = Vector3.Cross(Vector3.forward, diff.vector3); startAng = (cross.y > 0) ? ang : 360 - ang; diff = pB - pA; ang = Vector2.Angle(Vector2.up, diff.vector2); cross = Vector3.Cross(Vector3.forward, diff.vector3); endAng = (cross.y > 0) ? ang : 360 - ang; diff = pO - pA; ang = Vector2.Angle(Vector2.up, diff.vector2); cross = Vector3.Cross(Vector3.forward, diff.vector3); mouseAng = (cross.y > 0) ? ang : 360 - ang; mouseAng = (360 + (mouseAng % 360)) % 360; startAng = (3600000 + startAng) % 360; endAng = (3600000 + endAng) % 360; bool isBetween = false; if (startAng < endAng) isBetween = startAng <= mouseAng && mouseAng <= endAng; else isBetween = startAng <= mouseAng || mouseAng <= endAng; if (isLegal && !isBetween) isLegal = false; if (isLegal) { Handles.color = Color.white; float pointhandleSize = HandleUtility.GetHandleSize(pointPos); if (Handles.Button(pointPos, Quaternion.identity, pointhandleSize * 0.1f, pointhandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterSceneUndo("Split Volume"); plan.SplitVolume(s, a, o); editMode.selectedPoint = -1; editMode.SetMode(BuildrEditMode.modes.floorplan); return; } Handles.color = new Color(1, 0, 0, 0.25f); Handles.DrawLine(plan.points[selectedPoint].vector3 + position, plan.points[o].vector3 + position); } } } } break; case BuildrEditMode.modes.addNewCore: SceneView.focusedWindow.wantsMouseMove = true; Vector3 coreBasePoint = mousePlanePoint; Vector3 coreWidth = Vector3.right * 2.5f; Vector3 coreHeight = Vector3.forward * 2.5f; Vector3[] coreVerts = new Vector3[4] { coreBasePoint - coreWidth - coreHeight, coreBasePoint + coreWidth - coreHeight, coreBasePoint + coreWidth + coreHeight, coreBasePoint + coreHeight - coreWidth }; Color newCoreColour = BuildrColours.RED; newCoreColour.a = 0.5f; Handles.DrawSolidRectangleWithOutline(coreVerts, newCoreColour, BuildrColours.YELLOW); Handles.Label(mousePlanePoint, "Click to place a new core"); if (Handles.Button(coreBasePoint, Quaternion.identity, 0, 10, Handles.CircleCap)) { // Undo.RegisterSceneUndo("Add new core"); Vector3 coreBase = coreBasePoint - position; Rect newCoreRect = new Rect(coreBase.x - 2.5f, coreBase.z - 2.5f, 5.0f, 5.0f); plan.cores.Add(newCoreRect); editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); } break; case BuildrEditMode.modes.removeCore: for (int c = 0; c < numberOfCores; c++) { Rect core = plan.cores[c]; Vector3 centerPoint = new Vector3(core.center.x, 0, core.center.y) + position; Handles.color = Color.red; float centerPointHandleSize = HandleUtility.GetHandleSize(centerPoint); if (Handles.Button(centerPoint, Quaternion.identity, centerPointHandleSize * 0.1f, centerPointHandleSize * 0.1f, Handles.DotCap)) { // Undo.RegisterSceneUndo("Remove Core"); plan.cores.RemoveAt(c); numberOfCores--; c--; editMode.SetMode(BuildrEditMode.modes.floorplan); EditorUtility.SetDirty(plan); } } break; } bool clickedOutside = false; if (Event.current.isMouse) { RaycastHit hitInfo; clickedOutside = true; if (Physics.Raycast(ray, out hitInfo)) { if (hitInfo.collider.gameObject == editMode.gameObject) clickedOutside = false; } } if (clickedOutside) editMode.selectedPoints.Clear(); if (GUI.changed) { plan.CheckPlan(); EditorUtility.SetDirty(editMode); EditorUtility.SetDirty(plan); editMode.UpdateRender(); } }
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; //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); 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 } textureSize = textureWidth * textureWidth; colourArray = new Color32[textureSize]; //TestRectColours();//this test paints all the facades with rainbow colours - real pretty BuildTextures(); Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true); packedTexture.filterMode = FilterMode.Bilinear; packedTexture.SetPixels32(colourArray); packedTexture.Apply(true, false); if (data.OneDrawCallTexture != null) { Object.DestroyImmediate(data.OneDrawCallTexture); } data.OneDrawCallTexture = packedTexture; data.OneDrawCallTexture.name = "One Draw Call Texture"; int numberOfRoofTextures = roofTextures.Count - 1; List <Rect> facadeTexturePositions = new List <Rect>(packedTexturePositions); Debug.Log(numberOfRoofTextures); facadeTexturePositions.RemoveRange(packedTexturePositions.Count - numberOfRoofTextures, numberOfRoofTextures); BuildrBuilding.Build(mesh, data, facadeTexturePositions.ToArray()); data = null; mesh = null; textures = null; System.GC.Collect(); }
public static void InspectorGUI(BuildrEditMode editMode, BuildrPlan plan) { EditorGUILayout.Space(); Undo.RecordObject(plan, "Floorplan Modified"); editMode.showDimensionLines = EditorGUILayout.Toggle("Show Wall Dimensions", editMode.showDimensionLines); if (editMode.mode != BuildrEditMode.modes.floorplan) { EditorGUILayout.LabelField("Current Mode: " + editMode.mode.ToString()); if (GUILayout.Button("Cancel")) { editMode.SetMode(BuildrEditMode.modes.floorplan); UpdateGUI(); } } EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Snap to Grid", GUILayout.Width(100)); bool editModesnapFloorplanToGrid = EditorGUILayout.Toggle(editMode.snapFloorplanToGrid); if(editModesnapFloorplanToGrid != editMode.snapFloorplanToGrid) { //Snapping modified editMode.snapFloorplanToGrid = editModesnapFloorplanToGrid; if(editModesnapFloorplanToGrid) { int numberOfPoints = plan.points.Count; for (int i = 0; i < numberOfPoints; i++) { Vector2z point = plan.points[i]; Vector3 snappedPoint = point.vector3; snappedPoint.x -= snappedPoint.x % editMode.floorplanGridSize; snappedPoint.z -= snappedPoint.z % editMode.floorplanGridSize; point.vector3 = snappedPoint; } } } EditorGUI.BeginDisabledGroup(!editMode.snapFloorplanToGrid); EditorGUILayout.LabelField("Grid Size", GUILayout.Width(100)); editMode.floorplanGridSize = EditorGUILayout.FloatField(editMode.floorplanGridSize); EditorGUILayout.LabelField("metres", GUILayout.Width(60)); EditorGUI.EndDisabledGroup(); EditorGUILayout.EndHorizontal(); if(GUILayout.Button("Recenter Floorplan to Origin")) { Vector3 currentCenter = Vector3.zero; int numberOfPoints = plan.points.Count; for (int i = 0; i < numberOfPoints; i++) currentCenter += plan.points[i].vector3; currentCenter *= (1.0f / numberOfPoints); for (int i = 0; i < numberOfPoints; i++) plan.points[i].vector3 += -currentCenter; int numberOfCores = plan.cores.Count; for(int i = 0; i < numberOfCores; i++) { Rect core = plan.cores[i]; plan.cores[i] = new Rect(core.xMin - currentCenter.x, core.yMin - currentCenter.z, core.width, core.height); } } if (GUILayout.Button("Recenter Origin to Floorplan")) { Vector3 currentCenter = Vector3.zero; int numberOfPoints = plan.points.Count; for (int i = 0; i < numberOfPoints; i++) currentCenter += plan.points[i].vector3; currentCenter *= (1.0f / numberOfPoints); for (int i = 0; i < numberOfPoints; i++) plan.points[i].vector3 += -currentCenter; int numberOfCores = plan.cores.Count; for (int i = 0; i < numberOfCores; i++) { Rect core = plan.cores[i]; plan.cores[i] = new Rect(core.xMin - currentCenter.x, core.yMin - currentCenter.z, core.width, core.height); } editMode.transform.position += currentCenter; } EditorGUILayout.LabelField("New Volume Plans"); if (GUILayout.Button("Add New Volume Square")) { editMode.SetMode(BuildrEditMode.modes.addNewVolume); UpdateGUI(); } if (GUILayout.Button("Add New Volume By Drawing Rectangle")) { editMode.SetMode(BuildrEditMode.modes.addNewVolumeByDraw); UpdateGUI(); } if (GUILayout.Button("Add New Volume By Drawing Points")) { editMode.SetMode(BuildrEditMode.modes.addNewVolumeByPoints); UpdateGUI(); } if (GUILayout.Button("Add New Volume By Extending Wall")) { editMode.SetMode(BuildrEditMode.modes.addVolumeByWall); UpdateGUI(); } if (GUILayout.Button("Merge Volumes")) { editMode.SetMode(BuildrEditMode.modes.mergeVolumes); UpdateGUI(); } if (GUILayout.Button("Split Volumes")) { editMode.SetMode(BuildrEditMode.modes.splitVolume); UpdateGUI(); } if (GUILayout.Button("Remove Volume")) { editMode.SetMode(BuildrEditMode.modes.removeVolume); UpdateGUI(); } EditorGUILayout.LabelField("Volume Plan Modification"); if (GUILayout.Button("Split Wall")) { editMode.SetMode(BuildrEditMode.modes.splitwall); UpdateGUI(); } if (GUILayout.Button("Add Point To Volume")) { editMode.SetMode(BuildrEditMode.modes.addPointToVolume); UpdateGUI(); } if (GUILayout.Button("Remove Wall Point")) { editMode.SetMode(BuildrEditMode.modes.removewall); UpdateGUI(); } if (GUILayout.Button("Extrude Wall")) { editMode.SetMode(BuildrEditMode.modes.extrudewallselect); UpdateGUI(); } EditorGUILayout.LabelField("Core Modification"); if (GUILayout.Button("Add Building Core")) { editMode.SetMode(BuildrEditMode.modes.addNewCore); UpdateGUI(); } if (GUILayout.Button("Remove Building Core")) { editMode.SetMode(BuildrEditMode.modes.removeCore); UpdateGUI(); } }
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 void Init() { plan = CreateInstance<BuildrPlan>(); rgen = new RandomGen((useSeed) ? (uint)_seed : (uint)Random.Range(0, int.MaxValue)); }