Пример #1
0
    /// <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);
    }
Пример #2
0
    /// <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);
    }
Пример #3
0
    /// <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);
    }
Пример #4
0
    /// <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);
    }