public void CalculateSubmeshes(SubmeshLibrary submeshLibrary) { for (int p = 0; p < numberOfPoints; p++) { Facade facadeDesign = GetFacade(p); if (facadeDesign != null) { submeshLibrary.Add(facadeDesign.stringCourseSurface); List <WallSection> usedWallSections = facadeDesign.usedWallSections; int sectionCount = usedWallSections.Count; for (int u = 0; u < sectionCount; u++) { submeshLibrary.Add(usedWallSections[u]); } } if (this[p].isGabled && this[p].gableStyle != null) { submeshLibrary.Add(this[p].gableStyle.surface); } } submeshLibrary.Add(roof.mainSurface); submeshLibrary.Add(roof.wallSurface); submeshLibrary.Add(roof.floorSurface); submeshLibrary.Add(roof.wallSection); submeshLibrary.Add(_undersideSurafce); }
public void CalculateSubmeshes(SubmeshLibrary submeshLibrary) { for (int v = 0; v < numberOfVolumes; v++) { IVolume volume = this[v]; int numberOfPoints = volume.numberOfPoints; for (int p = 0; p < numberOfPoints; p++) { Facade facadeDesign = volume.GetFacade(p); if (facadeDesign != null) { submeshLibrary.Add(facadeDesign.stringCourseSurface); List <WallSection> usedWallSections = facadeDesign.usedWallSections; int sectionCount = usedWallSections.Count; for (int u = 0; u < sectionCount; u++) { submeshLibrary.Add(usedWallSections[u]); } } if (volume[p].isGabled && volume[p].gableStyle != null) { submeshLibrary.Add(volume[p].gableStyle.surface); } } submeshLibrary.Add(volume.roof.mainSurface); submeshLibrary.Add(volume.roof.wallSurface); submeshLibrary.Add(volume.roof.floorSurface); submeshLibrary.Add(volume.roof.wallSection); } }
private void OnEnable() { _portal = (Portal)target; _plane = Primitives.Plane(10); // _mat = AssetDatabase.LoadAssetAtPath<Material>("Assets/BuildR2/Materials/Blueprint.mat"); if (_submeshLibrary == null) { _submeshLibrary = new SubmeshLibrary(); } _submeshLibrary.Clear(); _submeshLibrary.Add(_portal); _portal.UpdatePreviewMesh(_submeshLibrary); }
public static void Portal(ref BuildRMesh dynamicMesh, Portal portal, Vector2 size, Vector3 offset, bool interior = true, SubmeshLibrary submeshLibrary = null) { if (submeshLibrary == null) { submeshLibrary = new SubmeshLibrary(); submeshLibrary.Add(portal); } Division root = portal.root; List <Panel> processNodes = new List <Panel>(); Dictionary <Panel, Panel[]> dataDic = new Dictionary <Panel, Panel[]>(); List <Panel> data = new List <Panel>(); Panel rootPanel = new Panel(root, new Rect(0, 0, size.x, size.y), 0); processNodes.Add(rootPanel); float totalDepth = 0; while (processNodes.Count > 0) { Panel current = processNodes[0]; Division division = current.division; List <Division> children = division.GetChildren; int childCount = children.Count; data.Add(current);//dump processed node into data. dataDic.Add(current, new Panel[childCount]); if (current.recess > totalDepth) { totalDepth = current.recess; } float childRatio = 0; for (int c = 0; c < childCount; c++) { childRatio += children[c].size; } for (int c = 0; c < childCount; c++) { Division child = children[c]; Rect newPanelrect = current.rect; float ratio = children[c].size / childRatio; if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal) { newPanelrect.width = Mathf.Max(newPanelrect.width - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio; newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2, 0); if (c > 0) { Panel lastPanel = processNodes[processNodes.Count - 1]; newPanelrect.x = lastPanel.rect.xMax + division.frame; } else { newPanelrect.x = current.rect.xMin + division.frame; } newPanelrect.y = current.rect.yMin + division.frame; } else { newPanelrect.width = Mathf.Max(newPanelrect.width - division.frame * 2, 0); newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio; if (c > 0) { Panel lastPanel = processNodes[processNodes.Count - 1]; newPanelrect.y = lastPanel.rect.y + lastPanel.rect.height + division.frame; } else { newPanelrect.y = current.rect.yMin + division.frame; } newPanelrect.x = current.rect.xMin + division.frame; } Panel childPanel = new Panel(child, newPanelrect, current.recess + division.recess); dataDic[current][c] = childPanel; processNodes.Add(childPanel); } processNodes.RemoveAt(0); } int dataCount = data.Count; Vector3 norm = Vector3.back; Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); Vector4 tangentForward = BuildRMesh.CalculateTangent(Vector3.forward); Vector4 tangentBack = BuildRMesh.CalculateTangent(Vector3.back); Vector4 tangentInvert = BuildRMesh.CalculateTangent(Vector3.left); Vector3 useOffset = size * 0.5f; useOffset += offset; useOffset.y = -useOffset.y;//inverse - UX resaons for (int i = 0; i < dataCount; i++) { Panel panel = data[i]; Division division = panel.division; Rect panelRect = panel.rect; if (panelRect.width == 0 || panelRect.height == 0) { continue; } Vector3 v0 = new Vector3(panelRect.xMin, -panelRect.yMin, panel.recess) - useOffset; Vector3 v1 = new Vector3(panelRect.xMax, -panelRect.yMin, panel.recess) - useOffset; Vector3 v2 = new Vector3(panelRect.xMin, -panelRect.yMax, panel.recess) - useOffset; Vector3 v3 = new Vector3(panelRect.xMax, -panelRect.yMax, panel.recess) - useOffset; Surface usedSurface = GetSurface(portal, division); int useSubmesh = submeshLibrary.SubmeshAdd(usedSurface); // int useSubmesh = usedSurface != null ? Array.IndexOf(usedSurfaces, usedSurface) : 0; Vector2 uv0 = CalculateUV(usedSurface, v0); Vector2 uv1 = CalculateUV(usedSurface, v1); Vector2 uv2 = CalculateUV(usedSurface, v2); Vector2 uv3 = CalculateUV(usedSurface, v3); if (!division.hasChildren)//simple panel { Vector3[] verts = { v0, v1, v2, v3 }; Vector2[] uvs = { uv0, uv1, uv2, uv3 }; int[] tris = { 0, 1, 2, 1, 3, 2 }; Vector3[] norms = { norm, norm, norm, norm }; Vector4[] tangents = { tangent, tangent, tangent, tangent }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); verts = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset }; uvs = new[] { uv1, uv0, uv3, uv2 }; tris = new[] { 0, 2, 1, 1, 2, 3 }; norms = new[] { -norm, -norm, -norm, -norm }; tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); } } else//build a frame { Vector3 v0f = v0 + new Vector3(division.frame, -division.frame, 0); Vector3 v1f = v1 + new Vector3(-division.frame, -division.frame, 0); Vector3 v2f = v2 + new Vector3(division.frame, division.frame, 0); Vector3 v3f = v3 + new Vector3(-division.frame, division.frame, 0); Vector3 recessV = Vector3.forward * (division.recess); Vector3 v0r = v0f + recessV; Vector3 v1r = v1f + recessV; Vector3 v2r = v2f + recessV; Vector3 v3r = v3f + recessV; Vector2 uv0f = CalculateUV(usedSurface, v0f); Vector2 uv1f = CalculateUV(usedSurface, v1f); Vector2 uv2f = CalculateUV(usedSurface, v2f); Vector2 uv3f = CalculateUV(usedSurface, v3f); // Vector2 uv0r = CalculateUV(usedSurface, v0r); // Vector2 uv1r = CalculateUV(usedSurface, v1r); // Vector2 uv2r = CalculateUV(usedSurface, v2r); // Vector2 uv3r = CalculateUV(usedSurface, v3r); Vector3[] verts = { v0, v1, v2, v3, v0f, v1f, v2f, v3f }; Vector2[] uvs = { uv0, uv1, uv2, uv3, uv0f, uv1f, uv2f, uv3f }; Vector3[] norms = { norm, norm, norm, norm, norm, norm, norm, norm }; Vector4[] tangents = { tangent, tangent, tangent, tangent, tangent, tangent, tangent, tangent }; int[] tris = { 0, 4, 2, 4, 6, 2, //left 0, 1, 4, 1, 5, 4, //top 5, 1, 3, 5, 3, 7, //right 2, 6, 3, 3, 6, 7, //bottom }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); Vector2 uvUp = CalculateUV(usedSurface, new Vector2(0, division.recess)); Vector2 uvRight = CalculateUV(usedSurface, new Vector2(division.recess, 0)); dynamicMesh.AddPlaneComplex(v1f, v0f, v1r, v0r, uv1f, uv0f, uv1f + uvUp, uv0f + uvUp, Vector3.down, tangent, useSubmesh, usedSurface); //top dynamicMesh.AddPlaneComplex(v2f, v3f, v2r, v3r, uv2f, uv3f, uv2f + uvUp, uv3f + uvUp, Vector3.up, tangent, useSubmesh, usedSurface); //bottom dynamicMesh.AddPlaneComplex(v0f, v2f, v0r, v2r, uv0f, uv2f, uv0f + uvRight, uv2f + uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //left dynamicMesh.AddPlaneComplex(v3f, v1f, v3r, v1r, uv3f, uv1f, uv3f + uvRight, uv1f + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface); //right if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2); verts = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset, v0f + interiorOffset, v1f + interiorOffset, v2f + interiorOffset, v3f + interiorOffset }; uvs = new [] { uv1, uv0, uv3, uv2, uv1f, uv0f, uv3f, uv2f }; Array.Reverse(tris); norms = new[] { -norm, -norm, -norm, -norm, -norm, -norm, -norm, -norm }; tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); dynamicMesh.AddPlaneComplex(v0f + interiorOffset, v1f + interiorOffset, v0r + interiorOffsetr, v1r + interiorOffsetr, uv0f, uv1f, uv0f + uvUp, uv1f + uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface); //top dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v2f + interiorOffset, v3r + interiorOffsetr, v2r + interiorOffsetr, uv3f, uv2f, uv3f + uvUp, uv2f + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface); //bottom dynamicMesh.AddPlaneComplex(v2f + interiorOffset, v0f + interiorOffset, v2r + interiorOffsetr, v0r + interiorOffsetr, uv2f, uv0f, uv2f + uvRight, uv0f + uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface); //left dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v3f + interiorOffset, v3r + interiorOffsetr, v3r + interiorOffsetr, uv1f, uv3f, uv1f + uvRight, uv3f + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface); //right } List <Division> children = division.GetChildren; int childCount = children.Count; if (childCount > 1 && division.frame > 0) { for (int c = 0; c < childCount - 1; c++) { Panel childPanel = dataDic[panel][c]; if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal) { Vector3 v0d = v0 + new Vector3(childPanel.rect.xMax - panelRect.xMin, -division.frame, 0); Vector3 v1d = v0d + new Vector3(division.frame, 0, 0); Vector3 v2d = v0d + new Vector3(0, -panelRect.height + division.frame * 2, 0); Vector3 v3d = v1d + new Vector3(0, -panelRect.height + division.frame * 2, 0); Vector2 uv0d = CalculateUV(usedSurface, v0d); Vector2 uv1d = CalculateUV(usedSurface, v1d); Vector2 uv2d = CalculateUV(usedSurface, v2d); Vector2 uv3d = CalculateUV(usedSurface, v3d); dynamicMesh.AddPlaneComplex(v1d, v0d, v3d, v2d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v2d, v0d, v2d + recessV, v0d + recessV, uv2d, uv0d, uv2d + uvRight, uv0d + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface); //divider left dynamicMesh.AddPlaneComplex(v1d, v3d, v1d + recessV, v3d + recessV, uv1d, uv3d, uv1d - uvRight, uv3d - uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface); //divider right if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2); dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v1d + interiorOffset, v2d + interiorOffset, v3d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v2d + interiorOffset, v0d + recessV + interiorOffsetr, v2d + recessV + interiorOffsetr, uv0d, uv2d, uv0d + uvRight, uv2d + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface); //divider left dynamicMesh.AddPlaneComplex(v3d + interiorOffset, v1d + interiorOffset, v3d + recessV + interiorOffsetr, v1d + recessV + interiorOffsetr, uv3d, uv1d, uv3d - uvRight, uv1d - uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //divider right } } else { Vector3 v0d = v0 + new Vector3(division.frame, -childPanel.rect.yMax + panelRect.yMin, 0); Vector3 v1d = v0d + new Vector3(0, -division.frame, 0); Vector3 v2d = v0d + new Vector3(panelRect.width - division.frame * 2, 0, 0); Vector3 v3d = v1d + new Vector3(panelRect.width - division.frame * 2, 0, 0); Vector2 uv0d = CalculateUV(usedSurface, v0d); Vector2 uv1d = CalculateUV(usedSurface, v1d); Vector2 uv2d = CalculateUV(usedSurface, v2d); Vector2 uv3d = CalculateUV(usedSurface, v3d); dynamicMesh.AddPlaneComplex(v0d, v1d, v2d, v3d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v0d, v2d, v0d + recessV, v2d + recessV, uv0d, uv2d, uv0d + uvUp, uv2d + uvUp, Vector3.up, tangent, useSubmesh, usedSurface); //divider top dynamicMesh.AddPlaneComplex(v3d, v1d, v3d + recessV, v1d + recessV, uv3d, uv1d, uv3d - uvUp, uv1d - uvUp, Vector3.down, tangent, useSubmesh, usedSurface); //divider bottom if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2); dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v0d + interiorOffset, v3d + interiorOffset, v2d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v2d + interiorOffset, v0d + interiorOffset, v2d + recessV + interiorOffsetr, v0d + recessV + interiorOffsetr, uv2d, uv0d, uv2d + uvUp, uv0d + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface); //divider top dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v3d + interiorOffset, v1d + recessV + interiorOffsetr, v3d + recessV + interiorOffsetr, uv1d, uv3d, uv1d - uvUp, uv3d - uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface); //divider bottom } } } } } } }
public static void Generate(IBuilding building, IVolume volume, IFloorplan floorplan, int volumeFloor, VerticalOpening[] openings, BuildRMesh mesh, BuildRCollider collider) { SubmeshLibrary submeshLibrary = mesh.submeshLibrary; bool generateColliders = building.colliderType != BuildingColliderTypes.None; bool generateMeshColliders = building.colliderType != BuildingColliderTypes.Primitive && generateColliders; BuildRCollider sendCollider = (generateColliders) ? collider : null; collider.thickness = volume.wallThickness; if (!generateMeshColliders) { collider = null; } float wallThickness = volume.wallThickness; float wallUp = volume.floorHeight - wallThickness; Vector3 wallUpV = Vector3.up * wallUp; Vector3 floorBaseV = Vector3.up * volume.baseHeight; int roomCount = floorplan.RoomCount; int actualFloor = building.VolumeBaseFloor(volume) + volumeFloor; int openingCount = openings.Length; bool[] openingBelow = new bool[openingCount]; bool[] openingAbove = new bool[openingCount]; FlatBounds[] openingBounds = new FlatBounds[openingCount]; Vector2[][] openingShapes = new Vector2[openingCount][]; bool[] openingUsedInThisFloor = new bool[openingCount]; for (int o = 0; o < openingCount; o++) { VerticalOpening opening = openings[o]; if (!openings[o].FloorIsIncluded(actualFloor)) { continue; } openingBelow[o] = opening.FloorIsIncluded(actualFloor - 1); openingAbove[o] = opening.FloorIsIncluded(actualFloor + 1); openingShapes[o] = opening.PointsRotated(); openingBounds[o] = new FlatBounds(openingShapes[o]); submeshLibrary.Add(opening.surfaceA); submeshLibrary.Add(opening.surfaceB); submeshLibrary.Add(opening.surfaceC); submeshLibrary.Add(opening.surfaceD); } Dictionary <int, List <Vector2Int> > externalWallAnchors = volume.facadeWallAnchors; Room[] rooms = floorplan.AllRooms(); for (int r = 0; r < roomCount; r++) { Room room = rooms[r]; int pointCount = room.numberOfPoints; Surface floorSurface = null; Surface wallSurface = null; Surface ceilingSurface = null; if (room.style != null) { RoomStyle style = room.style; floorSurface = style.floorSurface; wallSurface = style.wallSurface; ceilingSurface = style.ceilingSurface; } int floorSubmesh = submeshLibrary.SubmeshAdd(floorSurface); int wallSubmesh = submeshLibrary.SubmeshAdd(wallSurface); int ceilingSubmesh = submeshLibrary.SubmeshAdd(ceilingSurface); FloorplanUtil.RoomWall[] walls = FloorplanUtil.CalculatePoints(room, volume); Vector2[] roomArchorPoints = FloorplanUtil.RoomArchorPoints(walls); Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); Vector2[] offsetRoomAnchorPoints = QuickPolyOffset.Execute(roomArchorPoints, wallThickness); FlatBounds roomBounds = new FlatBounds(offsetRoomAnchorPoints); List <Vector2[]> floorCuts = new List <Vector2[]>(); List <Vector2[]> ceilingCuts = new List <Vector2[]>(); List <VerticalOpening> roomOpenings = new List <VerticalOpening>(); for (int o = 0; o < openingCount; o++) { if (openings[o].FloorIsIncluded(actualFloor)) { if (roomBounds.Overlaps(openingBounds[o])) { if (CheckShapeWithinRoom(offsetRoomAnchorPoints, openingShapes[o])) { if (openingBelow[o]) { floorCuts.Add(openingShapes[o]); } if (openingAbove[o]) { ceilingCuts.Add(openingShapes[o]); } if (openingAbove[o] || openingBelow[o]) { roomOpenings.Add(openings[o]); openingUsedInThisFloor[o] = true; } } } } } int offsetPointBase = 0; for (int p = 0; p < pointCount; p++)//generate room walls { FloorplanUtil.RoomWall wall = walls[p]; int wallPointCount = wall.offsetPoints.Length; List <RoomPortal> wallPortals = floorplan.GetWallPortals(room, p); int wallPortalCount = wallPortals.Count; if (!wall.isExternal) { int indexA = offsetPointBase; int indexB = (offsetPointBase + 1) % roomArchorPoints.Length; Vector2 origBaseA = roomArchorPoints[indexA]; Vector2 origBaseB = roomArchorPoints[indexB]; Vector2 baseA = offsetRoomAnchorPoints[indexA]; Vector2 baseB = offsetRoomAnchorPoints[indexB]; Vector3 v0 = new Vector3(origBaseA.x, 0, origBaseA.y) + floorBaseV; Vector3 v1 = new Vector3(origBaseB.x, 0, origBaseB.y) + floorBaseV; Vector3 vOffset0 = new Vector3(baseA.x, 0, baseA.y) + floorBaseV; Vector3 vOffset1 = new Vector3(baseB.x, 0, baseB.y) + floorBaseV; if (wallPortalCount == 0) //just draw the wall - no portals to cut { Vector3 v2 = vOffset1 + wallUpV; Vector3 v3 = vOffset0 + wallUpV; Vector2 minUV = Vector2.zero; Vector2 maxUV = new Vector2(Vector2.Distance(baseA, baseB), wallUp); if (wallSurface != null) { maxUV = wallSurface.CalculateUV(maxUV); } Vector3 wallDir = (vOffset0 - vOffset1).normalized; Vector3 wallNormal = Vector3.Cross(Vector3.up, wallDir); Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir); mesh.AddPlane(vOffset1, vOffset0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface); if (generateColliders) { collider.AddPlane(vOffset1, vOffset0, v2, v3); } } else { List <float> useLaterals = new List <float>(); List <bool> hasPortals = new List <bool>(); for (int wp = 0; wp < wallPortalCount; wp++) { RoomPortal portal = wallPortals[wp]; bool hasPortal = room.HasPortal(portal); hasPortals.Add(hasPortal); if (hasPortal) { useLaterals.Add(portal.lateralPosition); } else { useLaterals.Add(1 - portal.lateralPosition);//portal from other wall - wall orientation is flipped } } Vector3 wallVector = vOffset1 - vOffset0; Vector3 wallDirection = wallVector.normalized; Vector3 wallStart = vOffset0; Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDirection); Vector3 wallNormal = Vector3.Cross(Vector3.up, wallDirection); Vector4 wallNormalTangent = BuildRMesh.CalculateTangent(wallNormal); Vector4 wallNormalTangentReverse = BuildRMesh.CalculateTangent(-wallNormal); while (wallPortalCount > 0) { int portalIndex = 0; RoomPortal usePortal = wallPortals[0]; float lowestLat = useLaterals[0]; for (int wp = 1; wp < wallPortalCount; wp++) { if (useLaterals[wp] < lowestLat) { portalIndex = wp; usePortal = wallPortals[wp]; lowestLat = useLaterals[wp]; } } wallPortals.RemoveAt(portalIndex); useLaterals.RemoveAt(portalIndex); wallPortalCount--; Vector3 vl0 = v0 + (-wallNormal + wallDirection) * wallThickness; Vector3 vl1 = v1 + (-wallNormal - wallDirection) * wallThickness; Vector3 portalCenter = Vector3.Lerp(vl0, vl1, lowestLat); Vector3 portalHalfvector = wallDirection * (usePortal.width * 0.5f); Vector3 portalBase = Vector3.up * (volume.floorHeight - usePortal.height) * usePortal.verticalPosition; Vector3 portalUp = portalBase + Vector3.up * usePortal.height; Vector3 portalStart = portalCenter - portalHalfvector; Vector3 portalEnd = portalCenter + portalHalfvector; Vector2 initalWallUVMin = new Vector2(Vector3.Dot(portalStart, wallDirection), 0); Vector2 initalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp); mesh.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV, initalWallUVMin, initalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//initial wall if (generateColliders) { collider.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV); } if (usePortal.verticalPosition > 0) { Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), 0); Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), portalBase.y); mesh.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//bottom if (generateColliders) { collider.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase); } } if (usePortal.verticalPosition < 1) { Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), portalUp.y); Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), wallUp); mesh.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//top if (generateColliders) { collider.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV); } } if (hasPortals[portalIndex])//only do this once - from the room it's attached to { //portal interior frame Vector3 portalDepth = wallNormal * wallThickness * 2; //sides mesh.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp, wallDirection, wallNormalTangentReverse, wallSubmesh); mesh.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp, -wallDirection, wallNormalTangent, wallSubmesh); if (generateMeshColliders) { collider.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp); collider.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp); } //floor Vector2 minFloorUv = new Vector2((portalEnd + portalBase).z, (portalEnd + portalBase).x); Vector2 maxFloorUv = minFloorUv + new Vector2(wallThickness, usePortal.width); mesh.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase, minFloorUv, maxFloorUv, Vector3.up, wallTangent, floorSubmesh, floorSurface); if (generateMeshColliders) { collider.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase); } //ceiling mesh.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp, Vector3.down, wallTangent, wallSubmesh); if (generateMeshColliders) { collider.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp); } } wallStart = portalEnd;//move the start for the next calculation } Vector2 finalWallUVMin = new Vector2(Vector3.Dot(vOffset1, wallDirection), 0); Vector2 finalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp); mesh.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV, finalWallUVMin, finalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//final wall section if (generateColliders) { collider.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV); } } offsetPointBase += 1; } else//external anchored wall { int facadeIndex = wall.facadeIndex; Facade facadeDesign = volume.GetFacade(facadeIndex); int currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count - 1; int currentWallSectionIndex = wall.offsetPointWallSection[0]; int wallOffsetPoints = wall.offsetPoints.Length; for (int w = 0; w < wallOffsetPoints - 1; w++) { int roomPointIndex = offsetPointBase + w; Vector2 baseA = offsetRoomAnchorPoints[roomPointIndex]; int offsetIndexB = (roomPointIndex + 1) % offsetRoomAnchorPoints.Length; Vector2 baseB = offsetRoomAnchorPoints[offsetIndexB]; Vector3 v0 = new Vector3(baseA.x, 0, baseA.y) + floorBaseV; Vector3 v1 = new Vector3(baseB.x, 0, baseB.y) + floorBaseV; int wallSectionIndex = wall.offsetPointWallSection[w]; bool canGenerateWallSection = facadeDesign != null; Vector3 wallVector = v0 - v1; Vector3 wallDir = wallVector.normalized; float wallLength = wallVector.magnitude; if (!canGenerateWallSection) { if (wallSurface != null) { submeshLibrary.Add(wallSurface); } Vector3 v2 = v1 + wallUpV; Vector3 v3 = v0 + wallUpV; Vector2 minUV = Vector2.zero; Vector2 maxUV = new Vector2(Vector2.Distance(baseA, baseB), wallUp); Vector3 wallNormal = Vector3.Cross(Vector3.up, wallDir); Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir); mesh.AddPlane(v1, v0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface); if (generateMeshColliders) { collider.AddPlane(v1, v0, v2, v3); } } else { WallSection section = facadeDesign.GetWallSection(wallSectionIndex, volumeFloor, currentFacadeWallSectionLength, volume.floors); if (section.model != null) { continue;//cannot account for custom meshes assume custom mesh does include interior mesh or if does - will be generated with the exterior } GenerationOutput generatedSection = GenerationOutput.CreateRawOutput(); Vector2 wallSectionSize = new Vector2(wallLength, wallUp + wallThickness); bool cullOpening = building.cullDoors && section.isDoor; SubmeshLibrary sectionLib = new SubmeshLibrary(); if (wallSurface != null) { sectionLib.Add(wallSurface);//add interior wall surface submeshLibrary.Add(wallSurface); } sectionLib.Add(section.openingSurface);//add windows - the only surface we'll use in the interior room submeshLibrary.Add(section.openingSurface); float offset = 0; if (w == 0) { offset = wallThickness; } if (w == wallOffsetPoints - 2) { offset = -wallThickness; } WallSectionGenerator.Generate(section, generatedSection, wallSectionSize, true, wallThickness, cullOpening, null, sectionLib, offset); int[] mapping = submeshLibrary.MapSubmeshes(generatedSection.raw.materials); Vector3 curveNormal = Vector3.Cross(wallDir, Vector3.up); Quaternion meshRot = Quaternion.LookRotation(curveNormal, Vector3.up); Vector3 meshPos = new Vector3(v1.x, volume.baseHeight, v1.z) + wallDir * wallSectionSize.x + Vector3.up * wallSectionSize.y; meshPos += meshRot * -new Vector3(wallSectionSize.x, wallSectionSize.y, 0) * 0.5f; mesh.AddData(generatedSection.raw, mapping, meshPos, meshRot, Vector3.one); } currentWallSectionIndex++; if (currentWallSectionIndex >= currentFacadeWallSectionLength) { //reached the end of the facade - move to the next one and continue currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count; currentWallSectionIndex = 0; } } offsetPointBase += wallPointCount - 1; } } //FLOOR Vector2[] mainShape = offsetRoomAnchorPoints; Vector2[][] floorCutPoints = floorCuts.ToArray(); int floorVertCount = mainShape.Length; for (int flc = 0; flc < floorCutPoints.Length; flc++) { floorVertCount += floorCutPoints[flc].Length; } Vector2[] allFloorPoints = new Vector2[floorVertCount]; int mainShapeLength = mainShape.Length; for (int ms = 0; ms < mainShapeLength; ms++) { allFloorPoints[ms] = mainShape[ms]; } int cutPointIterator = mainShapeLength; for (int flc = 0; flc < floorCutPoints.Length; flc++) { for (int flcp = 0; flcp < floorCutPoints[flc].Length; flcp++) { allFloorPoints[cutPointIterator] = floorCutPoints[flc][flcp]; cutPointIterator++; } } Vector3[] floorPoints = new Vector3[floorVertCount]; Vector2[] floorUvs = new Vector2[floorVertCount]; Vector3[] floorNorms = new Vector3[floorVertCount]; Vector4[] floorTangents = new Vector4[floorVertCount]; for (int rp = 0; rp < floorVertCount; rp++) { floorPoints[rp] = new Vector3(allFloorPoints[rp].x, 0, allFloorPoints[rp].y) + floorBaseV; Vector2 uv = allFloorPoints[rp]; if (floorSurface != null) { uv = floorSurface.CalculateUV(uv); } floorUvs[rp] = uv; floorNorms[rp] = Vector3.up; floorTangents[rp] = tangent; } int[] tris = Poly2TriWrapper.Triangulate(mainShape, true, floorCutPoints); mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, floorSubmesh); if (generateColliders) { collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0); } //CEILING! Vector2[][] ceilingCutPoints = ceilingCuts.ToArray(); int ceilingVertCount = mainShape.Length; for (int flc = 0; flc < ceilingCutPoints.Length; flc++) { ceilingVertCount += ceilingCutPoints[flc].Length; } Vector2[] allCeilingPoints = new Vector2[ceilingVertCount]; for (int ms = 0; ms < mainShapeLength; ms++) { allCeilingPoints[ms] = mainShape[ms]; } cutPointIterator = mainShapeLength; for (int flc = 0; flc < ceilingCutPoints.Length; flc++) { for (int flcp = 0; flcp < ceilingCutPoints[flc].Length; flcp++) { allCeilingPoints[cutPointIterator] = ceilingCutPoints[flc][flcp]; cutPointIterator++; } } Vector3[] ceilingPoints = new Vector3[ceilingVertCount]; Vector2[] ceilingUvs = new Vector2[ceilingVertCount]; Vector3[] ceilingNorms = new Vector3[ceilingVertCount]; Vector4[] ceilingTangents = new Vector4[ceilingVertCount]; for (int rp = 0; rp < ceilingVertCount; rp++) { ceilingPoints[rp] = new Vector3(allCeilingPoints[rp].x, wallUp, allCeilingPoints[rp].y) + floorBaseV; Vector2 uv = allCeilingPoints[rp]; if (floorSurface != null) { uv = ceilingSurface.CalculateUV(uv); } ceilingUvs[rp] = uv; ceilingNorms[rp] = Vector3.down; ceilingTangents[rp] = tangent; } tris = Poly2TriWrapper.Triangulate(mainShape, false, ceilingCutPoints); mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, ceilingSubmesh); if (generateColliders) { collider.mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, 0); } for (int ob = 0; ob < openingCount; ob++) { VerticalOpening opening = openings[ob]; int openingIndex = Array.IndexOf(openings, opening); Vector3 basePosition = openingBounds[openingIndex].center; basePosition.z = basePosition.y; basePosition.y = volume.baseHeight; if (roomOpenings.Contains(opening))//opening used in this floorplan { int externalWallSubmesh = wallSubmesh != -1 ? wallSubmesh : -1; switch (opening.usage) { case VerticalOpening.Usages.Space: if (ceilingCutPoints.Length <= ob) { continue; } Vector3 ceilingCutUpV = Vector3.up * wallThickness; Vector2[] ceilingCut = ceilingCutPoints[ob]; int custSize = ceilingCut.Length; for (int cp = 0; cp < custSize; cp++) { int indexA = (cp + 1) % custSize; int indexB = cp; Vector3 cp0 = new Vector3(ceilingCut[indexA].x, wallUp, ceilingCut[indexA].y) + floorBaseV; Vector3 cp1 = new Vector3(ceilingCut[indexB].x, wallUp, ceilingCut[indexB].y) + floorBaseV; Vector3 cp2 = cp0 + ceilingCutUpV; Vector3 cp3 = cp1 + ceilingCutUpV; mesh.AddPlane(cp0, cp1, cp2, cp3, ceilingSubmesh); if (generateColliders) { collider.AddPlane(cp0, cp1, cp2, cp3); } } break; case VerticalOpening.Usages.Stairwell: StaircaseGenerator.Generate(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider); if (volumeFloor == volume.floors - 1 && opening.baseFloor + opening.floors > building.VolumeBaseFloor(volume) + volume.floors - 1 && volume.abovePlanCount == 0) { StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider); } break; case VerticalOpening.Usages.Elevator: ElevatorShaftGenerator.Generate(ref mesh, opening, actualFloor, basePosition, volume.floorHeight, externalWallSubmesh, sendCollider); break; } } } } for (int ob = 0; ob < openingCount; ob++) { Vector2[] openingShape = openingShapes[ob]; if (openingShape == null) { continue; //opening not used by this floorplan } if (openingUsedInThisFloor[ob]) { continue; //opening already generated } //seal this opening from the void VerticalOpening opening = openings[ob]; int openingIndex = Array.IndexOf(openings, opening); Vector3 basePosition = openingBounds[openingIndex].center; basePosition.z = basePosition.y; basePosition.y = 0; int cutSize = openingShape.Length; Vector3 sealingWallUpV = Vector3.up * volume.floorHeight; int sealWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB); Vector2[] offsetOpeningShape = QuickPolyOffset.Execute(openingShape, wallThickness); for (int cp = 0; cp < cutSize; cp++) { int indexA = (cp + 1) % cutSize; int indexB = cp; Vector2 p0 = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexA] : offsetOpeningShape[indexA]; Vector2 p1 = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexB] : offsetOpeningShape[indexB]; Vector3 cp0 = new Vector3(p0.x, 0, p0.y) + floorBaseV; Vector3 cp1 = new Vector3(p1.x, 0, p1.y) + floorBaseV; Vector3 cp2 = cp0 + sealingWallUpV; Vector3 cp3 = cp1 + sealingWallUpV; mesh.AddPlane(cp0, cp1, cp2, cp3, sealWallSubmesh); if (generateColliders) { collider.AddPlane(cp0, cp1, cp2, cp3); } } switch (opening.usage) { case VerticalOpening.Usages.Space: //nothing to implement break; case VerticalOpening.Usages.Stairwell: //need stairs to connect used floors StaircaseGenerator.GenerateStairs(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider); if (volumeFloor == volume.floors - 1) { StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider); } break; case VerticalOpening.Usages.Elevator: //nothing to implement break; } } }