public VerticalOpening AddOpening() { VerticalOpening output = new VerticalOpening(); _openings.Add(output); return(output); }
public static void Generate(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int floor, int wallSubmesh = -1, BuildRCollider collider = null) { if (collider != null) { collider.thickness = VerticalOpening.WALL_THICKNESS; } GenerateWall(mesh, opening, basePosition, height, wallSubmesh, collider); GenerateStairs(mesh, opening, basePosition, height, floor, wallSubmesh, collider); }
private static Path OpeningToPath(VerticalOpening opening) { Path output = new Path(); Vector2[] points = opening.PointsRotated(); points = QuickPolyOffset.Execute(points, VerticalOpening.WALL_THICKNESS); int numberOfPoints = points.Length; for (int p = 0; p < numberOfPoints; p++) { output.Add(Vector2ToIntpoint(points[p])); } return(output); }
/// <summary> /// This one ignores finding openings within specific shapes as we'll be doing this for rooms in floorplan gen /// </summary> /// <param name="building"></param> /// <param name="volume"></param> /// <returns></returns> public static VerticalOpening[] GetOpeningsQuick(IBuilding building, IVolume volume) { List <VerticalOpening> output = new List <VerticalOpening>(); int count = building.openingCount; VerticalOpening[] openings = building.GetAllOpenings(); int volumeBaseFloor = building.VolumeBaseFloor(volume); int volumeTopFloor = volumeBaseFloor + volume.floors; for (int i = 0; i < count; i++) { VerticalOpening opening = openings[i]; int openingBaseFloor = opening.baseFloor; int openingTopFloor = openingBaseFloor + opening.floors; // Debug.Log("CHECK IT " + openingTopFloor + " " + volume.name); // Debug.Log(volumeBaseFloor + " < " + openingTopFloor + " && " + openingBaseFloor + " < " + volumeTopFloor); if (volumeBaseFloor <= openingTopFloor && openingBaseFloor < volumeTopFloor)//opening and volume floors intersect { // Debug.Log("opening " + openingTopFloor + " "+ volume.name); FlatBounds volumeBounds = new FlatBounds(volume.bounds); volumeBounds.Expand(VerticalOpening.WALL_THICKNESS); Vector2[] openingPoints = opening.PointsRotated(); FlatBounds openingBounds = new FlatBounds(openingPoints); // if(volume.name == "Roof Exit") // { // Debug.Log(volumeBounds.Overlaps(openingBounds, true)); // Debug.Log(openingBounds.Overlaps(volumeBounds, true)); // volumeBounds.DrawDebug(Color.red); // openingBounds.DrawDebug(Color.green); // } if (openingBounds.Overlaps(volumeBounds, true))// opening is within the AABB bounds of the volume { output.Add(opening); // Debug.Log("opening bounds " + openingTopFloor + " " + volume.name); } else { // Debug.Log("opening NOT " + openingTopFloor + " " + volume.name); } } // Debug.Log("================================="); } return(output.ToArray()); }
public VerticalOpening[] GetOpenings(IVolume volume, IFloorplan inPlan) { List <VerticalOpening> output = new List <VerticalOpening>(); int count = _openings.Count; int planFloor = volume.Floor(inPlan); for (int i = 0; i < count; i++) { VerticalOpening opening = _openings[i]; int baseFloor = opening.baseFloor; int topFloor = baseFloor + opening.floors; if (planFloor >= baseFloor && planFloor <= topFloor) { output.Add(opening); } } return(output.ToArray()); }
public bool[] GetOpenings(IVolume volume, IFloorplan inPlan, int offset) { List <bool> output = new List <bool>(); int count = _openings.Count; int planFloor = volume.Floor(inPlan); int offsetFloor = planFloor + offset; for (int i = 0; i < count; i++) { VerticalOpening opening = _openings[i]; int baseFloor = opening.baseFloor; int topFloor = baseFloor + opening.floors; if (planFloor >= baseFloor && planFloor <= topFloor) { bool isOpen = offsetFloor >= baseFloor && offsetFloor <= topFloor; output.Add(isOpen); } } return(output.ToArray()); }
// _drag = Drag2D(_drag, r); // // if (_mPrevRender == null) // _mPrevRender = new PreviewRenderUtility(); // // // Vector3 max = _wallSection.previewMesh.bounds.size; // // float radius = Mathf.Max(max.x, Mathf.Max(max.y, max.z)) * 1.333f; // float dist = radius / (Mathf.Sin(_mPrevRender.camera.fieldOfView * Mathf.Deg2Rad)); // _mPrevRender.camera.transform.position = Vector2.zero; // _mPrevRender.camera.transform.rotation = Quaternion.Euler(new Vector3(-_drag.y, -_drag.x, 0)); // _mPrevRender.camera.transform.position = _mPrevRender.camera.transform.forward * -dist; // _mPrevRender.camera.nearClipPlane = 0.1f; // _mPrevRender.camera.farClipPlane = 500; // // _mPrevRender.lights[0].intensity = 0.5f; // _mPrevRender.lights[0].transform.rotation = Quaternion.Euler(30f, 30f, 0f); // _mPrevRender.lights[1].intensity = 0.5f; // // _mPrevRender.BeginPreview(r, background); // // if (_plane != null && _blueprintMaterial != null) // { // Matrix4x4 matrix = Matrix4x4.TRS(new Vector3(-25, -25, 1), Quaternion.identity, new Vector3(10, 10, 1)); // _mPrevRender.DrawMesh(_plane, matrix, _blueprintMaterial, 0); // _mPrevRender.camera.Render(); // } // // // int materialCount = mats.Length; // int submeshCount = mesh.subMeshCount; // int count = Mathf.Min(materialCount, submeshCount); // for (int c = 0; c < count; c++) // { // Material mat = c < materialCount ? mats[c] : AssetDatabase.GetBuiltinExtraResource<Material>("Default-Material.mat"); // if (mat == null) mat = AssetDatabase.GetBuiltinExtraResource<Material>("Default-Material.mat"); // _mPrevRender.DrawMesh(mesh, Matrix4x4.identity, mat, c); // } // // _mPrevRender.camera.Render(); // Texture texture = _mPrevRender.EndPreview(); // // GUI.DrawTexture(r, texture); // } // // public static Vector2 Drag2D(Vector2 scrollPosition, Rect position) // { // int controlID = GUIUtility.GetControlID("Slider".GetHashCode(), FocusType.Passive); // Event current = Event.current; // switch (current.GetTypeForControl(controlID)) // { // case EventType.MouseDown: // if (position.Contains(current.mousePosition) && position.width > 50f) // { // GUIUtility.hotControl = controlID; // current.Use(); // EditorGUIUtility.SetWantsMouseJumping(1); // } // break; // case EventType.MouseUp: // if (GUIUtility.hotControl == controlID) // { // GUIUtility.hotControl = 0; // } // EditorGUIUtility.SetWantsMouseJumping(0); // break; // case EventType.MouseDrag: // if (GUIUtility.hotControl == controlID) // { // scrollPosition -= current.delta * (float)((!current.shift) ? 1 : 3) / Mathf.Min(position.width, position.height) * 140f; // scrollPosition.y = Mathf.Clamp(scrollPosition.y, -90f, 90f); // current.Use(); // GUI.changed = true; // } // break; // } // return scrollPosition; // } public static FloorplanClick OnInteriorSelectionClick(Ray mouseRay) { FloorplanClick output = new FloorplanClick(); Building building = BuildingEditor.building; Volume volume = BuildingEditor.volume; Floorplan floorplan = BuildingEditor.floorplan; output.volume = volume; output.floorplan = floorplan; if (floorplan != null) { Vector3 basePosition = building.transform.position; float baseHeight = volume.baseHeight; Vector3 testPoint = basePosition + Vector3.up * baseHeight; if (Vector3.Dot(mouseRay.direction, testPoint - mouseRay.origin) < 0)//volume behind camera { return(output); } float floorHeight = volume.floorHeight; List <Room> rooms = floorplan.rooms; int roomCount = rooms.Count; float minDistance = Mathf.Infinity; for (int rm = 0; rm < roomCount; rm++) { Room room = rooms[rm]; RoomPortal[] portals = room.GetAllPortals(); int portalCount = portals.Length; for (int p = 0; p < portalCount; p++) { RoomPortal portal = portals[p]; int wallIndex = portal.wallIndex; Vector3 p0 = room[wallIndex].position.vector3XZ; Vector3 p1 = room[(wallIndex + 1) % room.numberOfPoints].position.vector3XZ; Vector3 baseUp = Vector3.up * (floorHeight - portal.height) * portal.verticalPosition; Vector3 portalUp = baseUp + Vector3.up * portal.height; Vector3 pointPos = SceneMeshHandler.PortalPosition(Quaternion.identity, room, portal); pointPos.y = baseHeight; Vector3 wallDirection = (p1 - p0).normalized; float defaultWidth = portal.width * 0.5f; // float defaultDepth = 0.1f; Vector3 v0 = pointPos - wallDirection * defaultWidth; Vector3 v1 = pointPos + wallDirection * defaultWidth; Vector3 v2 = v0 + portalUp; Vector3 v3 = v1 + portalUp; // Debug.DrawLine(v0,v1,Color.red,20); // Debug.DrawLine(v1,v3,Color.red,20); // Debug.DrawLine(v3,v2,Color.red,20); // Debug.DrawLine(v2,v0,Color.red,20); float distance = 0; if (RayTriangle.QuadIntersection(v0, v1, v2, v3, mouseRay, out distance, false)) { if (minDistance > distance) { minDistance = distance; output.room = room; output.portal = portal; output.opening = null; } } } } VerticalOpening[] openings = building.GetAllOpenings(); int openingCount = openings.Length; for (int o = 0; o < openingCount; o++) { VerticalOpening opening = openings[o]; Vector3 openingPosition = opening.position.vector3XZ; openingPosition.y = volume.floorHeight * opening.baseFloor; Vector3 openingSize = opening.size.vector3XZ; float openingWidth = openingSize.x; float openingHeight = openingSize.z; Quaternion openingRotation = Quaternion.Euler(0, opening.rotation, 0); Vector3 p0 = openingPosition + openingRotation * new Vector3(-openingWidth, 0, -openingHeight) * 0.5f; Vector3 p1 = openingPosition + openingRotation * new Vector3(openingWidth, 0, -openingHeight) * 0.5f; Vector3 p2 = openingPosition + openingRotation * new Vector3(openingWidth, 0, openingHeight) * 0.5f; Vector3 p3 = openingPosition + openingRotation * new Vector3(-openingWidth, 0, openingHeight) * 0.5f; // Vector3 openingUp = Vector3.up * volume.floorHeight * (opening.floors + 1); Vector3 floorUpA = Vector3.up * volume.CalculateFloorHeight(volume.Floor(BuildingEditor.floorplan)); // Vector3 floorUpB = floorUpA + Vector3.up * volume.floorHeight; float distance = 0; if (RayTriangle.QuadIntersection(p0 + floorUpA, p1 + floorUpA, p2 + floorUpA, p3 + floorUpA, mouseRay, out distance, false)) { if (minDistance > distance) { minDistance = distance; output.room = null; output.portal = null; output.opening = opening; } } } if (output.opening != null) { return(output); } if (output.portal != null) { return(output); } float intPlanBaseHeight = volume.CalculateFloorHeight(volume.Floor(floorplan)); Vector3 baseUpV = Vector3.up * intPlanBaseHeight; Plane planPlane = new Plane(Vector3.up, baseUpV); float rayDistance = 0; if (planPlane.Raycast(mouseRay, out rayDistance)) { Vector3 clickPos = mouseRay.GetPoint(rayDistance) - basePosition; Vector2Int floorClickPosition = new Vector2Int(clickPos, true); for (int rm = 0; rm < roomCount; rm++) { Vector2Int[] roomPoints = rooms[rm].AllPoints(); if (BuildrUtils.PointInsidePoly(floorClickPosition, roomPoints)) { output.room = rooms[rm]; } } } } return(output); }
public void RemoveOpening(VerticalOpening opening) { _openings.Remove(opening); }
public static void GenerateRoofAccess(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int floor, int wallSubmesh = -1, BuildRCollider collider = null) { // bool stepped = true;//todo float minimumWidth = 0.9f; //UK standard // float maximumWidth = 2.0f; // float stepHeight = 0.22f; float wallThickness = VerticalOpening.WALL_THICKNESS; float stairWidth = 0.70f; //todo / calculate float doorWidth = 1.3f; float doorHeight = 2.04f; bool generateColldier = collider != null; float minimumRunLength = 0.25f; float maximumRiserHeight = 0.2f; SubmeshLibrary submeshLibrary = mesh.submeshLibrary; int externalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceA); int internalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB); int doorFrameSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceC); int internalFloorSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceD); //base positions Quaternion rotation = Quaternion.Euler(0, opening.rotation, 0); Vector2Int openingSize = opening.size; Vector3 b0 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, height, -opening.size.vy * 0.5f); Vector3 b1 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, height, -opening.size.vy * 0.5f); Vector3 b2 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, height, opening.size.vy * 0.5f); Vector3 b3 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, height, opening.size.vy * 0.5f); //inner points Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness; Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness; Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness; Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness; Vector2 internalSize = new Vector2(openingSize.vx - wallThickness * 2, openingSize.vy - wallThickness * 2); float stairWidthFromX = internalSize.x * 0.5f; float stairWidthFromY = internalSize.y - Mathf.Ceil(height / maximumRiserHeight) * minimumRunLength; float useLandingWidth = (stairWidthFromX + stairWidthFromY) * 0.5f; useLandingWidth = Mathf.Clamp(useLandingWidth, minimumWidth, opening.stairWidth); Vector3 escalationFlatDir = (b2i - b0i).normalized; Vector3 landingDrop = Vector3.down * wallThickness; //landing Vector3 l0 = b0i; Vector3 l1 = b1i; Vector3 l2 = b0i + escalationFlatDir * useLandingWidth; Vector3 l3 = b1i + escalationFlatDir * useLandingWidth; //top mesh.AddPlane(l0, l1, l2, l3, internalFloorSubmesh); //bottom mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, internalWallSubmesh); //front mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, internalWallSubmesh); if (generateColldier) { collider.mesh.AddPlane(l0, l1, l2, l3, 0); collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0); collider.mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, 0); } //internal walls Vector3 wallUp = Vector3.up * height; wallUp.y += -wallThickness * 0.5f; Vector3 wallUpI = Vector3.up * (height - wallThickness); mesh.AddPlane(b0i, b2i, b0i + wallUpI, b2i + wallUpI, internalWallSubmesh); mesh.AddPlane(b2i, b3i, b2i + wallUpI, b3i + wallUpI, internalWallSubmesh); mesh.AddPlane(b3i, b1i, b3i + wallUpI, b1i + wallUpI, internalWallSubmesh); mesh.AddPlane(b1i + wallUpI, b0i + wallUpI, b3i + wallUpI, b2i + wallUpI, internalWallSubmesh); //external walls mesh.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp, externalWallSubmesh); mesh.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp, externalWallSubmesh); mesh.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp, externalWallSubmesh); mesh.AddPlane(b0 + wallUp, b1 + wallUp, b2 + wallUp, b3 + wallUp, internalWallSubmesh); if (generateColldier) { collider.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp); collider.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp); collider.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp); collider.mesh.AddPlane(b1i + wallUpI, b0i + wallUpI, b3i + wallUpI, b2i + wallUpI, 0); collider.mesh.AddPlane(b0 + wallUp, b1 + wallUp, b2 + wallUp, b3 + wallUp, 0); if (!collider.usingPrimitives) { collider.mesh.AddPlane(b0i, b2i, b0i + wallUpI, b2i + wallUpI, 0); collider.mesh.AddPlane(b2i, b3i, b2i + wallUpI, b3i + wallUpI, 0); collider.mesh.AddPlane(b3i, b1i, b3i + wallUpI, b1i + wallUpI, 0); } } //door wall //internal float internalWallLength = openingSize.vx - (wallThickness * 2f); float lerpA = Mathf.Max(stairWidth - doorWidth, 0.05f) / internalWallLength; float lerpB = (Mathf.Max(stairWidth - doorWidth, 0.05f) + doorWidth) / internalWallLength; Vector3 bd0i = Vector3.Lerp(b0i, b1i, lerpA); Vector3 bd1i = Vector3.Lerp(b0i, b1i, lerpB); Vector3 doorUp = Vector3.up * doorHeight; //Right side mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, internalWallSubmesh); //left side mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, internalWallSubmesh); //top mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUpI, b0i + wallUpI, internalWallSubmesh); //external Vector3 doorOut = -escalationFlatDir * wallThickness; //left mesh.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp, externalWallSubmesh); //right mesh.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp, externalWallSubmesh); //top mesh.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp, externalWallSubmesh); //frame //floor mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, externalWallSubmesh); //left mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, doorFrameSubmesh); //right mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); //top mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); if (generateColldier) { collider.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp); collider.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp); collider.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp); if (!collider.usingPrimitives) { collider.mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, 0); collider.mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, 0); collider.mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUpI, b0i + wallUpI, 0); collider.mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, 0); collider.mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, 0); collider.mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, 0); collider.mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, 0); } } }
public static void GenerateWall(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int wallSubmesh = -1, BuildRCollider collider = null) { float stairWidth = 0.70f; //todo / calculate float wallThickness = VerticalOpening.WALL_THICKNESS; float doorWidth = 1.3f; float doorHeight = 2.04f; bool generateColldier = collider != null; // bool generateMeshCollider = generateColldier && !collider.usingPrimitives; SubmeshLibrary submeshLibrary = mesh.submeshLibrary; int externalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceA); int internalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB); int doorFrameSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceC); //base positions Quaternion rotation = Quaternion.Euler(0, opening.rotation, 0); Vector2Int openingSize = opening.size; Vector3 b0 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b1 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b2 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); Vector3 b3 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); //inner points Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness; Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness; Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness; Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness; Vector3 escalationFlatDir = (b2i - b0i).normalized; Vector3 wallUp = Vector3.up * height; //external walls Vector2 uv20_min = new Vector2(0, 0); Vector2 uv20_max = new Vector2(opening.size.vy, height); Vector3 normal02 = rotation * Vector3.left; Vector4 tangent02 = BuildRMesh.CalculateTangent((b0 - b2).normalized); mesh.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp, uv20_min, uv20_max, normal02, tangent02, externalWallSubmesh, opening.surfaceA); Vector2 uv32_min = new Vector2(0, 0); Vector2 uv32_max = new Vector2(opening.size.vx, height); Vector3 normal32 = rotation * Vector3.forward; Vector4 tangent32 = BuildRMesh.CalculateTangent((b2 - b3).normalized); mesh.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp, uv32_min, uv32_max, normal32, tangent32, externalWallSubmesh, opening.surfaceA); Vector2 uv13_min = new Vector2(0, 0); Vector2 uv13_max = new Vector2(opening.size.vy, height); Vector3 normal13 = rotation * Vector3.right; Vector4 tangent13 = BuildRMesh.CalculateTangent((b3 - b1).normalized); mesh.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp, uv13_min, uv13_max, normal13, tangent13, externalWallSubmesh, opening.surfaceA); //internal walls Vector2 uv20i_min = new Vector2(wallThickness, 0); Vector2 uv20i_max = new Vector2(opening.size.vy - wallThickness, height); Vector3 normal02i = rotation * Vector3.right; Vector4 tangent02i = BuildRMesh.CalculateTangent((b2 - b0).normalized); mesh.AddPlane(b0i, b2i, b0i + wallUp, b2i + wallUp, uv20i_min, uv20i_max, normal02i, tangent02i, internalWallSubmesh, opening.surfaceB); Vector2 uv32i_min = new Vector2(0, 0); Vector2 uv32i_max = new Vector2(opening.size.vx - wallThickness, height); Vector3 normal32i = rotation * Vector3.back; Vector4 tangent32i = BuildRMesh.CalculateTangent((b3 - b2).normalized); mesh.AddPlane(b2i, b3i, b2i + wallUp, b3i + wallUp, uv32i_min, uv32i_max, normal32i, tangent32i, internalWallSubmesh, opening.surfaceB); Vector2 uv13i_min = new Vector2(0, 0); Vector2 uv13i_max = new Vector2(opening.size.vy - wallThickness, height); Vector3 normal13i = rotation * Vector3.left; Vector4 tangent13i = BuildRMesh.CalculateTangent((b1 - b3).normalized); mesh.AddPlane(b3i, b1i, b3i + wallUp, b1i + wallUp, uv13i_min, uv13i_max, normal13i, tangent13i, internalWallSubmesh, opening.surfaceB); if (generateColldier) { collider.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp); collider.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp); collider.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp); if (!collider.usingPrimitives) { collider.mesh.AddPlane(b0i, b2i, b0i + wallUp, b2i + wallUp, 0); collider.mesh.AddPlane(b2i, b3i, b2i + wallUp, b3i + wallUp, 0); collider.mesh.AddPlane(b3i, b1i, b3i + wallUp, b1i + wallUp, 0); } } //door wall float internalWallLength = openingSize.vx - (wallThickness * 2f); float lerpA = Mathf.Max(stairWidth - doorWidth, 0.05f) / internalWallLength; float lerpB = (Mathf.Max(stairWidth - doorWidth, 0.05f) + doorWidth) / internalWallLength; Vector2 uvd_b0 = new Vector2(0, 0); Vector2 uvd_b1 = new Vector2(opening.size.vx * lerpA, 0); Vector2 uvd_b2 = new Vector2(opening.size.vx * lerpB, 0); Vector2 uvd_b3 = new Vector2(opening.size.vx, 0); Vector2 uvd_m0 = new Vector2(uvd_b0.x, doorHeight); Vector2 uvd_m1 = new Vector2(uvd_b1.x, doorHeight); Vector2 uvd_m3 = new Vector2(uvd_b3.x, doorHeight); Vector2 uvd_t0 = new Vector2(0, height); Vector2 uvd_t3 = new Vector2(opening.size.vx, height); //internal Vector3 bd0i = Vector3.Lerp(b0i, b1i, lerpA); Vector3 bd1i = Vector3.Lerp(b0i, b1i, lerpB); Vector3 normal01i = rotation * Vector3.forward; Vector4 tangent01i = BuildRMesh.CalculateTangent((b0 - b1).normalized); Vector3 doorUp = Vector3.up * doorHeight; //Right side mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, uvd_b0, uvd_m1, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB); //left side mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, uvd_b2, uvd_m3, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB); //top mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUp, b0i + wallUp, uvd_m3, uvd_t0, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB); //external Vector3 doorOut = -escalationFlatDir * wallThickness; Vector3 normal01 = rotation * Vector3.back; Vector4 tangent01 = BuildRMesh.CalculateTangent((b1 - b0).normalized); //left mesh.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp, uvd_b0, uvd_m1, normal01, tangent01, externalWallSubmesh, opening.surfaceA); //right mesh.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp, uvd_b2, uvd_m3, normal01, tangent01, externalWallSubmesh, opening.surfaceA); //top mesh.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp, uvd_m0, uvd_t3, normal01, tangent01, externalWallSubmesh, opening.surfaceA); //frame //floor mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, externalWallSubmesh); //left mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, doorFrameSubmesh); //right mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); //top mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); if (generateColldier) { collider.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp); collider.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp); collider.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp); if (!collider.usingPrimitives) { collider.mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, 0); collider.mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, 0); collider.mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUp, b0i + wallUp, 0); collider.mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, 0); collider.mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, 0); collider.mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, 0); collider.mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, 0); } } }
public static void GenerateStairs(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int floor, int wallSubmesh = -1, BuildRCollider collider = null) { bool stepped = true; //todo float minimumWidth = 0.9f; //UK standard float stepHeight = 0.22f; float wallThickness = VerticalOpening.WALL_THICKNESS; bool generateColldier = collider != null; float minimumRunLength = 0.25f; float maximumRiserHeight = 0.2f; int internalWallSubmesh = mesh.submeshLibrary.SubmeshAdd(opening.surfaceB); int internalFloorSubmesh = mesh.submeshLibrary.SubmeshAdd(opening.surfaceD); bool isBottomFloor = opening.baseFloor == floor; bool isTopFloor = opening.baseFloor + opening.floors == floor; // Debug.Log((opening.baseFloor + opening.floors - 1) +" "+ floor); //base positions Quaternion rotation = Quaternion.Euler(0, opening.rotation, 0); Vector2Int openingSize = opening.size; Vector3 b0 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b1 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b2 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); Vector3 b3 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); //inner points Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness; Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness; Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness; Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness; Vector2 internalSize = new Vector2(openingSize.vx - wallThickness * 2, openingSize.vy - wallThickness * 2); float stairWidthFromX = internalSize.x * 0.5f; float stairWidthFromY = internalSize.y - Mathf.Ceil(height / maximumRiserHeight) * minimumRunLength; float useLandingWidth = (stairWidthFromX + stairWidthFromY) * 0.5f; useLandingWidth = Mathf.Clamp(useLandingWidth, minimumWidth, opening.stairWidth); //Mathf.Max(stairWidth, internalSize.x * 0.5f)); float useStairWidth = Mathf.Clamp(opening.stairWidth, minimumWidth, stairWidthFromX); float stairRun = internalSize.y - (useLandingWidth * 2); Vector3 escalationFlatDir = (b2i - b0i).normalized; Vector3 escalationRight = (b1i - b0i).normalized; Vector3 escalationVector = new Vector3(stairRun * escalationFlatDir.x, height * 0.5f, stairRun * escalationFlatDir.z); Vector3 escalationDirection = escalationVector.normalized; float escalationHypotenuse = escalationVector.magnitude; int numberOfSteps = Mathf.CeilToInt((height) / stepHeight); Vector3 escalationVectorB = new Vector3(stairRun * -escalationFlatDir.x, height * 0.5f, stairRun * -escalationFlatDir.z); Vector3 escalationDirectionB = escalationVectorB.normalized; Vector3 landingDrop = Vector3.down * wallThickness; Vector4 rightTangent = BuildRMesh.CalculateTangent(escalationRight); //lower landing if (!isBottomFloor) { Vector3 l0 = b0i; Vector3 l1 = b1i; Vector3 l2 = b0i + escalationFlatDir * useLandingWidth; Vector3 l3 = b1i + escalationFlatDir * useLandingWidth; Vector2 maxUVTop = new Vector2(internalSize.x, useLandingWidth); Vector2 maxUVSide = new Vector2(internalSize.x, stepHeight); //top mesh.AddPlane(l0, l1, l2, l3, Vector3.zero, maxUVTop, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //bottom mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, Vector3.zero, maxUVTop, Vector3.down, rightTangent, internalWallSubmesh, opening.surfaceB); //front mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, escalationFlatDir, maxUVSide, Vector3.up, rightTangent, internalWallSubmesh, opening.surfaceB); if (generateColldier) { collider.mesh.AddPlane(l0, l1, l2, l3, 0); collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0); collider.mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, 0); } } if (!isTopFloor) { //mid landing if (true) //half landed { Vector3 up = Vector3.up * height * 0.5f; Vector3 l0 = b2i - escalationFlatDir * useLandingWidth + up; Vector3 l1 = b3i - escalationFlatDir * useLandingWidth + up; Vector3 l2 = b2i + up; Vector3 l3 = b3i + up; Vector2 maxUVTop = new Vector2(internalSize.x, useLandingWidth); Vector2 maxUVSide = new Vector2(internalSize.x, useLandingWidth); //top mesh.AddPlane(l0, l1, l2, l3, Vector3.zero, maxUVTop, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //bottom mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, Vector3.zero, maxUVTop, Vector3.down, rightTangent, internalWallSubmesh, opening.surfaceB); //front mesh.AddPlane(l1, l0, l1 + landingDrop, l0 + landingDrop, Vector3.zero, maxUVSide, -escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB); if (generateColldier) { collider.mesh.AddPlane(l0, l1, l2, l3, 0); collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0); collider.mesh.AddPlane(l1, l0, l1 + landingDrop, l0 + landingDrop, 0); } } Vector3 flightABaseOutside = b0i + escalationFlatDir * useLandingWidth; Vector3 flightABaseInside = flightABaseOutside + escalationRight * useStairWidth; Vector3 flightATopOutside = flightABaseOutside + escalationDirection * escalationHypotenuse; Vector3 flightATopInside = flightABaseInside + escalationDirection * escalationHypotenuse; float dropThickness = wallThickness; //Mathf.Sin(Mathf.Atan2(height, stairRun)) * wallThickness; Vector3 flightABaseOutsideDrop = flightABaseOutside + Vector3.down * dropThickness; Vector3 flightABaseInsideDrop = flightABaseInside + Vector3.down * dropThickness; Vector3 flightATopOutsideDrop = flightATopOutside + Vector3.down * dropThickness; Vector3 flightATopInsideDrop = flightATopInside + Vector3.down * dropThickness; Vector3 flightBBaseOutside = b3i - escalationFlatDir * useLandingWidth + Vector3.up * height * 0.5f; Vector3 flightBBaseInside = flightBBaseOutside - escalationRight * useStairWidth; Vector3 flightBTopOutside = flightBBaseOutside + escalationDirectionB * escalationHypotenuse; Vector3 flightBTopInside = flightBBaseInside + escalationDirectionB * escalationHypotenuse; Vector3 flightBBaseOutsideDrop = flightBBaseOutside + Vector3.down * dropThickness; Vector3 flightBBaseInsideDrop = flightBBaseInside + Vector3.down * dropThickness; Vector3 flightBTopOutsideDrop = flightBTopOutside + Vector3.down * dropThickness; Vector3 flightBTopInsideDrop = flightBTopInside + Vector3.down * dropThickness; if (generateColldier) { collider.mesh.AddPlane(flightABaseOutside, flightABaseInside, flightATopOutside, flightATopInside, 0); collider.mesh.AddPlane(flightABaseInsideDrop, flightATopInsideDrop, flightABaseInside, flightATopInside, 0); collider.mesh.AddPlane(flightABaseInsideDrop, flightABaseOutsideDrop, flightATopInsideDrop, flightATopOutsideDrop, 0); collider.mesh.AddPlane(flightBBaseOutside, flightBBaseInside, flightBTopOutside, flightBTopInside, 0); collider.mesh.AddPlane(flightBBaseInsideDrop, flightBTopInsideDrop, flightBBaseInside, flightBTopInside, 0); collider.mesh.AddPlane(flightBBaseInsideDrop, flightBBaseOutsideDrop, flightBTopInsideDrop, flightBTopOutsideDrop, 0); } if (stepped) //todo, flat generation { float stepDepth = stairRun / (numberOfSteps); float skipStep = (stepDepth / (numberOfSteps - 1)); stepDepth += skipStep; float stepRiser = height / numberOfSteps / 2; Vector2 stepUvTopMin = new Vector2(0, 0); Vector2 stepUvTopMax = new Vector2(useStairWidth, stepDepth); Vector2 stepUvSideMin = new Vector2(0, 0); Vector2 stepUvSideMax = new Vector2(useStairWidth, stepRiser); //flight one float lerpIncrement = 1.0f / (numberOfSteps - 1); Vector3 flightATopOutsideStep = flightATopOutside + Vector3.down * stepHeight * 0.5f; Vector3 flightATopInsideStep = flightATopInside + Vector3.down * stepHeight * 0.5f; for (int s = 0; s < numberOfSteps - 1; s++) { float lerpValueAA = lerpIncrement * s; Vector3 s0 = Vector3.Lerp(flightABaseOutside, flightATopOutsideStep, lerpValueAA); Vector3 s1 = Vector3.Lerp(flightABaseInside, flightATopInsideStep, lerpValueAA); Vector3 s2 = s0 + Vector3.up * stepRiser; Vector3 s3 = s1 + Vector3.up * stepRiser; Vector3 s4 = s2 + escalationFlatDir.normalized * stepDepth; Vector3 s5 = s3 + escalationFlatDir.normalized * stepDepth; //front mesh.AddPlane(s0, s1, s2, s3, stepUvSideMin, stepUvSideMax, -escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB); //top mesh.AddPlane(s2, s3, s4, s5, stepUvTopMin, stepUvTopMax, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //sides float lerpValueB = lerpIncrement * s; Vector3 normal = escalationRight; Vector3[] normals = { normal, normal, normal, normal }; Vector4 tangent = BuildRMesh.CalculateTangent(escalationFlatDir); Vector4[] tangents = { tangent, tangent, tangent, tangent }; Vector3 s8 = Vector3.Lerp(flightABaseInsideDrop, flightATopInsideDrop, lerpValueB); Vector3 s9 = Vector3.Lerp(flightABaseInsideDrop, flightATopInsideDrop, lerpValueB + lerpIncrement); Vector2 uv5, uv3, uv8, uv9; if (opening.surfaceB != null) { uv5 = opening.surfaceB.CalculateUV(new Vector2(s5.z, s5.y)); uv3 = opening.surfaceB.CalculateUV(new Vector2(s3.z, s3.y)); uv8 = opening.surfaceB.CalculateUV(new Vector2(s8.z, s8.y)); uv9 = opening.surfaceB.CalculateUV(new Vector2(s9.z, s9.y)); } else { uv5 = new Vector2(); uv3 = new Vector2(); uv8 = new Vector2(); uv9 = new Vector2(); } mesh.AddData(new[] { s3, s5, s8, s9 }, new[] { uv3, uv5, uv8, uv9 }, new[] { 0, 1, 2, 2, 1, 3 }, normals, tangents, internalWallSubmesh); if (opening.surfaceB.tiled) { stepUvSideMin.x += 0.11f; stepUvSideMin.y += 0.37f; stepUvSideMax.x += 0.11f; stepUvSideMax.y += 0.37f; } if (opening.surfaceD.tiled) { stepUvTopMin.x += 0.23f; stepUvTopMin.y += 0.13f; stepUvTopMax.x += 0.23f; stepUvTopMax.y += 0.13f; } } mesh.AddPlane(flightABaseInsideDrop, flightABaseOutsideDrop, flightATopInsideDrop, flightATopOutsideDrop, internalWallSubmesh); //underside //flight two Vector3 flightBTopOutsideStep = flightBTopOutside + Vector3.down * stepHeight * 0.5f; Vector3 flightBTopInsideStep = flightBTopInside + Vector3.down * stepHeight * 0.5f; for (int s = 0; s < numberOfSteps - 1; s++) { float lerpValue = lerpIncrement * s; Vector3 s0 = Vector3.Lerp(flightBBaseOutside, flightBTopOutsideStep, lerpValue); Vector3 s1 = Vector3.Lerp(flightBBaseInside, flightBTopInsideStep, lerpValue); Vector3 s2 = s0 + Vector3.up * stepRiser; Vector3 s3 = s1 + Vector3.up * stepRiser; Vector3 s4 = s2 - escalationFlatDir.normalized * stepDepth; Vector3 s5 = s3 - escalationFlatDir.normalized * stepDepth; //front mesh.AddPlane(s0, s1, s2, s3, stepUvSideMin, stepUvSideMax, escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB); //top mesh.AddPlane(s2, s3, s4, s5, stepUvTopMin, stepUvTopMax, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //sides float lerpValueB = lerpIncrement * s; Vector3 normal = escalationRight; Vector3[] normals = { normal, normal, normal, normal }; Vector4 tangent = BuildRMesh.CalculateTangent(escalationFlatDir); Vector4[] tangents = { tangent, tangent, tangent, tangent }; Vector3 s8 = Vector3.Lerp(flightBBaseInsideDrop, flightBTopInsideDrop, lerpValueB); Vector3 s9 = Vector3.Lerp(flightBBaseInsideDrop, flightBTopInsideDrop, lerpValueB + lerpIncrement); Vector2 uv5, uv3, uv8, uv9; if (opening.surfaceB != null) { uv5 = opening.surfaceB.CalculateUV(new Vector2(s5.z, s5.y)); uv3 = opening.surfaceB.CalculateUV(new Vector2(s3.z, s3.y)); uv8 = opening.surfaceB.CalculateUV(new Vector2(s8.z, s8.y)); uv9 = opening.surfaceB.CalculateUV(new Vector2(s9.z, s9.y)); } else { uv5 = new Vector2(); uv3 = new Vector2(); uv8 = new Vector2(); uv9 = new Vector2(); } mesh.AddData(new[] { s3, s5, s8, s9 }, new[] { uv3, uv5, uv8, uv9 }, new[] { 0, 1, 2, 2, 1, 3 }, normals, tangents, internalWallSubmesh); } mesh.AddPlane(flightBBaseInsideDrop, flightBBaseOutsideDrop, flightBTopInsideDrop, flightBTopOutsideDrop, internalWallSubmesh); //underside } } }
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; } } }
public static void BuildFloorplan() { LAYERS.Clear(); SceneMeshLayer layerOpengings = new SceneMeshLayer(); SceneMeshLayer layer0 = new SceneMeshLayer(); SceneMeshLayer layer1 = new SceneMeshLayer(); SceneMeshLayer layer2 = new SceneMeshLayer(); LAYERS.Add(layerOpengings); LAYERS.Add(layer0); LAYERS.Add(layer1); LAYERS.Add(layer2); Building building = BuildingEditor.building; bPosition = building.transform.position; bRotation = building.transform.rotation; BuildRSettings settings = building.settings; int numberOfVolumes = building.numberOfPlans; Quaternion rotation = building.transform.rotation; Vector3[] centerPoints = new Vector3[numberOfVolumes]; for (int f = 0; f < numberOfVolumes; f++) { centerPoints[f] = BuildrUtils.CalculateFloorplanCenter(building[f]); } for (int v = 0; v < numberOfVolumes; v++) { Volume volume = (Volume)building[v]; bool isSelectedVolume = BuildingEditor.volume == volume; int numberOfPoints = volume.numberOfPoints; Vector3 vUp = Vector3.up * volume.floorHeight; Dictionary <int, List <Vector2Int> > anchorPoints = volume.facadeWallAnchors; IFloorplan[] floorplans = volume.InteriorFloorplans(); int floorplanCount = floorplans.Length; for (int f = 0; f < floorplanCount; f++)//floors { IFloorplan floorplan = floorplans[f]; bool isSelectedFloorplan = BuildingEditor.floorplan == (Floorplan)floorplan; float intPlanBaseHeight = volume.CalculateFloorHeight(f); Vector3 baseUpV = Vector3.up * intPlanBaseHeight; //draw external outline of selected floor if (numberOfPoints > 0 && isSelectedVolume) { SceneMeshLayer useLayer = isSelectedFloorplan ? layer1 : layer0; List <Vector2Int> planVs = new List <Vector2Int>(); Color fillCol = settings.subLineColour; Color lineCol = settings.mainLineColour; for (int p = 0; p < numberOfPoints; p++) { if (volume.IsWallStraight(p)) { if (!planVs.Contains(volume[p].position)) { planVs.Add(volume[p].position); } Vector3 p0 = volume[p].position.vector3XZ + baseUpV; Vector3 p1 = volume[(p + 1) % numberOfPoints].position.vector3XZ + baseUpV; Vector3 p2 = p0 + vUp; Vector3 p3 = p1 + vUp; useLayer.shapes.Add(new SceneMeshShape(fillCol, p0, p1, p3, p2)); useLayer.lines.Add(new SceneMeshLine(p2, p3, lineCol)); useLayer.lines.Add(new SceneMeshLine(p0, p2, lineCol)); useLayer.lines.Add(new SceneMeshLine(p1, p3, lineCol)); if (isSelectedFloorplan) { useLayer.lines.Add(new SceneMeshLine(p0, p1, Color.red)); List <Vector2Int> anchors = anchorPoints[p]; int wallSections = anchors.Count; for (int w = 0; w < wallSections - 1; w++) { Vector3 a = anchors[w].vector3XZ + baseUpV; float anchorSize = 0.05f; if (w == 0) { anchorSize *= 2; } useLayer.dots.Add(new SceneMeshDot(a, anchorSize, settings.anchorColour)); } } } else { List <Vector2Int> anchors = anchorPoints[p]; int wallSections = anchors.Count; for (int w = 0; w < wallSections - 2; w++) { if (!planVs.Contains(anchors[w])) { planVs.Add(anchors[w]); } Vector3 p0 = anchors[w].vector3XZ + baseUpV; Vector3 p1 = anchors[w + 1].vector3XZ + baseUpV; Vector3 p2 = p0 + vUp; Vector3 p3 = p1 + vUp; useLayer.lines.Add(new SceneMeshLine(p2, p3, lineCol)); if (w == 0) { useLayer.lines.Add(new SceneMeshLine(p0, p2, lineCol)); } if (w == wallSections - 2) { useLayer.lines.Add(new SceneMeshLine(p1, p3, lineCol)); } useLayer.shapes.Add(new SceneMeshShape(fillCol, p0, p1, p3, p2)); if (isSelectedFloorplan) { useLayer.lines.Add(new SceneMeshLine(p0, p1, Color.red)); float anchorSize = 0.05f; if (w == 0) { anchorSize *= 2; } if (w < wallSections - 1) { useLayer.dots.Add(new SceneMeshDot(p0, anchorSize, settings.anchorColour)); } } } } } if (isSelectedFloorplan) { int planVCount = planVs.Count; Vector3[] planV3 = new Vector3[planVCount]; for (int pv = 0; pv < planVCount; pv++) { planV3[pv] = planVs[pv].vector3XZ + baseUpV; } ShapeWithLines(useLayer, planV3, Color.red, new Color(1, 1, 1, 0.9f)); } } if (isSelectedFloorplan) { Room[] rooms = floorplan.AllRooms(); int roomCount = rooms.Length; List <Vector2Int> shapePoints = new List <Vector2Int>(); for (int r = 0; r < roomCount; r++) { Room room = rooms[r]; bool isRoomSelected = room == BuildingEditor.room && BuildingEditor.roomPortal == null && BuildingEditor.opening == null; shapePoints.Clear(); FloorplanUtil.RoomWall[] roomWalls = FloorplanUtil.CalculatePoints(room, volume); int roomWallCount = roomWalls.Length; Color wallCol = isRoomSelected ? settings.roomWallSelectedColour : settings.roomWallColour; Color floorCol = isRoomSelected ? settings.roomWallSelectedColour : settings.roomFloorColour; Color mainLineCol = isRoomSelected ? settings.selectedPointColour : settings.mainLineColour; Color subLineCol = isRoomSelected ? settings.selectedPointColour : settings.subLineColour; for (int rwp = 0; rwp < roomWallCount; rwp++) { FloorplanUtil.RoomWall roomWall = roomWalls[rwp]; int offsetCount = roomWall.offsetPoints.Length; Vector2Int pi0 = roomWall.baseA; Vector2Int pi1 = roomWall.baseB; if (pi0 == pi1) { continue; //not a wall } for (int op = 0; op < offsetCount - 1; op++) { Vector2Int wsint0 = new Vector2Int(roomWall.offsetPoints[op]); if (!shapePoints.Contains(wsint0)) { shapePoints.Add(wsint0); } Vector3 ws0 = new Vector3(roomWall.offsetPoints[op].x, 0, roomWall.offsetPoints[op].y) + baseUpV; if (isSelectedFloorplan)//draw anchor points { float anchorSize = 0.05f; if (op == 0) { anchorSize *= 2; } layer1.dots.Add(new SceneMeshDot(ws0, anchorSize * 0.05f, settings.linkedAnchorColour)); } int nextIndex = (op + 1) % offsetCount; Vector3 ws1 = new Vector3(roomWall.offsetPoints[nextIndex].x, 0, roomWall.offsetPoints[nextIndex].y) + baseUpV; Vector3 ws2 = ws0 + vUp; Vector3 ws3 = ws1 + vUp; layer1.lines.Add(new SceneMeshLine(ws0, ws1, mainLineCol)); layer1.lines.Add(new SceneMeshLine(ws0, ws2, subLineCol)); layer1.lines.Add(new SceneMeshLine(ws1, ws3, subLineCol)); layer1.shapes.Add(new SceneMeshShape(wallCol, ws0, ws1, ws3, ws2)); } } int shapePointsCount = shapePoints.Count; Vector3[] planV3 = new Vector3[shapePointsCount]; for (int pv = 0; pv < shapePointsCount; pv++) { planV3[pv] = shapePoints[pv].vector3XZ + baseUpV; } ShapeWithLines(layer1, planV3, mainLineCol, floorCol, settings.highlightPerpendicularity, settings.highlightPerpendicularityColour, settings.highlightAngleColour); RoomPortal[] portals = room.GetAllPortals(); int portalCount = portals.Length; for (int pt = 0; pt < portalCount; pt++) { RoomPortal portal = portals[pt]; bool isSelected = BuildingEditor.roomPortal == portal; Color portalLineColour = isSelectedFloorplan ? settings.mainLineColour : settings.subLineColour; Color portalFillColour = isSelected ? settings.selectedPointColour : settings.mainLineColour; if (!isSelectedFloorplan) { portalFillColour = Color.clear; } DrawPortal(layer2, rotation, intPlanBaseHeight, volume.floorHeight, room, portal, portalLineColour, portalFillColour); } } for (int r = 0; r < roomCount; r++) { Room room = rooms[r]; Vector3 roomCenter = room.center.vector3XZ + baseUpV + Vector3.up * volume.floorHeight; layer1.labels.Add(new SceneMeshLabel(roomCenter, string.Format("Room {0}", (r + 1)))); } } //Draw vertical openings if (BuildingEditor.floorplan != null) { VerticalOpening[] openings = building.GetAllOpenings(); int openingCount = openings.Length; for (int o = 0; o < openingCount; o++) { VerticalOpening opening = openings[o]; bool isSelectedOpening = BuildingEditor.opening == opening; Vector3 openingPosition = opening.position.vector3XZ; openingPosition.y = volume.floorHeight * opening.baseFloor; Vector3 openingSize = opening.size.vector3XZ; float openingWidth = openingSize.x; float openingHeight = openingSize.z; Quaternion openingRotation = Quaternion.Euler(0, opening.rotation, 0); Vector3 p0 = openingPosition + openingRotation * new Vector3(-openingWidth, 0, -openingHeight) * 0.5f; Vector3 p1 = openingPosition + openingRotation * new Vector3(openingWidth, 0, -openingHeight) * 0.5f; Vector3 p2 = openingPosition + openingRotation * new Vector3(openingWidth, 0, openingHeight) * 0.5f; Vector3 p3 = openingPosition + openingRotation * new Vector3(-openingWidth, 0, openingHeight) * 0.5f; Vector3 openingUp = Vector3.up * volume.floorHeight * (opening.floors + 1); //"Phil" Mitchels Color fillCol = settings.subLineColour; fillCol.a = 0.05f; layerOpengings.shapes.Add(new SceneMeshShape(fillCol, p0, p1, p2, p3)); layerOpengings.shapes.Add(new SceneMeshShape(fillCol, p0, p1, p1 + openingUp, p0 + openingUp)); layerOpengings.shapes.Add(new SceneMeshShape(fillCol, p1, p2, p2 + openingUp, p1 + openingUp)); layerOpengings.shapes.Add(new SceneMeshShape(fillCol, p2, p3, p3 + openingUp, p2 + openingUp)); layerOpengings.shapes.Add(new SceneMeshShape(fillCol, p3, p0, p0 + openingUp, p3 + openingUp)); //lines Color lineCol = settings.invertLineColour; layer0.lines.Add(new SceneMeshLine(p0, p1, lineCol)); layer0.lines.Add(new SceneMeshLine(p1, p2, lineCol)); layer0.lines.Add(new SceneMeshLine(p2, p3, lineCol)); layer0.lines.Add(new SceneMeshLine(p3, p0, lineCol)); layer0.lines.Add(new SceneMeshLine(p0 + openingUp, p1 + openingUp, lineCol)); layer0.lines.Add(new SceneMeshLine(p1 + openingUp, p2 + openingUp, lineCol)); layer0.lines.Add(new SceneMeshLine(p2 + openingUp, p3 + openingUp, lineCol)); layer0.lines.Add(new SceneMeshLine(p3 + openingUp, p0 + openingUp, lineCol)); layer0.lines.Add(new SceneMeshLine(p0, p0 + openingUp, lineCol)); layer0.lines.Add(new SceneMeshLine(p1, p1 + openingUp, lineCol)); layer0.lines.Add(new SceneMeshLine(p2, p2 + openingUp, lineCol)); layer0.lines.Add(new SceneMeshLine(p3, p3 + openingUp, lineCol)); layer0.labels.Add(new SceneMeshLabel(openingPosition + openingUp, string.Format("Opening {0}", o + 1))); if (volume == BuildingEditor.volume && BuildingEditor.floorplan != null) { Vector3 floorUpA = Vector3.up * volume.CalculateFloorHeight(volume.Floor(BuildingEditor.floorplan)); Vector3 floorUpB = floorUpA + Vector3.up * volume.floorHeight; Color col = isSelectedOpening ? Color.green : Color.red; SceneMeshLayer useLayer = isSelectedOpening ? layer2 : layer2; useLayer.lines.Add(new SceneMeshLine(p0 + floorUpA, p1 + floorUpA, col)); useLayer.lines.Add(new SceneMeshLine(p1 + floorUpA, p2 + floorUpA, col)); useLayer.lines.Add(new SceneMeshLine(p2 + floorUpA, p3 + floorUpA, col)); useLayer.lines.Add(new SceneMeshLine(p3 + floorUpA, p0 + floorUpA, col)); useLayer.lines.Add(new SceneMeshLine(p0 + floorUpB, p1 + floorUpB, col)); useLayer.lines.Add(new SceneMeshLine(p1 + floorUpB, p2 + floorUpB, col)); useLayer.lines.Add(new SceneMeshLine(p2 + floorUpB, p3 + floorUpB, col)); useLayer.lines.Add(new SceneMeshLine(p3 + floorUpB, p0 + floorUpB, col)); useLayer.lines.Add(new SceneMeshLine(p0 + floorUpA, p0 + floorUpB, col)); useLayer.lines.Add(new SceneMeshLine(p1 + floorUpA, p1 + floorUpB, col)); useLayer.lines.Add(new SceneMeshLine(p2 + floorUpA, p2 + floorUpB, col)); useLayer.lines.Add(new SceneMeshLine(p3 + floorUpA, p3 + floorUpB, col)); } } } } } }
public static void Generate(ref BuildRMesh mesh, VerticalOpening opening, int actualFloor, Vector3 basePosition, float height, int wallSubmesh = -1, BuildRCollider collider = null) { // bool lowerLanding = true; // float wallDepth = 0.5f;//todo bool generateColldier = collider != null; float wallThickness = VerticalOpening.WALL_THICKNESS; if (collider != null) { collider.thickness = VerticalOpening.WALL_THICKNESS; } // bool generateMeshCollider = generateColldier && !collider.usingPrimitives; SubmeshLibrary submeshLibrary = mesh.submeshLibrary; int externalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceA); int internalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB); int doorFrameSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceC); if (wallSubmesh != -1) { externalWallSubmesh = wallSubmesh; } if (externalWallSubmesh == -1) { externalWallSubmesh = 0; } if (internalWallSubmesh == -1) { internalWallSubmesh = 0; } if (doorFrameSubmesh == -1) { doorFrameSubmesh = 0; } //base positions Quaternion rotation = Quaternion.Euler(0, opening.rotation, 0); // Vector2Int openingSize = opening.size; Vector3 b0 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b1 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b2 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); Vector3 b3 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); //inner points Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness; Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness; Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness; Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness; //walls Vector3 wallUpInternal = Vector3.up * height; Vector3 wallUpExternal = Vector3.up * height; wallUpExternal.y += -wallThickness * 0.5f; //external mesh.AddPlane(b2, b0, b2 + wallUpExternal, b0 + wallUpExternal, externalWallSubmesh); mesh.AddPlane(b3, b2, b3 + wallUpExternal, b2 + wallUpExternal, externalWallSubmesh); mesh.AddPlane(b1, b3, b1 + wallUpExternal, b3 + wallUpExternal, externalWallSubmesh); //internal mesh.AddPlane(b0i, b2i, b0i + wallUpInternal, b2i + wallUpInternal, internalWallSubmesh); mesh.AddPlane(b2i, b3i, b2i + wallUpInternal, b3i + wallUpInternal, internalWallSubmesh); mesh.AddPlane(b3i, b1i, b3i + wallUpInternal, b1i + wallUpInternal, internalWallSubmesh); //door Vector3 b0d = b0 + rotation * (Vector3.right * opening.size.vx * 0.15f); Vector3 b1d = b1 + rotation * (Vector3.left * opening.size.vx * 0.15f); Vector3 doorUp = wallUpInternal * 0.85f; //external mesh.AddPlane(b0, b0d, b0 + doorUp, b0d + doorUp, externalWallSubmesh); mesh.AddPlane(b1d, b1, b1d + doorUp, b1 + doorUp, externalWallSubmesh); mesh.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUpExternal, b1 + wallUpExternal, externalWallSubmesh); //internal Vector3 doorFrameV = rotation * new Vector3(0, 0, 1) * wallThickness; mesh.AddPlane(b1i, b1d + doorFrameV, b1i + doorUp, b1d + doorFrameV + doorUp, internalWallSubmesh); mesh.AddPlane(b0d + doorFrameV, b0i, b0d + doorFrameV + doorUp, b0i + doorUp, internalWallSubmesh); mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUpInternal, b0i + wallUpInternal, internalWallSubmesh); //door frame mesh.AddPlane(b0d, b1d, b0d + doorFrameV, b1d + doorFrameV, doorFrameSubmesh); mesh.AddPlane(b0d, b0d + doorFrameV, b0d + doorUp, b0d + doorFrameV + doorUp, doorFrameSubmesh); mesh.AddPlane(b1d + doorFrameV, b1d, b1d + doorFrameV + doorUp, b1d + doorUp, doorFrameSubmesh); mesh.AddPlane(b0d + doorFrameV + doorUp, b1d + doorFrameV + doorUp, b0d + doorUp, b1d + doorUp, doorFrameSubmesh); if (generateColldier) { collider.AddPlane(b2, b0, b2 + wallUpExternal, b0 + wallUpExternal); collider.AddPlane(b3, b2, b3 + wallUpExternal, b2 + wallUpExternal); collider.AddPlane(b1, b3, b1 + wallUpExternal, b3 + wallUpExternal); collider.AddPlane(b0, b0d, b0 + doorUp, b0d + doorUp); collider.AddPlane(b1d, b1, b1d + doorUp, b1 + doorUp); collider.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUpExternal, b1 + wallUpExternal); if (!collider.usingPrimitives) { collider.mesh.AddPlane(b0i, b2i, b0i + wallUpInternal, b2i + wallUpInternal, 0); collider.mesh.AddPlane(b2i, b3i, b2i + wallUpInternal, b3i + wallUpInternal, 0); collider.mesh.AddPlane(b3i, b1i, b3i + wallUpInternal, b1i + wallUpInternal, 0); collider.mesh.AddPlane(b1i, b1d + doorFrameV, b1i + doorUp, b1d + doorFrameV + doorUp, 0); collider.mesh.AddPlane(b0d + doorFrameV, b0i, b0d + doorFrameV + doorUp, b0i + doorUp, 0); collider.mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUpInternal, b0i + wallUpInternal, 0); collider.mesh.AddPlane(b0d, b1d, b0d + doorFrameV, b1d + doorFrameV, 0); collider.mesh.AddPlane(b0d, b0d + doorFrameV, b0d + doorUp, b0d + doorFrameV + doorUp, 0); collider.mesh.AddPlane(b1d + doorFrameV, b1d, b1d + doorFrameV + doorUp, b1d + doorUp, 0); collider.mesh.AddPlane(b0d + doorFrameV + doorUp, b1d + doorFrameV + doorUp, b0d + doorUp, b1d + doorUp, 0); } } }
public static VerticalOpening[] GetOpenings(Building building, Volume volume) { List <VerticalOpening> output = new List <VerticalOpening>(); int count = building.openingCount; VerticalOpening[] openings = building.GetAllOpenings(); int volumeBaseFloor = building.VolumeBaseFloor(volume); int volumeTopFloor = volumeBaseFloor + volume.floors; for (int i = 0; i < count; i++) { VerticalOpening opening = openings[i]; int openingBaseFloor = opening.baseFloor; int openingTopFloor = openingBaseFloor + opening.floors - 1; if (volumeBaseFloor < openingTopFloor && openingBaseFloor < volumeTopFloor)//opening and volume floors intersect { FlatBounds volumeBounds = new FlatBounds(volume.bounds); Vector2[] openingPoints = opening.PointsRotated(); FlatBounds openingBounds = new FlatBounds(openingPoints); if (volumeBounds.Overlaps(openingBounds, true))// opening is within the AABB bounds of the volume { Vector2[] volumePoints = volume.AllPointsV2(); int volumePointCount = volumePoints.Length; int openingPointCount = openingPoints.Length; bool openingIntersects = false; for (int op = 0; op < openingPointCount; op++) { Vector2 opa = openingPoints[op]; Vector2 opb = openingPoints[(op + 1) % openingPointCount]; for (int vp = 0; vp < volumePointCount; vp++) { Vector2 vpa = volumePoints[vp]; Vector2 vpb = volumePoints[(vp + 1) % volumePointCount]; if (FastLineIntersection(opa, opb, vpa, vpb)) { openingIntersects = true; } if (openingIntersects) { break; } } if (openingIntersects) { break; } } if (!openingIntersects)//check that the opening is within the volume shape { Vector2 opa = openingPoints[0]; Vector2 opb = openingPoints[1]; int intersections = 0;//we should intersect an odd number of times for (int vp = 0; vp < volumePointCount; vp++) { Vector2 vpa = volumePoints[vp]; Vector2 vpb = volumePoints[(vp + 1) % volumePointCount]; if (FastLineIntersection(opa, opb, vpa, vpb)) { intersections++; } } if (intersections % 2 != 0) { output.Add(opening); } } } } } return(output.ToArray()); }