/// <summary> /// <b>호출</b> : ElementPresenter.MakeWall()<br></br> /// <b>참조</b> : CalcPadding(),FindRotateAngle(), MakeMesh.MakeWalls(), Outliner.FindAllOutline()<br></br> /// 문/창문 위치 반영한 벽 생성 함수. /// Outliner로 방의 외곽선 점을 얻은 다음, /// 그 점들을 따라 quad로 기준이 될 벽을 생성하고, /// MakeMesh.MakeWalls()으로 기준 벽에 문/창문 오브젝트의 정보를 반영하여 새로운 벽 오브젝트를 생성한 뒤, /// 생성된 오브젝트와 그 벽의 면적을 딕셔너리로 묶어서 저장하여 반환한다. /// </summary> /// <param name="rooms">모든 방 리스트</param> /// <param name="elements">모든 문/창문 오브젝트 리스트</param> /// <param name="height">벽 높이</param> /// <param name="material">생성된 벽에 적용할 기본 재질</param> /// <param name="wallParent">생성된 벽 오브젝트를 담을 부모 오브젝트</param> /// <param name="isDebug">디버그 옵션</param> /// <returns>생성된 벽 오브젝트와 벽의 면적을 담은 딕셔너리</returns> public static Dictionary <Transform, float> MakeWalls(List <Transform> rooms, List <Transform> elements, float height, Material material, out Transform wallParent, bool isDebug = false) { Dictionary <Transform, float> generatedWallList = new Dictionary <Transform, float>(); wallParent = new GameObject().transform; wallParent.transform.parent = rooms[0].parent; wallParent.name = "Walls"; foreach (var room in rooms) { // 방 외곽선을 이루는 점 수집 List <Transform> subFloors = new List <Transform>(); for (int i = 0; i < room.childCount; i++) { subFloors.Add(room.GetChild(i)); } Outliner outliner = new Outliner(); List <List <Dot> > allDots = outliner.FindAllOutline(subFloors); // 외곽선을 따라 벽 오브젝트 생성 foreach (var dots in allDots) { for (int i = 0; i < dots.Count; i++) { Vector3 dot1 = dots[i].position; Vector3 dot2 = dots[(i + 1) % dots.Count].position; // quad로 기준 벽을 생성 Transform wall = GameObject.CreatePrimitive(PrimitiveType.Quad).transform; float angle = FindRotateAngle(dot1, dot2); Vector3 padding = CalcPadding(angle); wall.position = (dot1 + dot2) * 0.5f + Vector3.up * height * 0.5f; wall.GetComponent <Renderer>().material.color = Color.black; wall.localScale = new Vector3(Mathf.Max(Mathf.Abs(dot1.x - dot2.x), Mathf.Abs(dot1.z - dot2.z)), height, 1); wall.Rotate(Vector3.up * angle); // 기준 벽과 문/창문 오브젝트 정보를 이용하여 새로운 벽 오브젝트 생성 Transform madeWall = MakeMesh.MakeWalls(wall, elements, material, out float area, isDebug).transform; generatedWallList.Add(madeWall, area); madeWall.parent = wallParent; GameObject.Destroy(wall.gameObject); } } } return(generatedWallList); }
/// <summary> /// <b>호출</b> : ElementPresenter.MakeWall()<br></br> /// <b>참조</b> : FindRotateAngle(), MakeMesh.MakeWalls(), Outliner.FindAllOutline()<br></br> /// 외곽벽을 생성하는 함수. /// Outliner를 이용하여 전체 방의 외곽 점을 수집한 뒤, 점사이 공간에 quad로 임시 벽을 생성한다. /// 임시벽의 위치, 크기, 회전을 참조해서 문/창문 오브젝트를 고려한 벽을 MakeMesh 클래스를 이용하여 생성한다. /// </summary> /// <param name="allFloors">전체 바닥 정보</param> /// <param name="elements">문/창문 리스트</param> /// <param name="border">벽 두께</param> /// <param name="height">벽 높이</param> /// <param name="material">외곽벽 생성시 적용할 기본 오브젝트</param> /// <returns>생성된 외곽벽 오브젝트를 담은 부모 오브젝트</returns> public static GameObject MakeOutlineWalls(List <Transform> allFloors, List <Transform> elements, float border, float height, Material material) { // 위치,크기,회전 참조를 위해 quad로 임시 생성한 벽 오브젝트를 담을 부모 오브젝트 Transform wallParent = new GameObject().transform; wallParent.name = "OutlineWalls"; // 문/창문 오브젝트를 고려하여 다시 생성한 벽 오브젝트를 담을 부모 오브젝트 Transform outlinewallParent = new GameObject().transform; outlinewallParent.name = "OutlineWalls"; // 전체 방 외곽 점 수집 Outliner outliner = new Outliner(); List <List <Dot> > allDots = outliner.FindAllOutline(allFloors); foreach (var dots in allDots) { for (int i = 0; i < dots.Count; i++) { Vector3 dot1 = dots[i].position; Vector3 dot2 = dots[(i + 1) % dots.Count].position; float angle = FindRotateAngle(dot1, dot2); // 임시 벽 생성 Transform wall = GameObject.CreatePrimitive(PrimitiveType.Quad).transform; wall.position = (dot1 + dot2) * 0.5f + Vector3.up * height * 0.5f; wall.localScale = new Vector3(Mathf.Max(Mathf.Abs(dot1.x - dot2.x), Mathf.Abs(dot1.z - dot2.z)), height, 1); wall.Rotate(Vector3.up * ((angle + 180) % 360)); wall.parent = wallParent; // 문/창문 고려한 벽 생성 Transform madeWall = MakeMesh.MakeWalls(wall, elements, material, out float area).transform; madeWall.parent = outlinewallParent; madeWall.GetComponent <Renderer>().receiveShadows = false; } } GameObject.Destroy(wallParent.gameObject); return(outlinewallParent.gameObject); }
/// <summary> /// <b>호출</b> : SpacePresenter.ShowFloorsLabel() <br></br> /// <b>참조</b> : AttachLabels(), Visualize(), Outliner.FindAllOutline() <br></br> /// 방의 각 벽 수치를 표시하는 함수. /// Outliner에서 방의 외곽선을 이루는 점 리스트를 받아오고, 각 점을 이어서 길이를 두 점 사이에 표시한다. /// </summary> /// <param name="room">수치 표시를 나타낼 방</param> /// <param name="labelTransform">라벨 오브젝트를 담을 부모 오브젝트</param> /// <param name="textPrefab">글자를 나타낼 프리팹</param> /// <param name="linePrefab">치수선 프리팹</param> /// <param name="isDebug">디버그 옵션</param> /// <param name="option">치수 표현 옵션(0 : 방 바깥쪽에 표시, 1: 벽 가운데에 표시, 2: 방 내부에 표시)</param> public static List <Transform> ShowRoomSize(List <Transform> subFloors, Transform labelTransform, GameObject textPrefab, GameObject linePrefab, bool isDebug = false, int option = 0) { List <Transform> labels = new List <Transform>(); List <Dot> allDots = new List <Dot>(); Outliner outliner = new Outliner(); Transform roomLabelParent = new GameObject("RoomLabel").transform; roomLabelParent.parent = labelTransform; try { List <List <Dot> > outlineAllDots = outliner.FindAllOutline(subFloors, isDebug); foreach (var outlineDots in outlineAllDots) { AttachLabels(outlineDots, roomLabelParent, textPrefab, linePrefab, option); allDots.AddRange(outlineDots.ToArray()); } return(labels); } catch (System.Exception) { //Debug.Log(e); } // 디버그 옵션을 위한 부분 : 점 시각화를 통해 점 생성이 정상적인지 체크. Transform debugParent = GameObject.Find("DebugParent").transform; if (isDebug && debugParent != null) { for (int i = 0; i < debugParent.childCount; i++) { GameObject.Destroy(debugParent.GetChild(i).gameObject); } debugParent.position = Vector3.zero; Util.Visualize(allDots, debugParent); debugParent.position = Vector3.up * 3f; } return(null); }
/// <summary> /// <b>호출</b> : SpacePresneter.MakeWallsAndFloors()<br></br> /// <b>참조</b> : IsClockwise(), FindRotateAngle(), CalcPadding(), Outliner.FindAllOutline() <br></br> /// 요소설정 단계에서 문/창문 설치를 위해 병합된 모든 방의 벽 윗부분(WallTop)을 생성하는 부분. /// Outliner로 각 방의 외곽선을 이루는 점을 수집한 뒤, /// 각 점 중간 부분에 두 점 사이 길이를 갖는 벽 오브젝트를 quad로 생성한다. /// 벽이 서로 직각으로 생성되는 경우 두 벽 사이에 빈 공간이 발생할 수 있는데, /// 이 부분을 메꾸기 위해 정사각형의 wallPoint를 추가로 생성하여 배치한다. /// 벽의 방향을 비교하여 가로 벽인지 세로 벽인지 구분하여 요소설정 단계에서 이용할 수 있도록 모델 클래스에 정보를 저장한다. /// </summary> /// <param name="rooms">모든 방 리스트</param> /// <param name="border">벽 두께</param> /// <param name="height">벽 높이</param> /// <returns>생성된 WallTop 오브젝트들이 담긴 부모 오브젝트</returns> public static GameObject MakeWallTops(List <Transform> rooms, float border, float height) { // 오브젝트들을 담을 부모 오브젝트 생성 // 실제로 꾸미기가 가능한 내벽을 제외한 나머지 벽 오브젝트를 담을 부모 모브젝트 Transform outwalls = new GameObject().transform; // 벽 윗부분 Transform wallTopParent = new GameObject().transform; // 벽 윗부분 중에서 모서리 점 부분 Transform wallPointParent = new GameObject().transform; outwalls.parent = rooms[0].parent; wallTopParent.parent = outwalls; wallPointParent.parent = outwalls; outwalls.name = "OutWalls"; wallTopParent.name = "WallsTop"; wallPointParent.name = "Points"; foreach (var room in rooms) { List <Transform> subFloors = new List <Transform>(); for (int i = 0; i < room.childCount; i++) { subFloors.Add(room.GetChild(i)); } Outliner outliner = new Outliner(); List <List <Dot> > allDots = outliner.FindAllOutline(subFloors); foreach (var dots in allDots) { //Visualize(dots, "outlineDots"); float beforeAngle = 0; for (int i = 0; i < dots.Count; i++) { Vector3 dot1 = dots[i].position; Vector3 dot2 = dots[(i + 1) % dots.Count].position; Transform wallTop = GameObject.CreatePrimitive(PrimitiveType.Quad).transform; wallTop.Rotate(Vector3.right * 90); // 두 점의 x,z값을 비교하여 벽의 회전 각도(0,90,180,270)를 구한다 float angle = FindRotateAngle(dot1, dot2); // 각도에 따라 두께만큼 이동할 방향을 계산한다. Vector3 padding = CalcPadding(angle); wallTop.localScale = new Vector3(Mathf.Max(Mathf.Abs(dot1.x - dot2.x), border), Mathf.Max(Mathf.Abs(dot1.z - dot2.z), border), height); wallTop.GetComponent <Renderer>().material.color = Color.black; wallTop.position = (dot1 + dot2) * 0.5f + Vector3.up * height + padding * border * 0.5f; wallTop.parent = wallTopParent; wallTop.GetComponent <Renderer>().material.color = Color.black; wallTop.GetComponent <Renderer>().receiveShadows = false; wallTop.gameObject.AddComponent <BoxCollider>(); wallTop.GetComponent <BoxCollider>().size = new Vector3(wallTop.localScale.x == border ? 2 : 1, wallTop.localScale.x == border ? 1 : 2, 0); // 모델의 벽 리스트에 생성된 벽을 방향 정보와 함께 추가한다. Model.Instance.WallList.Add( new Model.Wall(wallTop.gameObject, wallTop.localScale.x == border ? Model.Wall.WallDirection.Vertical : Model.Wall.WallDirection.Landscape)); //이전 angle과 비교했을때 반시계 방향으로 생성되면 -> 땜빵을 메꾸기 위해 가운데 모서리 생성 if (i == 0) { beforeAngle = FindRotateAngle(dots[(i - 1 + dots.Count) % dots.Count].position, dots[i].position); } if (IsClockwise(angle, beforeAngle)) { Transform point = GameObject.CreatePrimitive(PrimitiveType.Quad).transform; point.Rotate(Vector3.right * 90); point.localScale = Vector3.one * border; Vector3 padding2 = CalcPadding((angle + 90) % 360); point.position = dot1 + Vector3.up * height + (padding - padding2) * border * 0.5f; point.GetComponent <Renderer>().material.color = Color.black; point.GetComponent <Renderer>().receiveShadows = false; // 요소설정 단계에서 벽의 끝부분을 감지하기 위해 collider를 추가한다. BoxCollider box = point.gameObject.AddComponent(typeof(BoxCollider)) as BoxCollider; box.size = new Vector3(1, 1.1f, 1.1f); box = point.gameObject.AddComponent(typeof(BoxCollider)) as BoxCollider; box.size = new Vector3(1.1f, 1, 11.1f); point.parent = wallPointParent; point.tag = "CorssPoint"; } beforeAngle = angle == -90 ? 270 : angle; } } } return(wallTopParent.gameObject); }