Esempio n. 1
0
 private void OnDisable()
 {
     if (bMesh != null)
     {
         bMesh.Clear();
     }
     bMesh = null;
     if (mesh != null)
     {
         mesh.Clear();
     }
     mesh = null;
 }
Esempio 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;
                }
            }
        }
Esempio n. 3
0
 public void Clear()
 {
     _mesh.Clear();
     _boxList.Clear();
 }
Esempio n. 4
0
        public static void Generate(Chimney chimney, GenerationOutput output, SubmeshLibrary submeshLibrary = null)
        {
            RGEN.seed = chimney.seed;
            DYNAMIC_MESH.Clear();
            if (submeshLibrary != null)
            {
                DYNAMIC_MESH.submeshLibrary.AddRange(submeshLibrary.SURFACES.ToArray()); //DYNAMIC_MESH.submeshLibrary.Inject(ref submeshLibrary);
            }
            else
            {
                DYNAMIC_MESH.submeshLibrary.Add(chimney);
            }

            submeshLibrary = DYNAMIC_MESH.submeshLibrary;

            //CASE
            Vector3 caseNoiseVector = new Vector3(chimney.noise.x * RGEN.OneRange(), chimney.noise.y * RGEN.OneRange(), chimney.noise.z * RGEN.OneRange());
            Vector3 cs0             = new Vector3(-chimney.caseSize.x * 0.5f, 0, -chimney.caseSize.z * 0.5f);
            Vector3 cs1             = new Vector3(chimney.caseSize.x * 0.5f, 0, -chimney.caseSize.z * 0.5f);
            Vector3 cs2             = new Vector3(-chimney.caseSize.x * 0.5f, 0, chimney.caseSize.z * 0.5f);
            Vector3 cs3             = new Vector3(chimney.caseSize.x * 0.5f, 0, chimney.caseSize.z * 0.5f);

            Vector3 cs4 = new Vector3(-chimney.caseSize.x * 0.5f, chimney.caseSize.y, -chimney.caseSize.z * 0.5f) + caseNoiseVector;
            Vector3 cs5 = new Vector3(chimney.caseSize.x * 0.5f, chimney.caseSize.y, -chimney.caseSize.z * 0.5f) + caseNoiseVector;
            Vector3 cs6 = new Vector3(-chimney.caseSize.x * 0.5f, chimney.caseSize.y, chimney.caseSize.z * 0.5f) + caseNoiseVector;
            Vector3 cs7 = new Vector3(chimney.caseSize.x * 0.5f, chimney.caseSize.y, chimney.caseSize.z * 0.5f) + caseNoiseVector;

            Vector2 csuv0 = new Vector2(0, 0);
            Vector2 csuv1 = new Vector2(chimney.caseSize.x, chimney.caseSize.y);
            Vector2 csuv2 = new Vector2(csuv1.x, 0);
            Vector2 csuv3 = new Vector2(csuv1.x + chimney.caseSize.z, chimney.caseSize.y);
            Vector2 csuv4 = new Vector2(csuv3.x, 0);
            Vector2 csuv5 = new Vector2(csuv3.x + chimney.caseSize.x, chimney.caseSize.y);
            Vector2 csuv6 = new Vector2(csuv5.x, 0);
            Vector2 csuv7 = new Vector2(csuv5.x + chimney.caseSize.z, chimney.caseSize.y);
            Vector2 csuv8 = new Vector2(0, 0);
            Vector2 csuv9 = new Vector2(chimney.caseSize.x, chimney.caseSize.z);

            Vector4 cst0 = new Vector4(0, 0, 1, 0);
            Vector4 cst1 = new Vector4(1, 0, 1, 0);
            Vector4 cst2 = new Vector4(0, 0, -1, 0);
            Vector4 cst3 = new Vector4(-1, 0, 0, 0);
            Vector4 cst4 = new Vector4(0, 0, 1, 0);

            int caseSubmesh = submeshLibrary.SubmeshAdd(chimney.caseSurface);

            //sides
            DYNAMIC_MESH.AddPlane(cs0, cs1, cs4, cs5, csuv0, csuv1, Vector3.back, cst0, caseSubmesh, chimney.caseSurface);
            DYNAMIC_MESH.AddPlane(cs1, cs3, cs5, cs7, csuv2, csuv3, Vector3.right, cst1, caseSubmesh, chimney.caseSurface);
            DYNAMIC_MESH.AddPlane(cs3, cs2, cs7, cs6, csuv4, csuv5, Vector3.forward, cst2, caseSubmesh, chimney.caseSurface);
            DYNAMIC_MESH.AddPlane(cs2, cs0, cs6, cs4, csuv6, csuv7, Vector3.left, cst3, caseSubmesh, chimney.caseSurface);
            //top
            DYNAMIC_MESH.AddPlane(cs4, cs5, cs6, cs7, csuv8, csuv9, Vector3.up, cst4, caseSubmesh, chimney.caseSurface);//todo calculate the values for this - don't be lazy

            //CROWN
            Vector3 crownBase        = caseNoiseVector + Vector3.up * chimney.caseSize.y;
            Vector3 crownNoiseVector = new Vector3(chimney.noise.x * RGEN.OneRange(), chimney.noise.y * RGEN.OneRange(), chimney.noise.z * RGEN.OneRange());
            Vector3 cr0 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, 0, -chimney.crownSize.z * 0.5f);
            Vector3 cr1 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, 0, -chimney.crownSize.z * 0.5f);
            Vector3 cr2 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, 0, chimney.crownSize.z * 0.5f);
            Vector3 cr3 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, 0, chimney.crownSize.z * 0.5f);

            Vector3 cr4 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, chimney.crownSize.y, -chimney.crownSize.z * 0.5f) + crownNoiseVector;
            Vector3 cr5 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, chimney.crownSize.y, -chimney.crownSize.z * 0.5f) + crownNoiseVector;
            Vector3 cr6 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, chimney.crownSize.y, chimney.crownSize.z * 0.5f) + crownNoiseVector;
            Vector3 cr7 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, chimney.crownSize.y, chimney.crownSize.z * 0.5f) + crownNoiseVector;

            Vector2 cruv0 = new Vector2(0, 0);
            Vector2 cruv1 = new Vector2(chimney.crownSize.x, chimney.crownSize.y);
            Vector2 cruv2 = new Vector2(csuv1.x, 0);
            Vector2 cruv3 = new Vector2(csuv1.x + chimney.caseSize.z, chimney.crownSize.y);
            Vector2 cruv4 = new Vector2(csuv3.x, 0);
            Vector2 cruv5 = new Vector2(csuv3.x + chimney.crownSize.x, chimney.crownSize.y);
            Vector2 cruv6 = new Vector2(csuv5.x, chimney.crownSize.y);
            Vector2 cruv7 = new Vector2(csuv5.x + chimney.crownSize.z, chimney.crownSize.y);
            Vector2 cruv8 = new Vector2(0, 0);
            Vector2 cruv9 = new Vector2(chimney.crownSize.x, chimney.crownSize.z);

            Vector4 crt0 = new Vector4(0, 0, 1, 0);
            Vector4 crt1 = new Vector4(1, 0, 1, 0);
            Vector4 crt2 = new Vector4(0, 0, -1, 0);
            Vector4 crt3 = new Vector4(-1, 0, 0, 0);
            Vector4 crt4 = new Vector4(0, 0, 1, 0);

            int crownSubmesh = submeshLibrary.SubmeshAdd(chimney.crownSurface);

            DYNAMIC_MESH.AddPlane(cr0, cr1, cr4, cr5, cruv0, cruv1, Vector3.back, crt0, crownSubmesh, chimney.crownSurface);    //todo calculate the values for this - don't be lazy
            DYNAMIC_MESH.AddPlane(cr1, cr3, cr5, cr7, cruv2, cruv3, Vector3.right, crt1, crownSubmesh, chimney.crownSurface);   //todo calculate the values for this - don't be lazy
            DYNAMIC_MESH.AddPlane(cr3, cr2, cr7, cr6, cruv4, cruv5, Vector3.forward, crt2, crownSubmesh, chimney.crownSurface); //todo calculate the values for this - don't be lazy
            DYNAMIC_MESH.AddPlane(cr2, cr0, cr6, cr4, cruv6, cruv7, Vector3.left, crt3, crownSubmesh, chimney.crownSurface);    //todo calculate the values for this - don't be lazy
            DYNAMIC_MESH.AddPlane(cr1, cr0, cr3, cr2, cruv8, cruv9, Vector3.down, crt4, crownSubmesh, chimney.crownSurface);    //todo calculate the values for this - don't be lazy
            DYNAMIC_MESH.AddPlane(cr4, cr5, cr6, cr7, cruv8, cruv9, Vector3.up, crt4, crownSubmesh, chimney.crownSurface);      //todo calculate the values for this - don't be lazy

            int xCount = 1;
            int zCount = 1;

            if (chimney.allowMultiple)
            {
                xCount = Mathf.FloorToInt((chimney.crownSize.x - chimney.flueSpacing) / (chimney.flueSize.x + chimney.flueSpacing));
                if (xCount < 1)
                {
                    xCount = 1;
                }
                if (chimney.allowMultipleRows)
                {
                    zCount = Mathf.FloorToInt((chimney.crownSize.z - chimney.flueSpacing) / (chimney.flueSize.z + chimney.flueSpacing));
                    if (zCount < 1)
                    {
                        zCount = 1;
                    }
                }
            }

            float xSpacing = (chimney.crownSize.x - chimney.flueSize.x * xCount) / (xCount + 1);
            float zSpacing = (chimney.crownSize.z - chimney.flueSize.z * zCount) / (zCount + 1);

            //FLUES
            for (int x = 0; x < xCount; x++)
            {
                for (int z = 0; z < zCount; z++)
                {
                    Vector3 flueBase = cr4 + new Vector3(xSpacing + x * (chimney.flueSize.x + xSpacing) + chimney.flueSize.x * 0.5f, 0, zSpacing + z * (chimney.flueSize.z + zSpacing) + chimney.flueSize.z * 0.5f);

                    float   thickness  = (chimney.flueSize.x + chimney.flueSize.z) * 0.05f;//10%
                    float   drop       = chimney.flueSize.y * 0.9f;
                    Vector4 topTangent = new Vector4(1, 0, 0, 0);

                    Surface useFlueSurface = GenerationUtil.GetSurface(chimney.flueSurfaces, RGEN);
                    int     flueSubmesh    = submeshLibrary.SubmeshAdd(useFlueSurface);
                    int     innerSubmesh   = submeshLibrary.SubmeshAdd(chimney.innerSurface);

                    Vector3 flueNoiseVector = new Vector3(chimney.noise.x * RGEN.OneRange(), chimney.noise.y * RGEN.OneRange(), chimney.noise.z * RGEN.OneRange());

                    if (chimney.square)
                    {
                        Vector3 f0 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, 0, -chimney.flueSize.z * 0.5f);
                        Vector3 f1 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, 0, -chimney.flueSize.z * 0.5f);
                        Vector3 f2 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, 0, chimney.flueSize.z * 0.5f);
                        Vector3 f3 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, 0, chimney.flueSize.z * 0.5f);

                        Vector3 f4 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, chimney.flueSize.y, -chimney.flueSize.z * 0.5f) + flueNoiseVector;
                        Vector3 f5 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, chimney.flueSize.y, -chimney.flueSize.z * 0.5f) + flueNoiseVector;
                        Vector3 f6 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, chimney.flueSize.y, chimney.flueSize.z * 0.5f) + flueNoiseVector;
                        Vector3 f7 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, chimney.flueSize.y, chimney.flueSize.z * 0.5f) + flueNoiseVector;

                        Vector3 f4i = f4 + new Vector3(thickness, 0, thickness) + flueNoiseVector;
                        Vector3 f5i = f5 + new Vector3(-thickness, 0, thickness) + flueNoiseVector;
                        Vector3 f6i = f6 + new Vector3(thickness, 0, -thickness) + flueNoiseVector;
                        Vector3 f7i = f7 + new Vector3(-thickness, 0, -thickness) + flueNoiseVector;

                        Vector3 f4id = f4i + new Vector3(0, -drop, 0);
                        Vector3 f5id = f5i + new Vector3(0, -drop, 0);
                        Vector3 f6id = f6i + new Vector3(0, -drop, 0);
                        Vector3 f7id = f7i + new Vector3(0, -drop, 0);

//            Vector2 fuv0 = new Vector2(0, 0);
//            Vector2 fuv1 = new Vector2(chimney.flueSize.x, 0);
//            Vector2 fuv2 = new Vector2(fuv1.x + chimney.flueSize.z, 0);
//            Vector2 fuv3 = new Vector2(fuv2.x + chimney.flueSize.x, 0);
//
//            Vector2 fuv4 = new Vector2(0, chimney.flueSize.y);
//            Vector2 fuv5 = new Vector2(chimney.flueSize.x, chimney.flueSize.y);
//            Vector2 fuv6 = new Vector2(fuv1.x + chimney.flueSize.z, chimney.flueSize.y);
//            Vector2 fuv7 = new Vector2(fuv2.x + chimney.flueSize.x, chimney.flueSize.y);


                        //Flue Sides
                        DYNAMIC_MESH.AddPlane(f0, f1, f4, f5, flueSubmesh);                                                  //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlane(f1, f3, f5, f7, flueSubmesh);                                                  //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlane(f3, f2, f7, f6, flueSubmesh);                                                  //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlane(f2, f0, f6, f4, flueSubmesh);                                                  //todo calculate the values for this - don't be lazy
                                                                                                                             //Flue Top
                        DYNAMIC_MESH.AddPlaneComplex(f4, f5, f4i, f5i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlaneComplex(f5, f7, f5i, f7i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlaneComplex(f7, f6, f7i, f6i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlaneComplex(f6, f4, f6i, f4i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy
                                                                                                                             //Flue Drop
                        DYNAMIC_MESH.AddPlane(f5id, f4id, f5i, f4i, innerSubmesh);                                           //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlane(f7id, f5id, f7i, f5i, innerSubmesh);                                           //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlane(f6id, f7id, f6i, f7i, innerSubmesh);                                           //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlane(f4id, f6id, f4i, f6i, innerSubmesh);                                           //todo calculate the values for this - don't be lazy
                        DYNAMIC_MESH.AddPlane(f4id, f5id, f6id, f7id, innerSubmesh);                                         //todo calculate the values for this - don't be lazy
                    }
                    else
                    {
                        int         vertCount = (chimney.segments + 1) * 2;//add an additonal so we can wrap the UVs well
                        RawMeshData flueOuter = new RawMeshData(vertCount, chimney.segments * 6);
                        RawMeshData flueTop   = new RawMeshData(vertCount, chimney.segments * 6);
                        //add additional point for the middle, bottom of the inside of the flue
                        RawMeshData flueInner = new RawMeshData(vertCount + 1, chimney.segments * 9);

                        //the additonal point at the bottom of the flue - added to the end of the mesh data
                        flueInner.vertices[vertCount] = flueBase;
                        flueInner.normals[vertCount]  = Vector3.up;
                        flueInner.tangents[vertCount] = new Vector4(1, 0, 0, 0);
                        int   indexIm       = flueInner.vertCount - 1;
                        float circumference = Mathf.PI * (chimney.flueSize.x + chimney.flueSize.z);

                        for (int s = 0; s < chimney.segments + 1; s++)
                        {
                            float percent = s / (float)(chimney.segments);
                            percent = (percent + (chimney.angleOffset / 360)) % 1f;

                            int indexV0 = s * 2;
                            int indexV1 = s * 2 + 1;
                            int indexV2 = s * 2 + 2;
                            int indexV3 = s * 2 + 3;
                            if (s == chimney.segments - 1)
                            {
                                indexV2 = 0;
                                indexV3 = 1;
                            }

                            float xa = Mathf.Sin(percent * Mathf.PI * 2) * chimney.flueSize.x * 0.5f;
                            float za = Mathf.Cos(percent * Mathf.PI * 2) * chimney.flueSize.z * 0.5f;
//              float innerHalf = thickness / (chimney.flueSize.x + chimney.flueSize.z) / 2;
                            float xai = Mathf.Sin(percent * Mathf.PI * 2) * chimney.flueSize.x * 0.4f;
                            float zai = Mathf.Cos(percent * Mathf.PI * 2) * chimney.flueSize.z * 0.4f;

                            Vector3 v0 = flueBase + new Vector3(xa, 0, za);
                            Vector3 v1 = flueBase + new Vector3(xa, chimney.flueSize.y, za) + flueNoiseVector;
                            Vector3 v2 = flueBase + new Vector3(xai, chimney.flueSize.y, zai) + flueNoiseVector;
                            Vector3 v3 = flueBase + new Vector3(xai, chimney.flueSize.y * 0.1f, zai);

                            Vector2 uv0 = new Vector2(-circumference * percent, 0);
                            Vector2 uv1 = new Vector2(-circumference * percent, chimney.flueSize.y);
                            Vector2 uv2 = new Vector2(-circumference * percent, chimney.flueSize.y + 0.1f);
                            Vector2 uv3 = new Vector2(-circumference * percent, 0);

                            int     rdnFlueSurfaceIndex = RGEN.Index(chimney.flueSurfaces.Count);
                            Surface flueSurface         = rdnFlueSurfaceIndex != -1 ? chimney.flueSurfaces[rdnFlueSurfaceIndex] : null;


                            if (flueSurface != null)
                            {
                                uv0 = flueSurface.CalculateUV(uv0);
                                uv1 = flueSurface.CalculateUV(uv1);
                                uv2 = flueSurface.CalculateUV(uv2);
                                uv3 = flueSurface.CalculateUV(uv3);
                            }

                            flueOuter.vertices[indexV0] = v0;
                            flueOuter.vertices[indexV1] = v1;
                            flueOuter.uvs[indexV0]      = uv0;
                            flueOuter.uvs[indexV1]      = uv1;

                            flueTop.vertices[indexV0] = v1;
                            flueTop.vertices[indexV1] = v2;
                            flueTop.uvs[indexV0]      = uv1;
                            flueTop.uvs[indexV1]      = uv2;

                            flueInner.vertices[indexV0] = v2;
                            flueInner.vertices[indexV1] = v3;
                            flueInner.uvs[indexV0]      = uv2;
                            flueInner.uvs[indexV1]      = uv3;

                            Vector3 outerNormal = new Vector3(Mathf.Sin(percent * Mathf.PI * 2), 0, Mathf.Cos(percent * Mathf.PI * 2));
                            flueOuter.normals[indexV0] = outerNormal;
                            flueOuter.normals[indexV1] = outerNormal;
                            flueTop.normals[indexV0]   = Vector3.up;
                            flueTop.normals[indexV1]   = Vector3.up;
                            flueInner.normals[indexV0] = -outerNormal;
                            flueInner.normals[indexV1] = -outerNormal;

                            if (s < chimney.segments)
                            {
                                int tidx0 = s * 6;
                                flueOuter.triangles[tidx0 + 0] = indexV0;
                                flueOuter.triangles[tidx0 + 2] = indexV1;
                                flueOuter.triangles[tidx0 + 1] = indexV2;
                                flueOuter.triangles[tidx0 + 3] = indexV1;
                                flueOuter.triangles[tidx0 + 4] = indexV2;
                                flueOuter.triangles[tidx0 + 5] = indexV3;

                                flueTop.triangles[tidx0 + 0] = indexV0;
                                flueTop.triangles[tidx0 + 2] = indexV1;
                                flueTop.triangles[tidx0 + 1] = indexV2;
                                flueTop.triangles[tidx0 + 3] = indexV1;
                                flueTop.triangles[tidx0 + 4] = indexV2;
                                flueTop.triangles[tidx0 + 5] = indexV3;

                                int tidx0i = s * 9;
                                flueInner.triangles[tidx0i + 0] = indexV0;
                                flueInner.triangles[tidx0i + 2] = indexV1;
                                flueInner.triangles[tidx0i + 1] = indexV2;
                                flueInner.triangles[tidx0i + 3] = indexV1;
                                flueInner.triangles[tidx0i + 4] = indexV2;
                                flueInner.triangles[tidx0i + 5] = indexV3;

                                flueInner.triangles[tidx0i + 6] = indexV1;
                                flueInner.triangles[tidx0i + 7] = indexV3;
                                flueInner.triangles[tidx0i + 8] = indexIm;
                            }
                        }

                        DYNAMIC_MESH.AddData(flueOuter, flueSubmesh);
                        DYNAMIC_MESH.AddData(flueTop, flueSubmesh);
                        DYNAMIC_MESH.AddData(flueInner, innerSubmesh);
                    }
                }
            }


            if (output.raw != null)
            {
                output.raw.Copy(DYNAMIC_MESH);
            }

            if (output.mesh != null)
            {
                output.mesh.Clear(false);
                DYNAMIC_MESH.Build(output.mesh);
            }
        }
Esempio n. 5
0
        //TODO support custom models coming in from roof design
        public static void Generate(ref BuildRMesh mesh, IVolume volume, List <Vector3[]> roofFaces)
        {
            Roof  design     = volume.roof;
            float roofDepth  = design.depth;
            float roofHeight = design.height;

            float dormerWidth  = design.dormerWidth;
            float dormerHeight = design.dormerHeight;
            int   dormerRows   = design.dormerRows;

            if (dormerHeight * dormerRows > roofHeight)
            {
                dormerHeight = roofHeight / dormerRows;
            }
            float dormerRoofHeight = design.dormerRoofHeight;
            float roofPitchRad     = Mathf.Atan2(roofHeight, roofDepth);
            float roofHyp          = Mathf.Sqrt(roofDepth * roofDepth + roofHeight * roofHeight);//todo make a proper calculation - this is incorrect
            float dormerDepth      = Mathf.Cos(roofPitchRad) * dormerHeight;
            float dormerHyp        = Mathf.Sqrt(dormerHeight * dormerHeight + dormerDepth * dormerDepth);
            float dormerRowSpace   = roofHyp / dormerRows;

            dormerHyp = Mathf.Min(dormerHyp, dormerRowSpace);
            float dormerSpace     = dormerRowSpace - dormerHyp;
            float dormerSpaceLerp = dormerSpace / roofHyp;

            if (INTERNAL_B_MESH == null)
            {
                INTERNAL_B_MESH = new BuildRMesh("internal dormer");
            }
            INTERNAL_B_MESH.Clear();

            INTERNAL_B_MESH.submeshLibrary.AddRange(mesh.submeshLibrary.MATERIALS.ToArray());

            Vector3 bpl = Vector3.left * dormerWidth * 0.5f;
            Vector3 bpr = Vector3.right * dormerWidth * 0.5f;
            Vector3 tpc = Vector3.up * dormerHeight;
            float   dormerFaceHeight = dormerHeight - dormerHeight * dormerRoofHeight;
            Vector3 tpl = bpl + Vector3.up * dormerFaceHeight;
            Vector3 tpr = bpr + Vector3.up * dormerFaceHeight;
            Vector3 rpc = tpc + Vector3.back * dormerDepth;
            Vector3 rpl = tpl + Vector3.back * dormerDepth;
            Vector3 rpr = tpr + Vector3.back * dormerDepth;

            Surface mainSurface = design.mainSurface;
            Surface wallSurface = design.wallSurface;
            int     mainSubmesh = mesh.submeshLibrary.SubmeshAdd(mainSurface);
            int     wallSubmesh = mesh.submeshLibrary.SubmeshAdd(wallSurface);

            Vector2 sectionSize = new Vector2(dormerWidth, dormerFaceHeight);

            if (design.wallSection && design.wallSection.CanRender(sectionSize))
            {
                //                mesh.submeshLibrary.Add(design.wallSection);
                mesh.submeshLibrary.Add(design.wallSection);

                GenerationOutput output = GenerationOutput.CreateRawOutput();
                WallSectionGenerator.Generate(design.wallSection, output, sectionSize, false, 0.02f, false, null, mesh.submeshLibrary);
                Vector3 sectionPos = new Vector3(0, dormerFaceHeight * 0.5f, 0);
                int[]   mapping    = new int[output.raw.materials.Count];
                for (int s = 0; s < output.raw.materials.Count; s++)
                {
                    mapping[s] = 0;
                }
                INTERNAL_B_MESH.AddDataKeepSubmeshStructure(output.raw, sectionPos, Quaternion.Euler(0, 180, 0), Vector3.one);
            }
            else
            {
                INTERNAL_B_MESH.AddPlane(bpr, bpl, tpr, tpl, wallSubmesh);//dormer front square
            }

            //front triangle

            INTERNAL_B_MESH.AddTri(tpl, tpr, tpc, Vector3.right, wallSubmesh);
            //roof
            Vector3 normalRoofRight  = Vector3.Cross((tpr - tpc).normalized, (rpc - tpc).normalized);
            Vector4 tangentRoofRight = BuildRMesh.CalculateTangent(Vector3.back);
            Vector3 normalRoofLeft   = Vector3.Cross((rpc - tpc).normalized, (tpl - tpc).normalized);
            Vector4 tangentRoofLeft  = BuildRMesh.CalculateTangent(Vector3.forward);
            Vector2 roofUvMax        = new Vector2(dormerDepth, Vector3.Distance(tpc, tpl));

            INTERNAL_B_MESH.AddPlane(rpr, tpr, rpc, tpc, Vector2.zero, roofUvMax, normalRoofRight, tangentRoofRight, mainSubmesh, mainSurface);
            INTERNAL_B_MESH.AddPlane(rpc, tpc, rpl, tpl, Vector2.zero, roofUvMax, normalRoofLeft, tangentRoofLeft, mainSubmesh, mainSurface);
            //side triangles
            INTERNAL_B_MESH.AddTri(bpr, rpr, tpr, Vector3.back, wallSubmesh);
            INTERNAL_B_MESH.AddTri(bpl, tpl, rpl, Vector3.back, wallSubmesh);

            RawMeshData data = RawMeshData.CopyBuildRMesh(INTERNAL_B_MESH);

            int roofFaceCount = roofFaces.Count;

            for (int r = 0; r < roofFaceCount; r++)
            {
                Vector3[] roofFace = roofFaces[r];
                Vector3   p0       = roofFace[0];
                Vector3   p1       = roofFace[1];
                Vector3   p2       = roofFace[2];
                Vector3   p3       = roofFace[3];

                //center line
                Vector3 pDB             = Vector3.Lerp(p0, p1, 0.5f);
                Vector3 facadeVector    = p1 - p0;
                Vector3 facadeDirection = facadeVector.normalized;
                Vector3 facadeNormal    = Vector3.Cross(Vector3.up, facadeDirection);

                Vector3 projTL = p0 + Vector3.Project(p2 - p0, facadeDirection);
                Vector3 projTR = p1 + Vector3.Project(p3 - p1, facadeDirection);

                float sqrMagP0 = Vector3.SqrMagnitude(p0 - pDB);
                float sqrMagP1 = Vector3.SqrMagnitude(p1 - pDB);
                float sqrMagP2 = Vector3.SqrMagnitude(projTL - pDB);
                float sqrMagP3 = Vector3.SqrMagnitude(projTR - pDB);

                Vector3 dormerBaseLeft  = sqrMagP0 < sqrMagP2 ? p0 : projTL;
                Vector3 dormerBaseRight = sqrMagP1 < sqrMagP3 ? p1 : projTR;

                Vector3 roofNormal = BuildRMesh.CalculateNormal(p0, p2, p1);
                Vector3 roofUp     = Vector3.Cross(roofNormal, -facadeDirection);
                float   actualHyp  = sqrMagP0 < sqrMagP2?Vector3.Distance(p0, p2 + Vector3.Project(p0 - p2, facadeDirection)) : Vector3.Distance(projTL, p2);

                Vector3 dormerTopLeft  = dormerBaseLeft + roofUp * actualHyp;
                Vector3 dormerTopRight = dormerBaseRight + roofUp * actualHyp;

                float topLength       = Vector3.Distance(dormerBaseLeft, dormerBaseRight);
                int   numberOfDormers = Mathf.FloorToInt((topLength - design.minimumDormerSpacing * 2) / (design.minimumDormerSpacing + dormerWidth));

                if (numberOfDormers == 0)
                {
                    if (topLength > sectionSize.x)
                    {
                        numberOfDormers = 1;
                    }
                }

                for (int dr = 0; dr < dormerRows; dr++)
                {
                    float rowPercent = dr / (dormerRows + 0f) + dormerSpaceLerp * 0.5f;
                    //row vector
                    Vector3 rl = Vector3.Lerp(dormerBaseLeft, dormerTopLeft, rowPercent);
                    Vector3 rr = Vector3.Lerp(dormerBaseRight, dormerTopRight, rowPercent);

                    for (int dc = 0; dc < numberOfDormers; dc++)
                    {
                        float   columnPercent = (dc + 1f) / (numberOfDormers + 1f);
                        Vector3 dormerBegin   = Vector3.Lerp(rl, rr, columnPercent);

                        Quaternion meshRot = Quaternion.LookRotation(facadeNormal, Vector3.up);
                        Vector3    meshPos = dormerBegin;
                        //TODO account for the mesh mode of the wall section - custom meshes
                        mesh.AddDataKeepSubmeshStructure(data, meshPos, meshRot, Vector3.one);
                    }
                }
            }
        }
        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;
                }
            }
        }