public static void Generate(IBuilding building)
        {
            int numberOfVolumes = building.numberOfPlans;

            for (int v = 0; v < numberOfVolumes; v++)
            {
                IVolume volume = building[v];
                volume.CheckVolume();
                if (!volume.isLegal)
                {
                    GenerateMesh.ClearVisuals(volume);
                    continue;
                }
                int     numberOfPoints  = volume.numberOfPoints;
                float   totalPlanHeight = volume.planHeight;
                Vector3 planUp          = totalPlanHeight * Vector3.up;
//                List<Surface> usedFloorplanSurfaces = volume.CalculateSurfaceArray();
                //                VerticalOpening[] volumeOpenings = BuildrUtils.GetOpeningsQuick(building, volume);

                IVisualPart           visual       = volume.visualPart;
                BuildRMesh            dMesh        = visual.dynamicMesh;
                BuildRCollider        cMesh        = visual.colliderMesh;
                BuildingMeshTypes     meshType     = building.meshType;
                BuildingColliderTypes colliderType = building.colliderType;
                dMesh.Clear();
                dMesh.ignoreSubmeshAssignment = true;
                cMesh.Clear();
                cMesh.TogglePrimitives(colliderType == BuildingColliderTypes.Primitive);
                cMesh.thickness = volume.wallThickness;

                if (meshType == BuildingMeshTypes.None && colliderType == BuildingColliderTypes.None)
                {
                    visual.Clear();
                    return;
                }

                Dictionary <int, List <Vector2Int> > anchorPoints = volume.facadeWallAnchors;
                Texture2D facadeTexture   = null;
                Rect[]    faciaRectangles = null;
                Rect[]    faciaUVs        = null;
                Rect      roofRect        = new Rect();
                Rect      roofPixelRect   = new Rect();

                #region Exteriors

                if (building.generateExteriors)
                {
                    //                    List<Rect> faciaRectangles = null;
                    faciaRectangles = new Rect[numberOfPoints + 1];                                  //one additional for the roof
                    float foundation = building.IsBaseVolume(volume) ? building.foundationDepth : 0; //set suspended volumes foundation to 0

                    //                    faciaRectangles = new List<Rect>();
                    for (int p = 0; p < numberOfPoints; p++)
                    {
                        if (!volume[p].render)
                        {
                            continue;
                        }
                        int        indexA = p;
                        int        indexB = (p < numberOfPoints - 1) ? p + 1 : 0;
                        Vector2Int p0     = volume[indexA].position;
                        Vector2Int p1     = volume[indexB].position;

                        float facadeWidth = Vector2Int.DistanceWorld(p0, p1) * PIXELS_PER_METER;
                        int   floorBase   = BuildRFacadeUtil.MinimumFloor(building, volume, indexA);

                        int numberOfFloors = volume.floors - floorBase;
                        if (numberOfFloors < 1)//no facade - adjacent facade is taller and covers this one
                        {
                            continue;
                        }

                        float floorHeight  = volume.floorHeight;
                        float facadeHeight = ((volume.floors - floorBase) * floorHeight) * PIXELS_PER_METER;
                        if (facadeHeight < 0)//??
                        {
                            facadeWidth  = 0;
                            facadeHeight = 0;
                        }

                        Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight);
                        faciaRectangles[p] = newFacadeRect;
                        //                        Debug.Log(newFacadeRect);
                        //                        faciaRectangles.Add(newFacadeRect);
                    }

                    roofRect      = new Rect(0, 0, volume.bounds.size.x, volume.bounds.size.z);
                    roofPixelRect = new Rect(0, 0, volume.bounds.size.x * PIXELS_PER_METER, volume.bounds.size.z * PIXELS_PER_METER);
                    faciaRectangles[numberOfPoints] = roofPixelRect;
                    //                    Debug.Log(roofRect);

                    int currentWidth = RectanglePack.Pack(faciaRectangles, ATLAS_PADDING);
                    currentWidth  = RectanglePack.CheckMaxScale(faciaRectangles, currentWidth, MAXIMUM_TEXTURESIZE);
                    faciaUVs      = RectanglePack.ConvertToUVSpace(faciaRectangles, currentWidth);
                    facadeTexture = new Texture2D(currentWidth, currentWidth);


                    //                    float uvOffsetX = 0;
                    int rectIndex = 0;
                    for (int p = 0; p < numberOfPoints; p++)
                    {
                        if (!volume[p].render)
                        {
                            continue;
                        }

                        Vector3 p0 = volume.BuildingPoint(p);
                        Vector3 p1 = volume.BuildingPoint((p + 1) % numberOfPoints);

                        Vector3 p0u        = p0 + planUp;
                        Vector3 p1u        = p1 + planUp;
                        Vector3 cw0        = volume.BuildingControlPointA(p);
                        Vector3 cw1        = volume.BuildingControlPointB(p);
                        Facade  facade     = volume.GetFacade(p);
                        bool    isStraight = volume.IsWallStraight(p);

                        Vector3 facadeVector    = p1 - p0;
                        Vector3 facadeDirection = facadeVector.normalized;

                        FacadeGenerator.FacadeData fData = new FacadeGenerator.FacadeData();
                        fData.baseA        = p0;
                        fData.baseB        = p1;
                        fData.controlA     = cw0;
                        fData.controlB     = cw1;
                        fData.anchors      = anchorPoints[p];
                        fData.isStraight   = isStraight;
                        fData.curveStyle   = volume[p].curveStyle;
                        fData.floorCount   = volume.floors;
                        fData.facadeDesign = facade;

                        fData.wallThickness         = volume.wallThickness;
                        fData.minimumWallUnitLength = volume.minimumWallUnitLength;
                        fData.floorHeight           = volume.floorHeight;
                        fData.floors       = volume.floors;
                        fData.meshType     = building.meshType;
                        fData.colliderType = building.colliderType;
                        fData.cullDoors    = building.cullDoors;
                        fData.prefabs      = volume.prefabs;
                        //                        fData.submeshList = usedFloorplanSurfaces;
                        fData.startFloor = BuildRFacadeUtil.MinimumFloor(building, volume, p);

                        if (isStraight)
                        {
                            Vector3 normal  = Vector3.Cross(Vector3.up, facadeDirection);
                            Vector4 tangent = BuildRMesh.CalculateTangent(facadeDirection);

                            Vector3 fp2 = p0;
                            Vector3 fp3 = p1;
                            Vector3 fp0 = fp2 + Vector3.down * foundation;
                            Vector3 fp1 = fp3 + Vector3.down * foundation;

                            if (meshType == BuildingMeshTypes.Simple)
                            {
                                //                                if(facade != null)
                                //                                {
                                if (facade != null)
                                {
                                    SimpleTextureGenerator.GenerateFacade(fData, facadeTexture, faciaRectangles[rectIndex]);
                                }
                                Vector3[] verts  = { p0, p1, p0u, p1u };
                                Vector2[] uvs    = new Vector2[4];
                                Rect      uvRect = faciaUVs[rectIndex];
                                uvs[0] = new Vector2(uvRect.xMin, uvRect.yMin);
                                uvs[1] = new Vector2(uvRect.xMax, uvRect.yMin);
                                uvs[2] = new Vector2(uvRect.xMin, uvRect.yMax);
                                uvs[3] = new Vector2(uvRect.xMax, uvRect.yMax);
                                int[]     tris     = { 0, 2, 1, 1, 2, 3 };
                                Vector3[] norms    = { normal, normal, normal, normal };
                                Vector4[] tangents = { tangent, tangent, tangent, tangent };
                                dMesh.AddData(verts, uvs, tris, norms, tangents, 0);

                                if (foundation > Mathf.Epsilon)
                                {
                                    dMesh.AddPlane(fp0, fp1, fp2, fp3, uvs[0], uvs[0], normal, tangent, 0, null);
                                }
                            }
                            else
                            {
                                dMesh.AddPlane(p0, p1, p0u, p1u, normal, tangent, 0);

                                if (foundation > Mathf.Epsilon)
                                {
                                    dMesh.AddPlane(fp0, fp1, fp2, fp3, normal, tangent, 0);
                                }
                            }

                            if (colliderType != BuildingColliderTypes.None)
                            {
                                cMesh.AddPlane(p0, p1, p0u, p1u);
                                if (foundation > Mathf.Epsilon)
                                {
                                    cMesh.mesh.AddPlane(fp0, fp1, fp2, fp3, 0);
                                }
                            }
                        }
                        else
                        {
                            List <Vector2Int> facadeAnchorPoints = anchorPoints[p];
                            int anchorCount = facadeAnchorPoints.Count;
                            for (int i = 0; i < anchorCount - 1; i++)
                            {
                                Vector3 c0 = facadeAnchorPoints[i].vector3XZ;
                                c0.y = p0.y;
                                Vector3 c1 = facadeAnchorPoints[i + 1].vector3XZ;
                                c1.y = p0.y;
                                Vector3 c2 = c0 + planUp;
                                Vector3 c3 = c1 + planUp;
                                Vector3 sectionDirection = (c1 - c0).normalized;
                                Vector3 normal           = Vector3.Cross(Vector3.up, sectionDirection);
                                Vector4 tangent          = BuildRMesh.CalculateTangent(sectionDirection);

                                Vector3 fp2 = c0;
                                Vector3 fp3 = c1;
                                Vector3 fp0 = fp2 + Vector3.down * foundation;
                                Vector3 fp1 = fp3 + Vector3.down * foundation;

                                if (meshType == BuildingMeshTypes.Simple)
                                {
                                    if (facade != null)
                                    {
                                        SimpleTextureGenerator.GenerateFacade(fData, facadeTexture, faciaRectangles[rectIndex]);
                                    }
                                    Rect      uvRect         = faciaUVs[rectIndex];
                                    float     facadePercentA = i / (float)(anchorCount - 1);
                                    float     facadePercentB = (i + 1) / (float)(anchorCount - 1);
                                    float     uvxa           = uvRect.xMin + uvRect.width * facadePercentA;
                                    float     uvxb           = uvRect.xMin + uvRect.width * facadePercentB;
                                    Vector3[] verts          = { c0, c1, c2, c3 };
                                    Vector2[] uvs            = new Vector2[4];
                                    uvs[0] = new Vector2(uvxa, uvRect.yMin);
                                    uvs[1] = new Vector2(uvxb, uvRect.yMin);
                                    uvs[2] = new Vector2(uvxa, uvRect.yMax);
                                    uvs[3] = new Vector2(uvxb, uvRect.yMax);
                                    int[]     tris     = { 0, 2, 1, 1, 2, 3 };
                                    Vector3[] norms    = { normal, normal, normal, normal };
                                    Vector4[] tangents = { tangent, tangent, tangent, tangent };
                                    //                                        Vector2 uvMin = new Vector2(uvOffsetX, 0);
                                    //                                        Vector2 uvMax = new Vector2(uvOffsetX + facadeLength, totalPlanHeight);

                                    dMesh.AddData(verts, uvs, tris, norms, tangents, 0);
                                    //                                    dMesh.AddPlane(p0, p1, p0u, p1u, uvMin, uvMax, normal, tangent, 0);
                                    //todo simple mesh with textured facade
                                    //                                    rectIndex++;

                                    if (foundation > Mathf.Epsilon)
                                    {
                                        dMesh.AddPlane(fp0, fp1, fp2, fp3, uvs[0], uvs[0], normal, tangent, 0, null);
                                    }
                                }
                                else
                                {
                                    dMesh.AddPlane(p0, p1, p0u, p1u, normal, tangent, 0);

                                    if (foundation > Mathf.Epsilon)
                                    {
                                        dMesh.AddPlane(fp0, fp1, fp2, fp3, normal, tangent, 0);
                                    }
                                }

                                if (colliderType != BuildingColliderTypes.None)
                                {
                                    cMesh.AddPlane(c0, c1, c2, c3);

                                    if (foundation > Mathf.Epsilon)
                                    {
                                        cMesh.mesh.AddPlane(fp0, fp1, fp2, fp3, 0);
                                    }
                                }
                            }
                        }
                        rectIndex++;
                    }
                }

                #endregion

                #region Interiors

                IFloorplan[] floorplans = volume.InteriorFloorplans();
                int          floors     = volume.floors;
                for (int fl = 0; fl < floors; fl++)
                {
                    floorplans[fl].visualPart.Clear();
                }

                #endregion

                #region Volume Underside Generation

                BuildRVolumeUtil.VolumeShape[] underShapes = BuildRVolumeUtil.GetBottomShape(building, volume);
                int underShapeCount = underShapes.Length;
                //                Debug.Log(underShapeCount);
                float volumeBaseHeight = volume.baseHeight;
                for (int u = 0; u < underShapeCount; u++)
                {
                    //                    Debug.Log(underShapes[u].outer);
                    if (underShapes[u].outer == null)
                    {
                        continue;                              //no underside shape
                    }
                    //                    Debug.Log(underShapes[u].outer.Length);

                    Poly2TriWrapper.BMesh(dMesh, volumeBaseHeight, null, 0, underShapes[u].outer, new Rect(0, 0, 0, 0), false, underShapes[u].holes);
                }

                #endregion

                if (building.generateExteriors)
                {
                    Surface roofSurface = volume.roof.mainSurface;
                    if (roofSurface != null)
                    {
                        SimpleTextureGenerator.GenerateTexture(facadeTexture, roofSurface, faciaRectangles[faciaRectangles.Length - 1], roofRect);
                    }
                    RoofGenerator.Generate(building, volume, dMesh, cMesh, faciaUVs[faciaUVs.Length - 1]);
                    visual.GenerateFromDynamicMesh();
                }
                else
                {
                    visual.Clear();
                }

                switch (meshType)
                {
                case BuildingMeshTypes.Box:
                    visual.materials = new[] { new Material(Shader.Find("Standard")) };
                    break;

                case BuildingMeshTypes.Simple:
                    facadeTexture.filterMode = FilterMode.Bilinear;
                    facadeTexture.Apply(true, false);
                    Material simpleMaterial = new Material(Shader.Find("Standard"));
                    simpleMaterial.mainTexture = facadeTexture;
                    visual.materials           = new[] { simpleMaterial };
                    break;
                }
            }
        }
Ejemplo n.º 2
0
        public static void Generate(IBuilding building)
        {
            int numberOfVolumes = building.numberOfVolumes;

//            Debug.Log("n vol "+numberOfVolumes);
            for (int v = 0; v < numberOfVolumes; v++)
            {
                IVolume volume = building[v];
                volume.CheckVolume();
                if (!volume.isLegal)
                {
                    GenerateMesh.ClearVisuals(volume);
                    continue;
                }

                int                   numberOfPoints  = volume.numberOfPoints;
                float                 totalPlanHeight = volume.planHeight;
                Vector3               planUp          = totalPlanHeight * Vector3.up;
                VerticalOpening[]     volumeOpenings  = BuildrUtils.GetOpeningsQuick(building, volume);
                float                 foundation      = building.IsBaseVolume(volume) ? building.foundationDepth : 0;//set suspended volumes foundation to 0
                IVisualPart           visual          = volume.visualPart;
                BuildRMesh            dMesh           = visual.dynamicMesh;
                BuildRCollider        cMesh           = visual.colliderMesh;
                BuildingMeshTypes     meshType        = building.meshType;
                BuildingColliderTypes colliderType    = building.colliderType;
                dMesh.Clear();
                cMesh.Clear();
                cMesh.TogglePrimitives(colliderType == BuildingColliderTypes.Primitive);
                cMesh.thickness = volume.wallThickness;
                if (colliderType == BuildingColliderTypes.None)
                {
                    cMesh = null;
                }
                Transform[] prefabs     = volume.prefabs.GetComponentsInChildren <Transform>();
                int         prefabCount = prefabs.Length;
                for (int p = 0; p < prefabCount; p++)
                {
                    if (prefabs[p] == volume.prefabs)
                    {
                        continue;
                    }
                    if (prefabs[p] == null)
                    {
                        continue;                   //gone already man
                    }
#if UNITY_EDITOR
                    Object.DestroyImmediate(prefabs[p].gameObject);
#else
                    Object.Destroy(prefabs[p].gameObject);
#endif
                }

                Dictionary <int, List <Vector2Int> > anchorPoints = volume.facadeWallAnchors;
                Texture2D facadeTexture = null;

                #region Exteriors

//                Debug.Log("ext");
                if (building.generateExteriors)
                {
                    for (int p = 0; p < numberOfPoints; p++)
                    {
                        if (!volume[p].render)
                        {
                            continue;
                        }
                        Vector3 p0              = volume.BuildingPoint(p);
                        Vector3 p1              = volume.BuildingPoint((p + 1) % numberOfPoints);
                        Vector3 p0u             = p0 + planUp;
                        Vector3 p1u             = p1 + planUp;
                        Vector3 cw0             = volume.BuildingControlPointA(p);
                        Vector3 cw1             = volume.BuildingControlPointB(p);
                        Facade  facade          = volume.GetFacade(p);
                        bool    isStraight      = volume.IsWallStraight(p);
                        Vector3 facadeVector    = p1 - p0;
                        Vector3 facadeDirection = facadeVector.normalized;
                        float   facadeLength    = facadeVector.magnitude;
                        if (facadeLength < Mathf.Epsilon)
                        {
                            continue;
                        }

//                        Debug.Log("flength "+facadeLength);
                        if (facade == null || colliderType == BuildingColliderTypes.Simple)
                        {
//                            Debug.Log("simple");
                            if (isStraight)
                            {
                                Vector3 normal  = Vector3.Cross(Vector3.up, facadeDirection);
                                Vector4 tangent = BuildRMesh.CalculateTangent(facadeDirection);
                                if (facade == null)
                                {
                                    dMesh.AddPlane(p0, p1, p0u, p1u, normal, tangent, 0);
                                }

                                if (colliderType != BuildingColliderTypes.None)
                                {
                                    cMesh.AddPlane(p0, p1, p0u, p1u);
                                }

                                if (foundation > Mathf.Epsilon)
                                {
                                    Vector3 fp2 = p0;
                                    Vector3 fp3 = p1;
                                    Vector3 fp0 = fp2 + Vector3.down * foundation;
                                    Vector3 fp1 = fp3 + Vector3.down * foundation;
                                    if (facade == null)
                                    {
                                        Surface foundationSurface = building.foundationSurface != null ? building.foundationSurface : null;
                                        int     foundationSubmesh = dMesh.submeshLibrary.SubmeshAdd(foundationSurface);
                                        Vector2 uxmax             = new Vector2(Vector3.Distance(p0, p1), foundation);
                                        dMesh.AddPlane(fp0, fp1, fp2, fp3, Vector2.zero, uxmax, normal, tangent, foundationSubmesh, foundationSurface);
                                    }

                                    if (colliderType != BuildingColliderTypes.None)
                                    {
                                        cMesh.mesh.AddPlane(fp0, fp1, fp2, fp3, 0);
                                    }
                                }
                            }
                            else
                            {
                                List <Vector2Int> facadeAnchorPoints = anchorPoints[p];
                                int anchorCount = facadeAnchorPoints.Count;
                                for (int i = 0; i < anchorCount - 1; i++)
                                {
                                    Vector3 c0 = facadeAnchorPoints[i].vector3XZ;
                                    c0.y = p0.y;
                                    Vector3 c1 = facadeAnchorPoints[i + 1].vector3XZ;
                                    c1.y = p0.y;
                                    Vector3 c2 = c0 + planUp;
                                    Vector3 c3 = c1 + planUp;
                                    Vector3 sectionDirection = (c1 - c0).normalized;
                                    Vector3 normal           = Vector3.Cross(Vector3.up, sectionDirection);
                                    Vector4 tangent          = BuildRMesh.CalculateTangent(sectionDirection);
                                    if (facade == null)
                                    {
                                        dMesh.AddPlane(c0, c1, c2, c3, normal, tangent, 0);
                                    }
                                    if (colliderType != BuildingColliderTypes.None)
                                    {
                                        cMesh.AddPlane(c0, c1, c2, c3);
                                    }
                                    if (foundation > Mathf.Epsilon)
                                    {
                                        Vector3 fp2 = c0;
                                        Vector3 fp3 = c1;
                                        Vector3 fp0 = fp2 + Vector3.down * foundation;
                                        Vector3 fp1 = fp3 + Vector3.down * foundation;

                                        if (facade == null)
                                        {
                                            Surface foundationSurface = building.foundationSurface != null ? building.foundationSurface : null;
                                            int     foundationSubmesh = dMesh.submeshLibrary.SubmeshAdd(foundationSurface);
                                            Vector2 uxmax             = new Vector2(Vector3.Distance(c0, c1), foundation);
                                            dMesh.AddPlane(fp0, fp1, fp2, fp3, Vector2.zero, uxmax, normal, tangent, foundationSubmesh, foundationSurface);
                                        }

                                        if (colliderType != BuildingColliderTypes.None)
                                        {
                                            cMesh.AddPlane(fp0, fp1, fp2, fp3);
                                        }
                                    }
                                }
                            }

//                                                        Debug.Log("Generate facade " + p + " " + dMesh.vertexCount  );
                        }

//                        Debug.Log("fac "+p);
                        if (facade != null && (meshType == BuildingMeshTypes.Full || colliderType == BuildingColliderTypes.Primitive || colliderType == BuildingColliderTypes.Complex))
                        {
                            //generate the facade
//                            Debug.Log("full");
                            FacadeGenerator.FacadeData fData = new FacadeGenerator.FacadeData();
                            //                            fData.building = building;
                            //                            fData.volume = volume;
                            fData.baseA        = p0;
                            fData.baseB        = p1;
                            fData.controlA     = cw0;
                            fData.controlB     = cw1;
                            fData.anchors      = anchorPoints[p];
                            fData.isStraight   = isStraight;
                            fData.curveStyle   = volume[p].curveStyle;
                            fData.floorCount   = volume.floors;
                            fData.facadeDesign = facade;
                            //                            fData.submeshList = usedFloorplanSurfaces;
                            fData.startFloor            = BuildRFacadeUtil.MinimumFloor(building, volume, p);
                            fData.actualStartFloor      = building.VolumeBaseFloor(volume);
                            fData.foundationDepth       = foundation;
                            fData.foundationSurface     = building.foundationSurface;
                            fData.wallThickness         = volume.wallThickness;
                            fData.minimumWallUnitLength = volume.minimumWallUnitLength;
                            fData.floorHeight           = volume.floorHeight;
                            fData.floors       = volume.floors;
                            fData.meshType     = building.meshType;
                            fData.colliderType = building.colliderType;
                            fData.cullDoors    = building.cullDoors;
                            fData.prefabs      = volume.prefabs;

//                            Debug.Log("mesh");
                            FacadeGenerator.GenerateFacade(fData, dMesh, cMesh);
//                            Debug.Log("pref");
                            FacadeGenerator.GeneratePrefabs(fData);
//                                                        Debug.Log("Generate facade "+p+" "+dMesh.vertexCount);
                        }
                    }
                }

                #endregion

                #region Interiors

//                Debug.Log("int");
                bool generateInteriors = building.generateInteriors && meshType == BuildingMeshTypes.Full;
                if (generateInteriors)
                {
                    int          floors     = volume.floors;
                    IFloorplan[] floorplans = volume.InteriorFloorplans();
                    for (int fl = 0; fl < floors; fl++)
                    {
                        IFloorplan     floorplan   = floorplans[fl];
                        IVisualPart    floorVisual = floorplan.visualPart;
                        BuildRMesh     flMesh      = floorVisual.dynamicMesh;
                        BuildRCollider flCollider  = floorVisual.colliderMesh;
                        flMesh.Clear();
                        flCollider.Clear();
                        flCollider.TogglePrimitives(colliderType == BuildingColliderTypes.Primitive);
                        FloorplanGenerator.Generate(building, volume, floorplans[fl], fl, volumeOpenings, flMesh, flCollider);
                        floorVisual.GenerateFromDynamicMesh();
                        floorplan.transform.localPosition   = Vector3.up * (fl * volume.floorHeight);
                        floorVisual.transform.localPosition = Vector3.zero;//
                        floorVisual.transform.localRotation = Quaternion.identity;
                    }
                }
                else
                {
                    IFloorplan[] floorplans = volume.InteriorFloorplans();
                    int          floors     = floorplans.Length;
                    for (int fl = 0; fl < floors; fl++)
                    {
                        floorplans[fl].visualPart.Clear();
                    }
                }

                #endregion

                #region Volume Underside Generation

//                Debug.Log("und");
                BuildRVolumeUtil.VolumeShape[] underShapes = BuildRVolumeUtil.GetBottomShape(building, volume);
                int   underShapeCount  = underShapes.Length;
                float volumeBaseHeight = volume.baseHeight - building.foundationDepth;
                for (int u = 0; u < underShapeCount; u++)
                {
                    if (underShapes[u].outer == null)
                    {
                        continue;                             //no underside shape
                    }
                    int undersideSubmesh = dMesh.submeshLibrary.SubmeshAdd(volume.undersideSurafce);
                    Poly2TriWrapper.BMesh(dMesh, volumeBaseHeight, null, undersideSubmesh, underShapes[u].outer, new Rect(0, 0, 0, 0), false, underShapes[u].holes);
                }

                #endregion

//                Debug.Log("roof");
                if (building.generateExteriors)
                {
                    RoofGenerator.Generate(building, volume, dMesh, cMesh);
                    visual.GenerateFromDynamicMesh();
                }
                else
                {
                    visual.Clear();
                }

//                Debug.Log("mat");
                switch (meshType)
                {
                case BuildingMeshTypes.None:
                    visual.materials = null;
                    break;

                case BuildingMeshTypes.Box:
                    visual.materials = new[] { new Material(Shader.Find("Standard")) };
                    break;

                case BuildingMeshTypes.Simple:
                    facadeTexture.filterMode = FilterMode.Bilinear;
                    facadeTexture.Apply(true, false);
                    Material simpleMaterial = new Material(Shader.Find("Standard"));
                    simpleMaterial.mainTexture = facadeTexture;
                    visual.materials           = new[] { simpleMaterial };
                    break;

                case BuildingMeshTypes.Full:
                    visual.materials = dMesh.materials.ToArray();
                    break;
                }
            }
        }
Ejemplo n.º 3
0
        public static void Generate(IBuilding building, IVolume volume, BuildRMesh mesh, BuildRCollider collider, Rect clampUV)
        {
            int   numberOfPoints    = volume.numberOfPoints;
            float totalPlanHeight   = volume.planTotalHeight;
            Roof  roof              = volume.roof;
            bool  generateColliders = building.colliderType != BuildingColliderTypes.None;

            if (!roof.exists)
            {
                return;
            }

            List <Vector2> roofPoints     = new List <Vector2>();
            List <int>     facadeIndicies = new List <int>();

            mesh.submeshLibrary.SubmeshAdd(roof.mainSurface);
            int wallSubmesh  = mesh.submeshLibrary.SubmeshAdd(roof.wallSurface != null ? roof.wallSurface : roof.mainSurface);
            int floorSubmesh = mesh.submeshLibrary.SubmeshAdd(roof.floorSurface != null?roof.floorSurface: roof.mainSurface);

            bool[] facadeParapets = new bool[numberOfPoints];
            for (int p = 0; p < numberOfPoints; p++)
            {
                Vector3 p0 = volume.BuildingPoint(p);

                roofPoints.Add(new Vector2(p0.x, p0.z));
                facadeIndicies.Add(p);

                if (!volume.IsWallStraight(p))
                {
                    int anchorCount = volume.facadeWallAnchors[p].Count;
                    for (int a = 1; a < anchorCount - 1; a++)
                    {
                        roofPoints.Add(volume.facadeWallAnchors[p][a].vector2);
                        facadeIndicies.Add(p);
                    }
                }

                facadeParapets[p] = BuildRFacadeUtil.HasParapet(building, volume, p);
            }

            int numberOfRoofPoints = roofPoints.Count;

            Vector3[] facadeNormals    = new Vector3[numberOfRoofPoints];
            Vector3[] facadeDirections = new Vector3[numberOfRoofPoints];
            float[]   facadeLengths    = new float[numberOfRoofPoints];
            for (int p = 0; p < numberOfRoofPoints; p++)
            {
                Vector3 p0 = roofPoints[p];
                Vector3 p1 = roofPoints[(p + 1) % numberOfRoofPoints];

                Vector3 facadeVector = (p1 - p0);
                facadeDirections[p] = facadeVector.normalized;
                facadeNormals[p]    = Vector3.Cross(Vector3.up, facadeDirections[p]);
                facadeLengths[p]    = facadeVector.magnitude;
            }

            Vector2[] roofPointsA = roofPoints.ToArray();
            bool[]    roofGables  = new bool[numberOfPoints];
            for (int g = 0; g < numberOfPoints; g++)
            {
                roofGables[g] = volume[g].isGabled;
            }
            Vector2[] baseRoofPoints = new Vector2[0];
            if (roof.overhang > 0)
            {
                OffsetPoly polyOffset = new OffsetPoly(roofPointsA, -roof.overhang);
                polyOffset.Execute();
                baseRoofPoints = polyOffset.Shape();

                ShapeToRoofMesh.OverhangUnderside(ref mesh, roofPointsA, baseRoofPoints, totalPlanHeight, roof);
            }
            else
            {
                baseRoofPoints = roofPointsA;
            }

            if (baseRoofPoints.Length == 0)
            {
                return;
            }

            Vector2[] parapetExternalPoints = new Vector2[0];
            Vector2[] parapetInternalPoints = new Vector2[0];
            float     parapetFrontDepth     = roof.parapetFrontDepth;
            float     parapetBackDepth      = roof.parapetBackDepth;

            if (generateColliders)
            {
                collider.thickness = parapetFrontDepth * 0.5f + parapetBackDepth;
            }

            bool parapet = roof.parapet && building.meshType == BuildingMeshTypes.Full;

            if (parapet)
            {
                OffsetPoly polyOffset = new OffsetPoly(baseRoofPoints, -parapetFrontDepth);
                polyOffset.Execute();
                parapetExternalPoints = polyOffset.Shape();

                polyOffset = new OffsetPoly(baseRoofPoints, parapetBackDepth);
                polyOffset.Execute();
                parapetInternalPoints = polyOffset.Shape();
            }


            int roofPointCount = baseRoofPoints.Length;

            if (parapet && parapetExternalPoints.Length > 0 && parapetInternalPoints.Length > 0)
            {
                List <BuildRVolumeUtil.ParapetWallData> parapetShapes = BuildRVolumeUtil.GetParapetShapes(building, volume, baseRoofPoints);
                for (int p = 0; p < roofPointCount; p++)
                {
                    BuildRVolumeUtil.ParapetWallData parapetWallData = parapetShapes[p];

                    int facadeIndex = facadeIndicies[p];
                    if (!facadeParapets[facadeIndex] || parapetWallData.type == BuildRVolumeUtil.ParapetWallData.Types.None)
                    {
                        continue;
                    }

                    int pb  = (p + 1) % roofPointCount;
                    int pbi = (p + 1) % parapetInternalPoints.Length;
                    int pbe = (p + 1) % parapetExternalPoints.Length;

                    int facadeIndexB = (facadeIndex + 1) % numberOfPoints;
                    int facadeIndexC = (facadeIndex - 1 + numberOfPoints) % numberOfPoints;

                    bool facadeParapetB = facadeParapets[facadeIndexB] && parapetShapes[facadeIndexB].type != BuildRVolumeUtil.ParapetWallData.Types.None;
                    bool facadeParapetC = facadeParapets[facadeIndexC] && parapetShapes[facadeIndexC].type != BuildRVolumeUtil.ParapetWallData.Types.None;

                    Vector3 p0              = new Vector3(baseRoofPoints[p].x, totalPlanHeight, baseRoofPoints[p].y);
                    Vector3 p1              = new Vector3(baseRoofPoints[pb].x, totalPlanHeight, baseRoofPoints[pb].y);
                    Vector3 facadeVector    = (p1 - p0);
                    Vector3 facadeDirection = facadeVector.normalized;
                    Vector3 facadeNormal    = Vector3.Cross(Vector3.up, facadeDirection);
                    int     pCount          = Mathf.Min(parapetExternalPoints.Length, parapetInternalPoints.Length);
                    if (p < pCount)
                    {
                        float facadeLength = facadeVector.magnitude;

                        if (!facadeParapetC)//need to straighten the ends if no parapet exists
                        {
                            Vector3 parapetEndExternalC = p0 + facadeNormal * parapetFrontDepth;
                            Vector3 parapetEndInternalC = p0 - facadeNormal * parapetBackDepth;
                            parapetExternalPoints[p] = new Vector2(parapetEndExternalC.x, parapetEndExternalC.z);
                            parapetInternalPoints[p] = new Vector2(parapetEndInternalC.x, parapetEndInternalC.z);
                        }
                        if (!facadeParapetB)//need to straighten the ends if no parapet exists
                        {
                            Vector3 parapetEndExternalB = p1 + facadeNormal * parapetFrontDepth;
                            Vector3 parapetEndInternalB = p1 - facadeNormal * parapetBackDepth;
                            parapetExternalPoints[pbe] = new Vector2(parapetEndExternalB.x, parapetEndExternalB.z);
                            parapetInternalPoints[pbi] = new Vector2(parapetEndInternalB.x, parapetEndInternalB.z);
                        }

                        //external points
                        Vector3 p0e = new Vector3(parapetExternalPoints[p].x, totalPlanHeight, parapetExternalPoints[p].y);
                        Vector3 p1e = new Vector3(parapetExternalPoints[pbe].x, totalPlanHeight, parapetExternalPoints[pbe].y);
                        //internal points
                        Vector3 p0i                  = new Vector3(parapetInternalPoints[p].x, totalPlanHeight, parapetInternalPoints[p].y);
                        Vector3 p1i                  = new Vector3(parapetInternalPoints[pbi].x, totalPlanHeight, parapetInternalPoints[pbi].y);
                        float   uvAngle              = JMath.SignAngle(new Vector2(facadeDirection.x, facadeDirection.z).normalized) + 90;
                        Vector4 facadeTangent        = BuildRMesh.CalculateTangent(facadeDirection);
                        Vector4 facadeTangentInverse = BuildRMesh.CalculateTangent(-facadeDirection);

                        if (parapetWallData.type == BuildRVolumeUtil.ParapetWallData.Types.AtoIntersection)
                        {
                            Vector2 intV2 = parapetWallData.Int;
                            Vector3 intV3 = new Vector3(intV2.x, totalPlanHeight, intV2.y);
                            p1e = intV3 + facadeNormal * parapetFrontDepth;
                            p1i = intV3 - facadeNormal * parapetBackDepth;
                        }

                        if (parapetWallData.type == BuildRVolumeUtil.ParapetWallData.Types.IntersectiontoB)
                        {
                            Vector2 intV2 = parapetWallData.Int;
                            Vector3 intV3 = new Vector3(intV2.x, totalPlanHeight, intV2.y);
                            p0e = intV3 + facadeNormal * parapetFrontDepth;
                            p0i = intV3 - facadeNormal * parapetBackDepth;
                        }

                        if (roof.parapetStyle == Roof.ParapetStyles.Flat)
                        {
                            Vector3 parapetUp = Vector3.up * roof.parapetHeight;

                            Vector3 w0 = p0e;                                                                                                                                               //front left
                            Vector3 w1 = p1e;                                                                                                                                               //front right
                            Vector3 w2 = p0i;                                                                                                                                               //back left
                            Vector3 w3 = p1i;                                                                                                                                               //back right
                            Vector3 w6 = w2 + parapetUp;                                                                                                                                    //front left top
                            Vector3 w7 = w3 + parapetUp;                                                                                                                                    //front right top
                            Vector3 w4 = w0 + parapetUp;                                                                                                                                    //back left top
                            Vector3 w5 = w1 + parapetUp;                                                                                                                                    //back right top

                            mesh.AddPlane(w0, w1, w4, w5, Vector2.zero, new Vector2(facadeLength, roof.parapetHeight), facadeNormal, facadeTangent, wallSubmesh, roof.wallSurface);         //front
                            mesh.AddPlane(w3, w2, w7, w6, Vector2.zero, new Vector2(facadeLength, roof.parapetHeight), -facadeNormal, facadeTangentInverse, wallSubmesh, roof.wallSurface); //back
                            mesh.AddPlaneComplexUp(w7, w6, w5, w4, uvAngle, Vector3.up, facadeTangent, wallSubmesh, roof.wallSurface);                                                      //top

                            if (generateColliders)
                            {
                                collider.AddPlane(w0, w1, w4, w5);
                                if (!collider.usingPrimitives)
                                {
                                    collider.mesh.AddPlane(w3, w2, w7, w6, 0);
                                    collider.mesh.AddPlane(w7, w6, w5, w4, 0);
                                }
                            }

                            if (parapetFrontDepth > 0)
                            {
                                mesh.AddPlaneComplexUp(p0, p1, w0, w1, uvAngle, Vector3.down, facadeTangent, wallSubmesh, roof.wallSurface);//bottom
                            }
                            bool leftParapet = facadeParapetB;
                            if (!leftParapet)
                            {
                                //todo proper calculations
                                Vector3 leftCapNormal = Vector3.forward;
                                mesh.AddPlane(w0, w2, w4, w6, Vector2.zero, new Vector2(parapetBackDepth + parapetFrontDepth, roof.parapetHeight), leftCapNormal, facadeTangent, wallSubmesh, roof.wallSurface);//left cap
                            }

                            bool rightParapet = facadeParapetC;
                            if (!rightParapet)
                            {
                                //todo proper calculations
                                Vector3 rightCapNormal = Vector3.forward;
                                mesh.AddPlane(w3, w1, w7, w5, Vector2.zero, new Vector2(parapetBackDepth + parapetFrontDepth, roof.parapetHeight), rightCapNormal, facadeTangent, wallSubmesh, roof.wallSurface);//right cap
                            }
                        }
                        else//battlements!
                        {
                            int battlementCount = Mathf.CeilToInt(facadeLength / roof.battlementSpacing) * 2 + 1;
                            for (int b = 0; b < battlementCount + 1; b++)
                            {
                                float percentLeft    = b / (float)(battlementCount);
                                float percentRight   = (b + 1f) / (battlementCount);
                                float parapetUVStart = percentLeft * facadeLength;
                                float parapetUVWidth = (percentRight - percentLeft) * facadeLength;

                                Vector3 b0 = Vector3.Lerp(p0e, p1e, percentLeft);
                                Vector3 b1 = Vector3.Lerp(p0e, p1e, percentRight);
                                Vector3 b2 = Vector3.Lerp(p0i, p1i, percentLeft);
                                Vector3 b3 = Vector3.Lerp(p0i, p1i, percentRight);
                                bool    upperBattlement = b % 2 == 0;
                                float   battlementUp    = upperBattlement ? roof.parapetHeight : roof.parapetHeight * roof.battlementHeightRatio;
                                Vector3 battlementUpV   = Vector3.up * battlementUp;

                                Vector3 b6 = b2 + battlementUpV; //front left top
                                Vector3 b7 = b3 + battlementUpV; //front right top
                                Vector3 b4 = b0 + battlementUpV; //back left top
                                Vector3 b5 = b1 + battlementUpV; //back right top

                                //front
                                mesh.AddPlane(b0, b1, b4, b5, new Vector2(parapetUVStart, 0), new Vector2(parapetUVStart + parapetUVWidth, battlementUp), facadeNormal, facadeTangent, wallSubmesh, roof.wallSurface);
                                //back
                                mesh.AddPlane(b3, b2, b7, b6, new Vector2(parapetUVStart, 0), new Vector2(parapetUVStart + parapetUVWidth, battlementUp), -facadeNormal, facadeTangentInverse, wallSubmesh, roof.wallSurface);
                                //top
                                mesh.AddPlaneComplexUp(b7, b6, b5, b4, uvAngle, Vector3.up, facadeTangent, wallSubmesh, roof.wallSurface);
                                if (parapetFrontDepth > 0)
                                {
                                    mesh.AddPlaneComplexUp(p0, p1, b0, b1, uvAngle, Vector3.down, facadeTangent, wallSubmesh, roof.wallSurface);//bottom
                                }
                                if (generateColliders)
                                {
                                    collider.AddPlane(b0, b1, b4, b5);
                                    if (!collider.usingPrimitives)
                                    {
                                        collider.mesh.AddPlane(b3, b2, b7, b6, 0);
                                        collider.mesh.AddPlane(b7, b6, b5, b4, 0);
                                    }
                                }

                                if (upperBattlement)
                                {
                                    //todo proper calculations
                                    float   uvBattlementCapUp = roof.parapetHeight * roof.battlementHeightRatio;
                                    Vector3 leftCapNormal     = -facadeDirection;
                                    Vector4 leftCapTangent    = BuildRMesh.CalculateTangent(-facadeNormal);
                                    mesh.AddPlane(b2, b0, b6, b4, new Vector2(parapetUVStart, 0), new Vector2(parapetUVStart + roof.parapetBackDepth + parapetFrontDepth, uvBattlementCapUp), leftCapNormal, leftCapTangent, wallSubmesh, roof.wallSurface);//left cap
                                    Vector3 rightCapNormal  = facadeDirection;
                                    Vector4 rightCapTangent = BuildRMesh.CalculateTangent(facadeNormal);
                                    mesh.AddPlane(b1, b3, b5, b7, new Vector2(parapetUVStart, 0), new Vector2(parapetUVStart + roof.parapetBackDepth + parapetFrontDepth, uvBattlementCapUp), rightCapNormal, rightCapTangent, wallSubmesh, roof.wallSurface);//right cap

                                    if (generateColliders)
                                    {
                                        if (!collider.usingPrimitives)
                                        {
                                            collider.mesh.AddPlane(b2, b0, b6, b4, 0);
                                            collider.mesh.AddPlane(b1, b3, b5, b7, 0);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            Vector2[] roofFloorBasePoints = (roof.parapet && roof.parapetBackDepth > 0 && parapetInternalPoints.Length > 0) ? parapetInternalPoints : baseRoofPoints;

            Roof.Types roofType = roof.type;
            if (volume.abovePlanCount > 0)
            {
                roofType = Roof.Types.Flat;
            }

            switch (roofType)
            {
            default:
                Flat(building, volume, mesh, collider, roofFloorBasePoints, totalPlanHeight, roof, floorSubmesh, roof.floorSurface, clampUV);
                break;

            case Roof.Types.Pitched:
                if (!PitchedRoofGenerator.Generate(mesh, collider, roofFloorBasePoints, facadeIndicies.ToArray(), totalPlanHeight, volume, clampUV))
                {
                    Flat(building, volume, mesh, collider, roofFloorBasePoints, totalPlanHeight, roof, floorSubmesh, roof.floorSurface, clampUV);
                }
                break;

            case Roof.Types.Mansard:
                if (!MansardRoofGenerator.Generate(mesh, collider, roofFloorBasePoints, facadeIndicies.ToArray(), totalPlanHeight, volume))
                {
                    Flat(building, volume, mesh, collider, roofFloorBasePoints, totalPlanHeight, roof, floorSubmesh, roof.floorSurface, clampUV);
                }
                //                    ShapeToRoofMesh.MansardRoof(ref mesh, roofFloorBasePoints, roofGables, totalPlanHeight, roof, surfaceMapping);
                break;

                //                case Roof.Types.Gambrel:
                //                    ShapeToRoofMesh.Gambrel(ref mesh, roofFloorBasePoints, roofGables, totalPlanHeight, roof, surfaceMapping);
                //                    break;
            }
        }