Esempio n. 1
0
        private static void ToMesh(ref BuildRMesh mesh, Vector2[] points, float height, int[] facadeIndices, IVolume volume, int submesh, Surface surface)
        {
            int vertCount = points.Length;

            Vector3[] verts = new Vector3[vertCount];
            for (int i = 0; i < vertCount; i++)
            {
                verts[i] = new Vector3(points[i].x, height, points[i].y);
            }
            Vector2[] uvs      = new Vector2[vertCount];
            Vector3[] normals  = new Vector3[vertCount];
            Vector4[] tangents = new Vector4[vertCount];
            Vector4   tangent  = BuildRMesh.CalculateTangent(Vector3.right);

            for (int v = 0; v < vertCount; v++)
            {
                if (surface != null)
                {
                    uvs[v] = surface.CalculateUV(points[v]);
                }
                normals[v]  = Vector3.up;
                tangents[v] = tangent;
            }

//            int[] topTris = EarClipper.Triangulate(points);
            int[] topTris = Poly2TriWrapper.Triangulate(points, true);
            mesh.AddData(verts, uvs, topTris, normals, tangents, submesh);
        }
Esempio n. 2
0
        public static void OverhangUnderside(ref BuildRMesh mesh, Vector2[] facadePoints, Vector2[] outerPoints, float roofBaseHeight, Roof design)
        {
            Vector2[][] facadeHole = new Vector2[1][];
            facadeHole[0] = outerPoints;
            int[] topTris = Poly2TriWrapper.Triangulate(outerPoints, false, facadeHole);
            //            Array.Reverse(topTris);

            int facadePointCount = facadePoints.Length;
            int outerPointCount  = outerPoints.Length;
            int usePoints        = facadePointCount + outerPointCount;

            Vector2[] points = new Vector2[usePoints];
            for (int f = 0; f < facadePointCount; f++)
            {
                points[f] = facadePoints[f];
            }
            for (int o = 0; o < outerPointCount; o++)
            {
                points[o + facadePointCount] = outerPoints[o];
            }

            int submesh = mesh.submeshLibrary.SubmeshAdd(design.floorSurface);

            int vertCount = points.Length;

            Vector3[] verts = new Vector3[vertCount];
            for (int i = 0; i < vertCount; i++)
            {
                verts[i] = new Vector3(points[i].x, roofBaseHeight, points[i].y);
            }
            Vector2[] uvs      = new Vector2[vertCount];
            Vector3[] normals  = new Vector3[vertCount];
            Vector4[] tangents = new Vector4[vertCount];
            Vector4   tangent  = BuildRMesh.CalculateTangent(Vector3.right);
            Surface   surface  = design.floorSurface;

            for (int v = 0; v < vertCount; v++)
            {
                if (surface != null)
                {
                    uvs[v] = surface.CalculateUV(points[v]);
                }
                normals[v]  = Vector3.down;
                tangents[v] = tangent;
            }

            mesh.AddData(verts, uvs, topTris, normals, tangents, submesh);
        }
Esempio n. 3
0
        private static void ToMesh(ref BuildRMesh mesh, Vector2[] points, float height, int submesh, Surface surface)
        {
            int vertCount = points.Length;

            Vector3[] verts = new Vector3[vertCount];
            for (int i = 0; i < vertCount; i++)
            {
                verts[i] = new Vector3(points[i].x, height, points[i].y);
            }
            Vector2[] uvs      = new Vector2[vertCount];
            Vector3[] normals  = new Vector3[vertCount];
            Vector4[] tangents = new Vector4[vertCount];
            Vector4   tangent  = BuildRMesh.CalculateTangent(Vector3.right);

            for (int v = 0; v < vertCount; v++)
            {
                if (surface != null)
                {
                    uvs[v] = surface.CalculateUV(points[v]);
                }
                normals[v]  = Vector3.up;
                tangents[v] = tangent;
            }

//            int[] topTris = EarClipper.Triangulate(points);
            int[] topTris = Poly2TriWrapper.Triangulate(points);
            for (int t = 0; t < topTris.Length; t += 3)
            {
                int ia = topTris[t];
                int ib = topTris[t + 1];
                int ic = topTris[t + 2];
                Debug.DrawLine(verts[topTris[ia]], verts[topTris[ib]]);
                Debug.DrawLine(verts[topTris[ib]], verts[topTris[ic]]);
                Debug.DrawLine(verts[topTris[ic]], verts[topTris[ia]]);
            }
            mesh.AddData(verts, uvs, topTris, normals, tangents, submesh);
        }
Esempio n. 4
0
        public static void GenerateFacade(FacadeData data, BuildRMesh dmesh, BuildRCollider collider = null)
        {
//		    Debug.Log("******************* "+data.facadeDesign.ToString());
            Vector3 facadeVector = data.baseB - data.baseA;

            if (facadeVector.magnitude < Mathf.Epsilon)
            {
                return;
            }
            Vector3   facadeDirection = facadeVector.normalized;
            Vector3   facadeNormal    = Vector3.Cross(facadeDirection, Vector3.up);
            Vector4   facadeTangent   = BuildRMesh.CalculateTangent(facadeDirection);
            RandomGen rGen            = new RandomGen();

            rGen.GenerateNewSeed();
            float                 wallThickness = data.wallThickness;
            float                 foundation    = data.foundationDepth;
            BuildingMeshTypes     meshType      = data.meshType;
            BuildingColliderTypes colliderType  = data.colliderType;
            int     wallSections = 0;
            Vector2 wallSectionSize;
            float   facadeLength = 0;

            if (data.isStraight)
            {
                facadeLength = facadeVector.magnitude;
                wallSections = Mathf.FloorToInt(facadeLength / data.minimumWallUnitLength);
                if (wallSections < 1)
                {
                    wallSections = 1;
                }
                wallSectionSize = new Vector2(facadeLength / wallSections, data.floorHeight);
            }
            else
            {
                wallSections = data.anchors.Count - 1;
                if (wallSections < 1)
                {
                    wallSections = 1;
                }
                float sectionWidth = Vector2.Distance(data.anchors[0].vector2, data.anchors[1].vector2);
                wallSectionSize = new Vector2(sectionWidth, data.floorHeight);
            }

            Dictionary <WallSection, RawMeshData>           generatedSections                  = new Dictionary <WallSection, RawMeshData>();
            Dictionary <WallSection, RawMeshData>           generatedSectionMeshColliders      = new Dictionary <WallSection, RawMeshData>();
            Dictionary <WallSection, BuildRCollider.BBox[]> generatedSectionPrimitiveColliders = new Dictionary <WallSection, BuildRCollider.BBox[]>();

            int startFloor = data.startFloor;

//		    Debug.Log("st fl "+startFloor);
//		    Debug.Log("fl ct "+ data.floorCount);
            for (int fl = startFloor; fl < data.floorCount; fl++)
            {
//			    Debug.Log(fl);
                if (data.facadeDesign.randomisationMode == Facade.RandomisationModes.RandomRows)
                {
                    generatedSections.Clear();                                                                             //recalculate each row
                }
//			    Debug.Log(wallSections);
                for (int s = 0; s < wallSections; s++)
                {
//				    Debug.Log(s);
                    WallSection section = data.facadeDesign.GetWallSection(s, fl + data.actualStartFloor, wallSections, data.floorCount);
//				    Debug.Log(section);
                    dmesh.submeshLibrary.Add(section);                    //add the wallsection to the main submesh library
                    RawMeshData generatedSection         = null;
                    RawMeshData generatedSectionCollider = null;

                    BuildRCollider.BBox[] bboxes = new BuildRCollider.BBox[0];

                    if (section == null)
                    {
                        GenerationOutput output         = GenerationOutput.CreateRawOutput();
                        GenerationOutput outputCollider = null;
                        if (colliderType == BuildingColliderTypes.Complex)
                        {
                            outputCollider = GenerationOutput.CreateRawOutput();
                        }
                        if (colliderType == BuildingColliderTypes.Primitive)
                        {
                            BuildRCollider.BBox[] bbox = WallSectionGenerator.Generate(section, wallSectionSize, wallThickness);
                            generatedSectionPrimitiveColliders.Add(section, bbox);
                        }
                        WallSectionGenerator.Generate(section, output, wallSectionSize, false, wallThickness, true, outputCollider, dmesh.submeshLibrary);

                        generatedSection = output.raw;
                        if (outputCollider != null)
                        {
                            generatedSectionCollider = outputCollider.raw;
                        }
                    }
                    else
                    {
                        if (generatedSections.ContainsKey(section))
                        {
                            generatedSection = generatedSections[section];
                            if (generatedSectionMeshColliders.ContainsKey(section))
                            {
                                generatedSectionCollider = generatedSectionMeshColliders[section];
                            }
                        }
                        else
                        {
                            GenerationOutput output         = GenerationOutput.CreateRawOutput();
                            GenerationOutput outputCollider = null;
                            bool             cullOpening    = data.cullDoors && section.isDoor;
                            if (colliderType == BuildingColliderTypes.Complex)
                            {
                                outputCollider = GenerationOutput.CreateRawOutput();
                            }
                            if (colliderType == BuildingColliderTypes.Primitive)
                            {
                                BuildRCollider.BBox[] bbox = WallSectionGenerator.Generate(section, wallSectionSize, wallThickness, cullOpening);
                                generatedSectionPrimitiveColliders.Add(section, bbox);
                            }
                            WallSectionGenerator.Generate(section, output, wallSectionSize, false, wallThickness, cullOpening, outputCollider, dmesh.submeshLibrary);

                            generatedSections.Add(section, output.raw);
                            if (generatedSectionCollider != null)
                            {
                                generatedSectionMeshColliders.Add(section, outputCollider.raw);
                            }

                            generatedSection = output.raw;
                            if (generatedSectionCollider != null)
                            {
                                generatedSectionCollider = outputCollider.raw;
                            }
                        }

                        if (generatedSectionPrimitiveColliders.ContainsKey(section))
                        {
                            bboxes = generatedSectionPrimitiveColliders[section];
                        }
                    }

//				    Debug.Log("data strt" + data.isStraight);
                    if (data.isStraight)
                    {
                        Quaternion meshRot           = Quaternion.LookRotation(facadeNormal, Vector3.up);
                        Vector3    baseMeshPos       = data.baseA + facadeDirection * wallSectionSize.x + Vector3.up * wallSectionSize.y;
                        Vector3    wallSectionVector = new Vector3(wallSectionSize.x * s, wallSectionSize.y * fl, 0);
                        baseMeshPos += meshRot * wallSectionVector;
                        Vector3 meshPos = baseMeshPos + meshRot * -wallSectionSize * 0.5f;

                        Vector2 uvOffset       = new Vector2(wallSectionSize.x * s, wallSectionSize.y * fl);
                        Vector2 uvOffsetScaled = uvOffset;
                        if (section != null && section.wallSurface != null)
                        {
                            uvOffsetScaled = CalculateUv(uvOffsetScaled, section.wallSurface);
                        }

                        //TODO account for the mesh mode of the wall section - custom meshes
                        if (meshType == BuildingMeshTypes.Full)
                        {
                            dmesh.AddData(generatedSection, meshPos, meshRot, Vector3.one, uvOffsetScaled);
                        }
                        if (collider != null && generatedSectionCollider != null)
                        {
                            collider.mesh.AddData(generatedSectionCollider, meshPos, meshRot, Vector3.one);
                        }
                        if (collider != null && bboxes.Length > 0)
                        {
                            collider.AddBBox(bboxes, meshPos, meshRot);
                        }

//					    Debug.Log("foundation");
                        if (fl == 0 && foundation > Mathf.Epsilon)
                        {
                            Vector3 fp3 = baseMeshPos + Vector3.down * wallSectionSize.y;
                            Vector3 fp2 = fp3 - facadeDirection * wallSectionSize.x;
                            Vector3 fp0 = fp2 + Vector3.down * foundation;
                            Vector3 fp1 = fp3 + Vector3.down * foundation;

                            if (meshType == BuildingMeshTypes.Full)
                            {
                                Surface foundationSurface = data.foundationSurface != null ? data.foundationSurface : section.wallSurface;
                                int     foundationSubmesh = dmesh.submeshLibrary.SubmeshAdd(foundationSurface);                            //facadeSurfaces.IndexOf(section.wallSurface));
                                dmesh.AddPlane(fp0, fp1, fp2, fp3, new Vector2(uvOffset.x, -foundation), new Vector2(uvOffset.x + wallSectionSize.x, 0), -facadeNormal, facadeTangent, foundationSubmesh, foundationSurface);
                            }
                            if (collider != null && generatedSectionCollider != null)
                            {
                                collider.mesh.AddPlane(fp0, fp1, fp2, fp3, 0);
                            }
                        }
                    }
                    else
                    {
                        //todo switch - support wall section based curves for now

                        Vector3 cp0 = data.anchors[s].vector3XZ;
                        cp0.y = data.baseA.y;
                        Vector3 cp1 = data.anchors[s + 1].vector3XZ;
                        cp1.y = data.baseA.y;
                        Vector3 curveVector    = cp1 - cp0;
                        Vector3 curveDirection = curveVector.normalized;
                        Vector3 curveNormal    = Vector3.Cross(curveDirection, Vector3.up);
                        float   actualWidth    = curveVector.magnitude;

                        Quaternion meshRot           = Quaternion.LookRotation(curveNormal, Vector3.up);
                        Vector3    meshPos           = cp1 + Vector3.up * wallSectionSize.y;
                        Vector3    wallSectionVector = new Vector3(0, wallSectionSize.y * fl, 0);
                        meshPos += meshRot * wallSectionVector;
                        meshPos += meshRot * -new Vector3(actualWidth, wallSectionSize.y, 0) * 0.5f;
                        Vector3 meshScale = new Vector3(actualWidth / wallSectionSize.x, 1, 1);

                        //Thanks Anthony Cuellar - issue #12
                        Vector2 uvOffset       = new Vector2(wallSectionVector.x, wallSectionVector.y + (section.hasOpening ? 0 : wallSectionSize.y / 2f));
                        Vector2 uvOffsetScaled = CalculateUv(uvOffset, section.wallSurface);
                        //TODO account for the mesh mode of the wall section - custom meshes
                        if (meshType == BuildingMeshTypes.Full)
                        {
                            dmesh.AddData(generatedSection, meshPos, meshRot, meshScale, uvOffsetScaled);
                        }
                        if (collider != null && generatedSectionCollider != null)
                        {
                            collider.mesh.AddData(generatedSectionCollider, meshPos, meshRot, meshScale);
                        }
                        if (collider != null && bboxes.Length > 0)
                        {
                            collider.AddBBox(bboxes, meshPos, meshRot);
                        }

//					    Debug.Log("foundation");
                        if (fl == 0 && foundation > Mathf.Epsilon)
                        {
                            Vector3 fp3 = cp1;
                            Vector3 fp2 = fp3 - curveDirection * actualWidth;
                            Vector3 fp0 = fp2 + Vector3.down * foundation;
                            Vector3 fp1 = fp3 + Vector3.down * foundation;

                            if (meshType == BuildingMeshTypes.Full)
                            {
                                Surface foundationSurface = data.foundationSurface != null ? data.foundationSurface : section.wallSurface;
                                int     foundationSubmesh = dmesh.submeshLibrary.SubmeshAdd(foundationSurface);                            //facadeSurfaces.IndexOf(section.wallSurface);
                                dmesh.AddPlane(fp0, fp1, fp2, fp3, new Vector2(uvOffset.x, -foundation), new Vector2(uvOffset.x + actualWidth, 0), -curveNormal, facadeTangent, foundationSubmesh, foundationSurface);
                            }
                            if (collider != null && generatedSectionCollider != null)
                            {
                                collider.mesh.AddPlane(fp0, fp1, fp2, fp3, 0);
                            }
                        }
                    }
                }

                //string course is completely ignored for a collision
//			    Debug.Log("string");
                if (fl > 0 && data.facadeDesign.stringCourse && meshType == BuildingMeshTypes.Full)                //no string course on ground floor
                {
                    float   baseStringCoursePosition = wallSectionSize.y * fl + wallSectionSize.y * data.facadeDesign.stringCoursePosition;
                    Vector3 scBaseUp = baseStringCoursePosition * Vector3.up;
                    Vector3 scTopUp  = (data.facadeDesign.stringCourseHeight + baseStringCoursePosition) * Vector3.up;
                    if (data.isStraight)
                    {
                        Vector3 scNm    = data.facadeDesign.stringCourseDepth * facadeNormal;
                        Vector3 p0      = data.baseA;
                        Vector3 p1      = data.baseB;
                        Vector3 p0o     = data.baseA - scNm;
                        Vector3 p1o     = data.baseB - scNm;
                        int     submesh = dmesh.submeshLibrary.SubmeshAdd(data.facadeDesign.stringCourseSurface);                                                                                        //data.facadeDesign.stringCourseSurface != null ? facadeSurfaces.IndexOf(data.facadeDesign.stringCourseSurface) : 0;
                        Vector2 uvMax   = new Vector2(facadeLength, data.facadeDesign.stringCourseHeight);
                        dmesh.AddPlane(p0o + scBaseUp, p1o + scBaseUp, p0o + scTopUp, p1o + scTopUp, Vector3.zero, uvMax, -facadeNormal, facadeTangent, submesh, data.facadeDesign.stringCourseSurface); //front
                        dmesh.AddPlane(p0 + scBaseUp, p0o + scBaseUp, p0 + scTopUp, p0o + scTopUp, facadeNormal, facadeTangent, submesh);                                                                //left
                        dmesh.AddPlane(p1o + scBaseUp, p1 + scBaseUp, p1o + scTopUp, p1 + scTopUp, facadeNormal, facadeTangent, submesh);                                                                //right
                        float facadeAngle = BuildrUtils.CalculateFacadeAngle(facadeDirection);
                        dmesh.AddPlaneComplexUp(p0 + scBaseUp, p1 + scBaseUp, p0o + scBaseUp, p1o + scBaseUp, facadeAngle, Vector3.down, facadeTangent, submesh, data.facadeDesign.stringCourseSurface); //bottom
                        dmesh.AddPlaneComplexUp(p1 + scTopUp, p0 + scTopUp, p1o + scTopUp, p0o + scTopUp, facadeAngle, Vector3.up, facadeTangent, submesh, data.facadeDesign.stringCourseSurface);       //top
                    }
                    else
                    {
                        int       baseCurvePointCount = data.anchors.Count;                  //baseCurvepoints.Count;
                        Vector3[] interSectionNmls    = new Vector3[baseCurvePointCount];
                        for (int i = 0; i < baseCurvePointCount - 1; i++)
                        {
                            Vector3 p0 = data.anchors[i].vector3XZ;                            //baseCurvepoints[i];
                            Vector3 p1 = data.anchors[i + 1].vector3XZ;                        //baseCurvepoints[i + 1];
                            Vector3 p2 = data.anchors[Mathf.Max(i - 1, 0)].vector3XZ;          //baseCurvepoints[Mathf.Max(i - 1, 0)];
                            interSectionNmls[i] = Vector3.Cross((p1 - p0 + p0 - p2).normalized, Vector3.up);
                        }

                        for (int i = 0; i < baseCurvePointCount - 1; i++)
                        {
                            Vector3 p0            = data.anchors[i].vector3XZ;                 //baseCurvepoints[i];
                            Vector3 p1            = data.anchors[i + 1].vector3XZ;             //baseCurvepoints[i + 1];
                            Vector3 sectionVector = p1 - p0;
                            Vector3 sectionDir    = sectionVector.normalized;
                            Vector3 sectionNml    = Vector3.Cross(sectionDir, Vector3.up);
                            Vector4 sectionTgnt   = BuildRMesh.CalculateTangent(sectionDir);
                            Vector3 scNmA         = data.facadeDesign.stringCourseDepth * interSectionNmls[i + 0];
                            Vector3 scNmB         = data.facadeDesign.stringCourseDepth * interSectionNmls[i + 1];
                            Vector3 p0o           = p0 - scNmA;
                            Vector3 p1o           = p1 - scNmB;
                            int     submesh       = dmesh.submeshLibrary.SubmeshAdd(data.facadeDesign.stringCourseSurface);                  //data.facadeDesign.stringCourseSurface != null ? facadeSurfaces.IndexOf(data.facadeDesign.stringCourseSurface) : 0;
                            dmesh.AddPlane(p0o + scBaseUp, p1o + scBaseUp, p0o + scTopUp, p1o + scTopUp, sectionNml, sectionTgnt, submesh);
                            dmesh.AddPlane(p0 + scBaseUp, p0o + scBaseUp, p0 + scTopUp, p0o + scTopUp, sectionNml, sectionTgnt, submesh);
                            dmesh.AddPlane(p1o + scBaseUp, p1 + scBaseUp, p1o + scTopUp, p1 + scTopUp, sectionNml, sectionTgnt, submesh);
                            float facadeAngle = BuildrUtils.CalculateFacadeAngle(sectionDir);
                            dmesh.AddPlaneComplexUp(p0 + scBaseUp, p1 + scBaseUp, p0o + scBaseUp, p1o + scBaseUp, facadeAngle, Vector3.down, sectionTgnt, submesh, data.facadeDesign.stringCourseSurface);                      //bottom
                            dmesh.AddPlaneComplexUp(p1 + scTopUp, p0 + scTopUp, p1o + scTopUp, p0o + scTopUp, facadeAngle, Vector3.up, sectionTgnt, submesh, data.facadeDesign.stringCourseSurface);                            //top
                        }
                    }
                }
            }
        }
Esempio n. 5
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. 6
0
        public static bool Generate(BuildRMesh mesh, BuildRCollider collider, Vector2[] points, int[] facadeIndices, float roofBaseHeight, IVolume volume, Rect clampUV)
        {
            Roof           design     = volume.roof;
            OffsetSkeleton offsetPoly = new OffsetSkeleton(points);

            offsetPoly.direction = 1;
            offsetPoly.Execute();
            Shape shape       = offsetPoly.shape;
            int   submesh     = mesh.submeshLibrary.SubmeshAdd(design.mainSurface); // surfaceMapping.IndexOf(design.mainSurface);
            int   wallSubmesh = mesh.submeshLibrary.SubmeshAdd(design.wallSurface); //surfaceMapping.IndexOf(design.wallSurface);

            if (shape == null)
            {
                return(false);
            }

            List <Edge> edges     = new List <Edge>(shape.edges);
            List <Edge> baseEdges = new List <Edge>(shape.baseEdges);

            float shapeHeight  = shape.HeighestPoint();
            float designHeight = design.height;
            float heightScale  = designHeight / shapeHeight;

            Vector2 clampUVScale = Vector2.one;

            if (clampUV.width > 0)
            {
                FlatBounds bounds = new FlatBounds();
                for (int fvc = 0; fvc < points.Length; fvc++)
                {
                    bounds.Encapsulate(points[fvc]);
                }
                clampUVScale.x = bounds.width / clampUV.width;
                clampUVScale.y = bounds.height / clampUV.height;
            }

            Dictionary <Node, int>          shapeConnectionCount = new Dictionary <Node, int>();
            Dictionary <Node, List <Node> > shapeConnections     = new Dictionary <Node, List <Node> >();
            int edgeCount = edges.Count;

            for (int e = 0; e < edgeCount; e++)
            {
                Edge edge = edges[e];

                if (edge.length < Mathf.Epsilon)
                {
                    continue;
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeA))
                {
                    shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeA, new List <Node> {
                        edge.nodeB
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeA]++;
                    if (!shapeConnections[edge.nodeA].Contains(edge.nodeB))
                    {
                        shapeConnections[edge.nodeA].Add(edge.nodeB);
                    }
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeB))
                {
                    shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeB, new List <Node> {
                        edge.nodeA
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeB]++;
                    if (!shapeConnections[edge.nodeB].Contains(edge.nodeA))
                    {
                        shapeConnections[edge.nodeB].Add(edge.nodeA);
                    }
                }
            }

            int baseEdgeCount = baseEdges.Count;

            for (int b = 0; b < baseEdgeCount; b++)
            {
                Edge baseEdge = baseEdges[b];
                Node nodeA    = baseEdge.nodeA;
                Node nodeB    = baseEdge.nodeB;

                Node        currentNode = nodeA;
                Node        lastNode    = nodeB;
                int         itMax       = 50;
                List <Node> edgeShape   = new List <Node>()
                {
                    nodeA
                };

                while (currentNode != nodeB)
                {
                    List <Node> nodeConnections     = shapeConnections[currentNode];
                    int         nodeConnectionCount = nodeConnections.Count;
                    float       minAngle            = Mathf.Infinity;
                    Node        nextNode            = null;
                    Vector2     currentDirection    = (currentNode.position - lastNode.position).normalized;
                    for (int n = 0; n < nodeConnectionCount; n++)
                    {
                        Node connectingNode = nodeConnections[n];
                        if (connectingNode == lastNode)
                        {
                            continue;
                        }
                        Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized;
                        float   nodeAngle     = JMath.SignAngleDirection(currentDirection, nextDirection);
                        if (nodeAngle < minAngle)
                        {
                            minAngle = nodeAngle;
                            nextNode = connectingNode;
                        }
                    }
                    if (nextNode != null)
                    {
                        edgeShape.Add(nextNode);
                        lastNode    = currentNode;
                        currentNode = nextNode;
                    }


                    itMax--;
                    if (itMax < 0)
                    {
                        break;
                    }
                }

                int edgeShapeCount = edgeShape.Count;
                if (edgeShapeCount < 3)
                {
                    continue;
                }
//                Debug.Log("Generate edgeShapeCount "+ edgeShapeCount);

                Vector3[] verts = new Vector3[edgeShapeCount];

                Vector2[] uvs = new Vector2[edgeShapeCount];
                Vector3   baseShapeDirection = ShapeOffset.Utils.ToV3(nodeB.position - nodeA.position).normalized;
                float     uvAngle            = JMath.SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90;

                Vector2[] faceShape = new Vector2[edgeShapeCount];
                Vector3[] normals   = new Vector3[edgeShapeCount];
                Vector4[] tangents  = new Vector4[edgeShapeCount];
                //                Vector3 normal = Vector3.up;//BuildRMesh.CalculateNormal(); TODO
                Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection);
                for (int i = 0; i < edgeShapeCount; i++)//what on earth did I write here?
                {
                    Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y);
                    verts[i] = newVert;

                    Vector2 baseUV = new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z);
                    Vector2 newUV  = Vector2.zero;
                    if (i != 0)
                    {
                        newUV = JMath.Rotate(baseUV, uvAngle);
                    }
                    if (clampUV.width > Mathf.Epsilon)
                    {
                        newUV.x = Mathf.Clamp(clampUV.x + newUV.x / clampUVScale.x, clampUV.xMin, clampUV.xMax);
                        newUV.y = Mathf.Clamp(clampUV.y + newUV.y / clampUVScale.y, clampUV.yMin, clampUV.yMax);
                    }
                    else
                    {
                        if (i != 0)
                        {
                            float faceHeight = edgeShape[i].height * heightScale;
                            newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight));//hypotenuse of roof to give length of roof face
                            if (design.mainSurface != null)
                            {
                                newUV = design.mainSurface.CalculateUV(newUV);
                            }
                        }
                    }
                    uvs[i] = newUV;

                    faceShape[i] = edgeShape[i].position;//used for triangulation
                    //                    normals[i] = normal;
                    tangents[i] = tangent;
                }
//                int[] tris = EarClipper.Triangulate(faceShape, 0, -1);
                int[] tris     = Poly2TriWrapper.Triangulate(faceShape, true);
                int   triCount = tris.Length;

                Vector3 normal = (verts.Length > 2 && triCount > 2) ? BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]) : Vector3.up;
                for (int i = 0; i < edgeShapeCount; i++)
                {
                    normals[i] = normal;
                }

                mesh.AddData(verts, uvs, tris, normals, tangents, submesh);

                //gable
                bool isGabled = volume[facadeIndices[b]].isGabled;
                if (isGabled)
                {
                    for (int t = 0; t < triCount; t += 3)
                    {
                        if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0)
                        {
                            int beB = edgeShapeCount - 1;
                            if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB)
                            {
                                Vector3 b0       = verts[0];
                                Vector3 b1       = verts[beB];
                                Vector3 g0       = b0;
                                Vector3 g1       = b1;
                                int     topIndex = 0;
                                for (int tx = 0; tx < 3; tx++)
                                {
                                    if (tris[t + tx] != 0 && tris[t + tx] != beB)
                                    {
                                        topIndex = tris[t + tx];
                                    }
                                }
                                Vector3 b2 = verts[topIndex];

                                Vector3 baseV = b1 - b0;
                                Vector3 dir   = baseV.normalized;
                                Vector3 face  = Vector3.Cross(Vector3.up, dir).normalized;
                                Vector3 up    = Vector3.Project(b2 - b0, Vector3.up);

                                //clear triangle
                                tris[t]     = 0;
                                tris[t + 1] = 0;
                                tris[t + 2] = 0;

                                bool  simpleGable      = volume[facadeIndices[b]].simpleGable;
                                Gable gableStyle       = volume[facadeIndices[b]].gableStyle;
                                float thickness        = volume[facadeIndices[b]].gableThickness;
                                float additionalHeight = volume[facadeIndices[b]].gableHeight;
                                float height           = up.magnitude + additionalHeight;

                                if (simpleGable || gableStyle != null)
                                {
                                    Vector3 pitchVectorA = (b2 - b0).normalized;
                                    Vector3 pitchVectorB = (b2 - b1).normalized;
                                    float   angle        = Vector3.Angle(-face, pitchVectorA);
                                    float   scale        = Mathf.Cos(angle / 57.2957795f);
                                    b0 += pitchVectorA * (thickness * (1 / scale));
                                    b1 += pitchVectorB * (thickness * (1 / scale));
                                }

                                Vector3 center = Vector3.Lerp(b0, b1, 0.5f);
                                up = Vector3.Project(b2 - b0, Vector3.up); //recalculate after b change(?)
                                Vector3 b3 = center + up;
                                if (simpleGable)                           //generate a simple gable
                                {
                                    //generate simple gable based on roof
                                    Vector3 gCenter = Vector3.Lerp(g0, g1, 0.5f);
                                    Vector3 gBaseUp = Vector3.up * additionalHeight;
                                    Vector3 gUp     = up.normalized * height;
                                    Vector3 gBack   = -face * thickness;
                                    //todo further calculations
                                    //face
                                    mesh.AddPlane(g0, g1, g0 + gBaseUp, g1 + gBaseUp, wallSubmesh);
                                    mesh.AddTri(g1 + gBaseUp, g0 + gBaseUp, gCenter + gUp, dir, wallSubmesh);
                                    //backface
                                    mesh.AddPlane(g1 + gBack, g0 + gBack, g1 + gBaseUp + gBack, g0 + gBaseUp + gBack, wallSubmesh);
                                    mesh.AddTri(g0 + gBack + gBaseUp, g1 + gBack + gBaseUp, b3 + gBaseUp, -dir, wallSubmesh);
                                    //left
                                    mesh.AddPlane(g0 + gBack, g0, g0 + gBaseUp + gBack, g0 + gBaseUp, wallSubmesh);
                                    mesh.AddPlane(g0 + gBaseUp + gBack, g0 + gBaseUp, b3 + gBaseUp, gCenter + gUp, wallSubmesh);
                                    //right
                                    mesh.AddPlane(g1, g1 + gBack, g1 + gBaseUp, g1 + gBaseUp + gBack, wallSubmesh);
                                    mesh.AddPlane(g1 + gBaseUp, g1 + gBaseUp + gBack, gCenter + gUp, b3 + gBaseUp, wallSubmesh);
                                }
                                else if (volume[facadeIndices[b]].gableStyle != null)
                                {
                                    Vector2 baseUV = new Vector2(0, volume.planHeight);
                                    GableGenerator.Generate(ref mesh, gableStyle, g0, g1, height, thickness, baseUV);
                                }
                                else
                                {
                                    mesh.AddTri(b0, b3, b1, dir, submesh);//face - no separate gable
                                }

                                mesh.AddTri(b0, b2, b3, face, submesh);  //left
                                mesh.AddTri(b1, b3, b2, -face, submesh); //right
                            }
                        }
                    }
                }
            }

            return(true);
        }
Esempio n. 7
0
        public static void Portal(ref BuildRMesh dynamicMesh, Portal portal, Vector2 size, Vector3 offset, bool interior = true, SubmeshLibrary submeshLibrary = null)
        {
            if (submeshLibrary == null)
            {
                submeshLibrary = new SubmeshLibrary();
                submeshLibrary.Add(portal);
            }

            Division root = portal.root;

            List <Panel> processNodes           = new List <Panel>();
            Dictionary <Panel, Panel[]> dataDic = new Dictionary <Panel, Panel[]>();
            List <Panel> data      = new List <Panel>();
            Panel        rootPanel = new Panel(root, new Rect(0, 0, size.x, size.y), 0);

            processNodes.Add(rootPanel);
            float totalDepth = 0;

            while (processNodes.Count > 0)
            {
                Panel           current    = processNodes[0];
                Division        division   = current.division;
                List <Division> children   = division.GetChildren;
                int             childCount = children.Count;

                data.Add(current);//dump processed node into data.
                dataDic.Add(current, new Panel[childCount]);
                if (current.recess > totalDepth)
                {
                    totalDepth = current.recess;
                }

                float childRatio = 0;
                for (int c = 0; c < childCount; c++)
                {
                    childRatio += children[c].size;
                }

                for (int c = 0; c < childCount; c++)
                {
                    Division child        = children[c];
                    Rect     newPanelrect = current.rect;
                    float    ratio        = children[c].size / childRatio;

                    if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal)
                    {
                        newPanelrect.width  = Mathf.Max(newPanelrect.width - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio;
                        newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2, 0);
                        if (c > 0)
                        {
                            Panel lastPanel = processNodes[processNodes.Count - 1];
                            newPanelrect.x = lastPanel.rect.xMax + division.frame;
                        }
                        else
                        {
                            newPanelrect.x = current.rect.xMin + division.frame;
                        }
                        newPanelrect.y = current.rect.yMin + division.frame;
                    }
                    else
                    {
                        newPanelrect.width  = Mathf.Max(newPanelrect.width - division.frame * 2, 0);
                        newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio;
                        if (c > 0)
                        {
                            Panel lastPanel = processNodes[processNodes.Count - 1];
                            newPanelrect.y = lastPanel.rect.y + lastPanel.rect.height + division.frame;
                        }
                        else
                        {
                            newPanelrect.y = current.rect.yMin + division.frame;
                        }
                        newPanelrect.x = current.rect.xMin + division.frame;
                    }

                    Panel childPanel = new Panel(child, newPanelrect, current.recess + division.recess);
                    dataDic[current][c] = childPanel;

                    processNodes.Add(childPanel);
                }

                processNodes.RemoveAt(0);
            }

            int     dataCount      = data.Count;
            Vector3 norm           = Vector3.back;
            Vector4 tangent        = BuildRMesh.CalculateTangent(Vector3.right);
            Vector4 tangentForward = BuildRMesh.CalculateTangent(Vector3.forward);
            Vector4 tangentBack    = BuildRMesh.CalculateTangent(Vector3.back);
            Vector4 tangentInvert  = BuildRMesh.CalculateTangent(Vector3.left);
            Vector3 useOffset      = size * 0.5f;

            useOffset  += offset;
            useOffset.y = -useOffset.y;//inverse - UX resaons
            for (int i = 0; i < dataCount; i++)
            {
                Panel    panel    = data[i];
                Division division = panel.division;

                Rect panelRect = panel.rect;

                if (panelRect.width == 0 || panelRect.height == 0)
                {
                    continue;
                }

                Vector3 v0 = new Vector3(panelRect.xMin, -panelRect.yMin, panel.recess) - useOffset;
                Vector3 v1 = new Vector3(panelRect.xMax, -panelRect.yMin, panel.recess) - useOffset;
                Vector3 v2 = new Vector3(panelRect.xMin, -panelRect.yMax, panel.recess) - useOffset;
                Vector3 v3 = new Vector3(panelRect.xMax, -panelRect.yMax, panel.recess) - useOffset;

                Surface usedSurface = GetSurface(portal, division);
                int     useSubmesh  = submeshLibrary.SubmeshAdd(usedSurface);
//                int useSubmesh = usedSurface != null ? Array.IndexOf(usedSurfaces, usedSurface) : 0;

                Vector2 uv0 = CalculateUV(usedSurface, v0);
                Vector2 uv1 = CalculateUV(usedSurface, v1);
                Vector2 uv2 = CalculateUV(usedSurface, v2);
                Vector2 uv3 = CalculateUV(usedSurface, v3);

                if (!division.hasChildren)//simple panel
                {
                    Vector3[] verts    = { v0, v1, v2, v3 };
                    Vector2[] uvs      = { uv0, uv1, uv2, uv3 };
                    int[]     tris     = { 0, 1, 2, 1, 3, 2 };
                    Vector3[] norms    = { norm, norm, norm, norm };
                    Vector4[] tangents = { tangent, tangent, tangent, tangent };
                    dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);

                    if (interior)
                    {
                        Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                        verts    = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset };
                        uvs      = new[] { uv1, uv0, uv3, uv2 };
                        tris     = new[] { 0, 2, 1, 1, 2, 3 };
                        norms    = new[] { -norm, -norm, -norm, -norm };
                        tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert };

                        dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);
                    }
                }
                else//build a frame
                {
                    Vector3 v0f = v0 + new Vector3(division.frame, -division.frame, 0);
                    Vector3 v1f = v1 + new Vector3(-division.frame, -division.frame, 0);
                    Vector3 v2f = v2 + new Vector3(division.frame, division.frame, 0);
                    Vector3 v3f = v3 + new Vector3(-division.frame, division.frame, 0);

                    Vector3 recessV = Vector3.forward * (division.recess);
                    Vector3 v0r     = v0f + recessV;
                    Vector3 v1r     = v1f + recessV;
                    Vector3 v2r     = v2f + recessV;
                    Vector3 v3r     = v3f + recessV;

                    Vector2 uv0f = CalculateUV(usedSurface, v0f);
                    Vector2 uv1f = CalculateUV(usedSurface, v1f);
                    Vector2 uv2f = CalculateUV(usedSurface, v2f);
                    Vector2 uv3f = CalculateUV(usedSurface, v3f);

//                    Vector2 uv0r = CalculateUV(usedSurface, v0r);
//                    Vector2 uv1r = CalculateUV(usedSurface, v1r);
//                    Vector2 uv2r = CalculateUV(usedSurface, v2r);
//                    Vector2 uv3r = CalculateUV(usedSurface, v3r);

                    Vector3[] verts =
                    {
                        v0,  v1,  v2,  v3,
                        v0f, v1f, v2f, v3f
                    };
                    Vector2[] uvs =
                    {
                        uv0,  uv1,  uv2,  uv3,
                        uv0f, uv1f, uv2f, uv3f
                    };
                    Vector3[] norms =
                    {
                        norm, norm, norm, norm,
                        norm, norm, norm, norm
                    };
                    Vector4[] tangents =
                    {
                        tangent, tangent, tangent, tangent,
                        tangent, tangent, tangent, tangent
                    };

                    int[] tris =
                    {
                        0, 4, 2, 4, 6, 2,            //left
                        0, 1, 4, 1, 5, 4,            //top
                        5, 1, 3, 5, 3, 7,            //right
                        2, 6, 3, 3, 6, 7,            //bottom
                    };

                    dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);
                    Vector2 uvUp    = CalculateUV(usedSurface, new Vector2(0, division.recess));
                    Vector2 uvRight = CalculateUV(usedSurface, new Vector2(division.recess, 0));
                    dynamicMesh.AddPlaneComplex(v1f, v0f, v1r, v0r, uv1f, uv0f, uv1f + uvUp, uv0f + uvUp, Vector3.down, tangent, useSubmesh, usedSurface);               //top
                    dynamicMesh.AddPlaneComplex(v2f, v3f, v2r, v3r, uv2f, uv3f, uv2f + uvUp, uv3f + uvUp, Vector3.up, tangent, useSubmesh, usedSurface);                 //bottom
                    dynamicMesh.AddPlaneComplex(v0f, v2f, v0r, v2r, uv0f, uv2f, uv0f + uvRight, uv2f + uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //left
                    dynamicMesh.AddPlaneComplex(v3f, v1f, v3r, v1r, uv3f, uv1f, uv3f + uvRight, uv1f + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface);     //right

                    if (interior)
                    {
                        Vector3 interiorOffset  = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                        Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2);
                        verts = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset, v0f + interiorOffset, v1f + interiorOffset, v2f + interiorOffset, v3f + interiorOffset };
                        uvs   = new [] { uv1, uv0, uv3, uv2, uv1f, uv0f, uv3f, uv2f };
                        Array.Reverse(tris);
                        norms    = new[] { -norm, -norm, -norm, -norm, -norm, -norm, -norm, -norm };
                        tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert };

                        dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh);
                        dynamicMesh.AddPlaneComplex(v0f + interiorOffset, v1f + interiorOffset, v0r + interiorOffsetr, v1r + interiorOffsetr, uv0f, uv1f, uv0f + uvUp, uv1f + uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface);        //top
                        dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v2f + interiorOffset, v3r + interiorOffsetr, v2r + interiorOffsetr, uv3f, uv2f, uv3f + uvUp, uv2f + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface);          //bottom
                        dynamicMesh.AddPlaneComplex(v2f + interiorOffset, v0f + interiorOffset, v2r + interiorOffsetr, v0r + interiorOffsetr, uv2f, uv0f, uv2f + uvRight, uv0f + uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface);   //left
                        dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v3f + interiorOffset, v3r + interiorOffsetr, v3r + interiorOffsetr, uv1f, uv3f, uv1f + uvRight, uv3f + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface); //right
                    }

                    List <Division> children   = division.GetChildren;
                    int             childCount = children.Count;
                    if (childCount > 1 && division.frame > 0)
                    {
                        for (int c = 0; c < childCount - 1; c++)
                        {
                            Panel childPanel = dataDic[panel][c];
                            if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal)
                            {
                                Vector3 v0d = v0 + new Vector3(childPanel.rect.xMax - panelRect.xMin, -division.frame, 0);
                                Vector3 v1d = v0d + new Vector3(division.frame, 0, 0);
                                Vector3 v2d = v0d + new Vector3(0, -panelRect.height + division.frame * 2, 0);
                                Vector3 v3d = v1d + new Vector3(0, -panelRect.height + division.frame * 2, 0);

                                Vector2 uv0d = CalculateUV(usedSurface, v0d);
                                Vector2 uv1d = CalculateUV(usedSurface, v1d);
                                Vector2 uv2d = CalculateUV(usedSurface, v2d);
                                Vector2 uv3d = CalculateUV(usedSurface, v3d);

                                dynamicMesh.AddPlaneComplex(v1d, v0d, v3d, v2d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface);                                                      //divider face

                                dynamicMesh.AddPlaneComplex(v2d, v0d, v2d + recessV, v0d + recessV, uv2d, uv0d, uv2d + uvRight, uv0d + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface);  //divider left
                                dynamicMesh.AddPlaneComplex(v1d, v3d, v1d + recessV, v3d + recessV, uv1d, uv3d, uv1d - uvRight, uv3d - uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface); //divider right

                                if (interior)
                                {
                                    Vector3 interiorOffset  = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                                    Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2);
                                    dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v1d + interiorOffset, v2d + interiorOffset, v3d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface);                                                    //divider face
                                    dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v2d + interiorOffset, v0d + recessV + interiorOffsetr, v2d + recessV + interiorOffsetr, uv0d, uv2d, uv0d + uvRight, uv2d + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface);  //divider left
                                    dynamicMesh.AddPlaneComplex(v3d + interiorOffset, v1d + interiorOffset, v3d + recessV + interiorOffsetr, v1d + recessV + interiorOffsetr, uv3d, uv1d, uv3d - uvRight, uv1d - uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //divider right
                                }
                            }
                            else
                            {
                                Vector3 v0d = v0 + new Vector3(division.frame, -childPanel.rect.yMax + panelRect.yMin, 0);
                                Vector3 v1d = v0d + new Vector3(0, -division.frame, 0);
                                Vector3 v2d = v0d + new Vector3(panelRect.width - division.frame * 2, 0, 0);
                                Vector3 v3d = v1d + new Vector3(panelRect.width - division.frame * 2, 0, 0);

                                Vector2 uv0d = CalculateUV(usedSurface, v0d);
                                Vector2 uv1d = CalculateUV(usedSurface, v1d);
                                Vector2 uv2d = CalculateUV(usedSurface, v2d);
                                Vector2 uv3d = CalculateUV(usedSurface, v3d);

                                dynamicMesh.AddPlaneComplex(v0d, v1d, v2d, v3d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface);                                           //divider face

                                dynamicMesh.AddPlaneComplex(v0d, v2d, v0d + recessV, v2d + recessV, uv0d, uv2d, uv0d + uvUp, uv2d + uvUp, Vector3.up, tangent, useSubmesh, usedSurface);   //divider top
                                dynamicMesh.AddPlaneComplex(v3d, v1d, v3d + recessV, v1d + recessV, uv3d, uv1d, uv3d - uvUp, uv1d - uvUp, Vector3.down, tangent, useSubmesh, usedSurface); //divider bottom

                                if (interior)
                                {
                                    Vector3 interiorOffset  = new Vector3(0, 0, (totalDepth - panel.recess) * 2);
                                    Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2);
                                    dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v0d + interiorOffset, v3d + interiorOffset, v2d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface);                                            //divider face
                                    dynamicMesh.AddPlaneComplex(v2d + interiorOffset, v0d + interiorOffset, v2d + recessV + interiorOffsetr, v0d + recessV + interiorOffsetr, uv2d, uv0d, uv2d + uvUp, uv0d + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface);   //divider top
                                    dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v3d + interiorOffset, v1d + recessV + interiorOffsetr, v3d + recessV + interiorOffsetr, uv1d, uv3d, uv1d - uvUp, uv3d - uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface); //divider bottom
                                }
                            }
                        }
                    }
                }
            }
        }
Esempio n. 8
0
        public static void GenerateWall(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int wallSubmesh = -1, BuildRCollider collider = null)
        {
            float stairWidth       = 0.70f;      //todo / calculate
            float wallThickness    = VerticalOpening.WALL_THICKNESS;
            float doorWidth        = 1.3f;
            float doorHeight       = 2.04f;
            bool  generateColldier = collider != null;
            //            bool generateMeshCollider = generateColldier && !collider.usingPrimitives;

            SubmeshLibrary submeshLibrary      = mesh.submeshLibrary;
            int            externalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceA);
            int            internalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB);
            int            doorFrameSubmesh    = submeshLibrary.SubmeshAdd(opening.surfaceC);

            //base positions
            Quaternion rotation    = Quaternion.Euler(0, opening.rotation, 0);
            Vector2Int openingSize = opening.size;
            Vector3    b0          = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f);
            Vector3    b1          = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f);
            Vector3    b2          = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f);
            Vector3    b3          = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f);

            //inner points
            Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness;
            Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness;
            Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness;
            Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness;

            Vector3 escalationFlatDir = (b2i - b0i).normalized;
            Vector3 wallUp            = Vector3.up * height;

            //external walls
            Vector2 uv20_min  = new Vector2(0, 0);
            Vector2 uv20_max  = new Vector2(opening.size.vy, height);
            Vector3 normal02  = rotation * Vector3.left;
            Vector4 tangent02 = BuildRMesh.CalculateTangent((b0 - b2).normalized);

            mesh.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp, uv20_min, uv20_max, normal02, tangent02, externalWallSubmesh, opening.surfaceA);

            Vector2 uv32_min  = new Vector2(0, 0);
            Vector2 uv32_max  = new Vector2(opening.size.vx, height);
            Vector3 normal32  = rotation * Vector3.forward;
            Vector4 tangent32 = BuildRMesh.CalculateTangent((b2 - b3).normalized);

            mesh.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp, uv32_min, uv32_max, normal32, tangent32, externalWallSubmesh, opening.surfaceA);

            Vector2 uv13_min  = new Vector2(0, 0);
            Vector2 uv13_max  = new Vector2(opening.size.vy, height);
            Vector3 normal13  = rotation * Vector3.right;
            Vector4 tangent13 = BuildRMesh.CalculateTangent((b3 - b1).normalized);

            mesh.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp, uv13_min, uv13_max, normal13, tangent13, externalWallSubmesh, opening.surfaceA);

            //internal walls
            Vector2 uv20i_min  = new Vector2(wallThickness, 0);
            Vector2 uv20i_max  = new Vector2(opening.size.vy - wallThickness, height);
            Vector3 normal02i  = rotation * Vector3.right;
            Vector4 tangent02i = BuildRMesh.CalculateTangent((b2 - b0).normalized);

            mesh.AddPlane(b0i, b2i, b0i + wallUp, b2i + wallUp, uv20i_min, uv20i_max, normal02i, tangent02i, internalWallSubmesh, opening.surfaceB);

            Vector2 uv32i_min  = new Vector2(0, 0);
            Vector2 uv32i_max  = new Vector2(opening.size.vx - wallThickness, height);
            Vector3 normal32i  = rotation * Vector3.back;
            Vector4 tangent32i = BuildRMesh.CalculateTangent((b3 - b2).normalized);

            mesh.AddPlane(b2i, b3i, b2i + wallUp, b3i + wallUp, uv32i_min, uv32i_max, normal32i, tangent32i, internalWallSubmesh, opening.surfaceB);

            Vector2 uv13i_min  = new Vector2(0, 0);
            Vector2 uv13i_max  = new Vector2(opening.size.vy - wallThickness, height);
            Vector3 normal13i  = rotation * Vector3.left;
            Vector4 tangent13i = BuildRMesh.CalculateTangent((b1 - b3).normalized);

            mesh.AddPlane(b3i, b1i, b3i + wallUp, b1i + wallUp, uv13i_min, uv13i_max, normal13i, tangent13i, internalWallSubmesh, opening.surfaceB);

            if (generateColldier)
            {
                collider.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp);
                collider.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp);
                collider.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp);

                if (!collider.usingPrimitives)
                {
                    collider.mesh.AddPlane(b0i, b2i, b0i + wallUp, b2i + wallUp, 0);
                    collider.mesh.AddPlane(b2i, b3i, b2i + wallUp, b3i + wallUp, 0);
                    collider.mesh.AddPlane(b3i, b1i, b3i + wallUp, b1i + wallUp, 0);
                }
            }


            //door wall

            float internalWallLength = openingSize.vx - (wallThickness * 2f);
            float lerpA = Mathf.Max(stairWidth - doorWidth, 0.05f) / internalWallLength;
            float lerpB = (Mathf.Max(stairWidth - doorWidth, 0.05f) + doorWidth) / internalWallLength;

            Vector2 uvd_b0 = new Vector2(0, 0);
            Vector2 uvd_b1 = new Vector2(opening.size.vx * lerpA, 0);
            Vector2 uvd_b2 = new Vector2(opening.size.vx * lerpB, 0);
            Vector2 uvd_b3 = new Vector2(opening.size.vx, 0);
            Vector2 uvd_m0 = new Vector2(uvd_b0.x, doorHeight);
            Vector2 uvd_m1 = new Vector2(uvd_b1.x, doorHeight);
            Vector2 uvd_m3 = new Vector2(uvd_b3.x, doorHeight);
            Vector2 uvd_t0 = new Vector2(0, height);
            Vector2 uvd_t3 = new Vector2(opening.size.vx, height);

            //internal

            Vector3 bd0i       = Vector3.Lerp(b0i, b1i, lerpA);
            Vector3 bd1i       = Vector3.Lerp(b0i, b1i, lerpB);
            Vector3 normal01i  = rotation * Vector3.forward;
            Vector4 tangent01i = BuildRMesh.CalculateTangent((b0 - b1).normalized);

            Vector3 doorUp = Vector3.up * doorHeight;

            //Right side
            mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, uvd_b0, uvd_m1, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB);
            //left side
            mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, uvd_b2, uvd_m3, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB);
            //top
            mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUp, b0i + wallUp, uvd_m3, uvd_t0, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB);

            //external
            Vector3 doorOut   = -escalationFlatDir * wallThickness;
            Vector3 normal01  = rotation * Vector3.back;
            Vector4 tangent01 = BuildRMesh.CalculateTangent((b1 - b0).normalized);

            //left
            mesh.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp, uvd_b0, uvd_m1, normal01, tangent01, externalWallSubmesh, opening.surfaceA);
            //right
            mesh.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp, uvd_b2, uvd_m3, normal01, tangent01, externalWallSubmesh, opening.surfaceA);
            //top
            mesh.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp, uvd_m0, uvd_t3, normal01, tangent01, externalWallSubmesh, opening.surfaceA);

            //frame
            //floor
            mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, externalWallSubmesh);
            //left
            mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, doorFrameSubmesh);
            //right
            mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh);
            //top
            mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh);

            if (generateColldier)
            {
                collider.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp);
                collider.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp);
                collider.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp);

                if (!collider.usingPrimitives)
                {
                    collider.mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, 0);
                    collider.mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, 0);
                    collider.mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUp, b0i + wallUp, 0);

                    collider.mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, 0);
                    collider.mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, 0);
                    collider.mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, 0);
                    collider.mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, 0);
                }
            }
        }
Esempio n. 9
0
        public static void GenerateStairs(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int floor, int wallSubmesh = -1, BuildRCollider collider = null)
        {
            bool  stepped          = true;  //todo
            float minimumWidth     = 0.9f;  //UK standard
            float stepHeight       = 0.22f;
            float wallThickness    = VerticalOpening.WALL_THICKNESS;
            bool  generateColldier = collider != null;

            float minimumRunLength   = 0.25f;
            float maximumRiserHeight = 0.2f;

            int internalWallSubmesh  = mesh.submeshLibrary.SubmeshAdd(opening.surfaceB);
            int internalFloorSubmesh = mesh.submeshLibrary.SubmeshAdd(opening.surfaceD);

            bool isBottomFloor = opening.baseFloor == floor;
            bool isTopFloor    = opening.baseFloor + opening.floors == floor;
            //            Debug.Log((opening.baseFloor + opening.floors - 1) +" "+ floor);

            //base positions
            Quaternion rotation    = Quaternion.Euler(0, opening.rotation, 0);
            Vector2Int openingSize = opening.size;
            Vector3    b0          = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f);
            Vector3    b1          = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f);
            Vector3    b2          = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f);
            Vector3    b3          = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f);

            //inner points
            Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness;
            Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness;
            Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness;
            Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness;

            Vector2 internalSize    = new Vector2(openingSize.vx - wallThickness * 2, openingSize.vy - wallThickness * 2);
            float   stairWidthFromX = internalSize.x * 0.5f;
            float   stairWidthFromY = internalSize.y - Mathf.Ceil(height / maximumRiserHeight) * minimumRunLength;

            float useLandingWidth = (stairWidthFromX + stairWidthFromY) * 0.5f;

            useLandingWidth = Mathf.Clamp(useLandingWidth, minimumWidth, opening.stairWidth);            //Mathf.Max(stairWidth, internalSize.x * 0.5f));
            float useStairWidth = Mathf.Clamp(opening.stairWidth, minimumWidth, stairWidthFromX);


            float stairRun = internalSize.y - (useLandingWidth * 2);


            Vector3 escalationFlatDir    = (b2i - b0i).normalized;
            Vector3 escalationRight      = (b1i - b0i).normalized;
            Vector3 escalationVector     = new Vector3(stairRun * escalationFlatDir.x, height * 0.5f, stairRun * escalationFlatDir.z);
            Vector3 escalationDirection  = escalationVector.normalized;
            float   escalationHypotenuse = escalationVector.magnitude;
            int     numberOfSteps        = Mathf.CeilToInt((height) / stepHeight);

            Vector3 escalationVectorB    = new Vector3(stairRun * -escalationFlatDir.x, height * 0.5f, stairRun * -escalationFlatDir.z);
            Vector3 escalationDirectionB = escalationVectorB.normalized;

            Vector3 landingDrop  = Vector3.down * wallThickness;
            Vector4 rightTangent = BuildRMesh.CalculateTangent(escalationRight);

            //lower landing
            if (!isBottomFloor)
            {
                Vector3 l0 = b0i;
                Vector3 l1 = b1i;
                Vector3 l2 = b0i + escalationFlatDir * useLandingWidth;
                Vector3 l3 = b1i + escalationFlatDir * useLandingWidth;

                Vector2 maxUVTop  = new Vector2(internalSize.x, useLandingWidth);
                Vector2 maxUVSide = new Vector2(internalSize.x, stepHeight);
                //top
                mesh.AddPlane(l0, l1, l2, l3, Vector3.zero, maxUVTop, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD);
                //bottom
                mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, Vector3.zero, maxUVTop, Vector3.down, rightTangent, internalWallSubmesh, opening.surfaceB);
                //front
                mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, escalationFlatDir, maxUVSide, Vector3.up, rightTangent, internalWallSubmesh, opening.surfaceB);

                if (generateColldier)
                {
                    collider.mesh.AddPlane(l0, l1, l2, l3, 0);
                    collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0);
                    collider.mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, 0);
                }
            }

            if (!isTopFloor)
            {
                //mid landing

                if (true)                //half landed
                {
                    Vector3 up = Vector3.up * height * 0.5f;
                    Vector3 l0 = b2i - escalationFlatDir * useLandingWidth + up;
                    Vector3 l1 = b3i - escalationFlatDir * useLandingWidth + up;
                    Vector3 l2 = b2i + up;
                    Vector3 l3 = b3i + up;

                    Vector2 maxUVTop  = new Vector2(internalSize.x, useLandingWidth);
                    Vector2 maxUVSide = new Vector2(internalSize.x, useLandingWidth);
                    //top
                    mesh.AddPlane(l0, l1, l2, l3, Vector3.zero, maxUVTop, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD);
                    //bottom
                    mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, Vector3.zero, maxUVTop, Vector3.down, rightTangent, internalWallSubmesh, opening.surfaceB);
                    //front
                    mesh.AddPlane(l1, l0, l1 + landingDrop, l0 + landingDrop, Vector3.zero, maxUVSide, -escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB);

                    if (generateColldier)
                    {
                        collider.mesh.AddPlane(l0, l1, l2, l3, 0);
                        collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0);
                        collider.mesh.AddPlane(l1, l0, l1 + landingDrop, l0 + landingDrop, 0);
                    }
                }

                Vector3 flightABaseOutside = b0i + escalationFlatDir * useLandingWidth;
                Vector3 flightABaseInside  = flightABaseOutside + escalationRight * useStairWidth;
                Vector3 flightATopOutside  = flightABaseOutside + escalationDirection * escalationHypotenuse;
                Vector3 flightATopInside   = flightABaseInside + escalationDirection * escalationHypotenuse;
                float   dropThickness      = wallThickness;         //Mathf.Sin(Mathf.Atan2(height, stairRun)) * wallThickness;

                Vector3 flightABaseOutsideDrop = flightABaseOutside + Vector3.down * dropThickness;
                Vector3 flightABaseInsideDrop  = flightABaseInside + Vector3.down * dropThickness;
                Vector3 flightATopOutsideDrop  = flightATopOutside + Vector3.down * dropThickness;
                Vector3 flightATopInsideDrop   = flightATopInside + Vector3.down * dropThickness;

                Vector3 flightBBaseOutside = b3i - escalationFlatDir * useLandingWidth + Vector3.up * height * 0.5f;
                Vector3 flightBBaseInside  = flightBBaseOutside - escalationRight * useStairWidth;
                Vector3 flightBTopOutside  = flightBBaseOutside + escalationDirectionB * escalationHypotenuse;
                Vector3 flightBTopInside   = flightBBaseInside + escalationDirectionB * escalationHypotenuse;

                Vector3 flightBBaseOutsideDrop = flightBBaseOutside + Vector3.down * dropThickness;
                Vector3 flightBBaseInsideDrop  = flightBBaseInside + Vector3.down * dropThickness;
                Vector3 flightBTopOutsideDrop  = flightBTopOutside + Vector3.down * dropThickness;
                Vector3 flightBTopInsideDrop   = flightBTopInside + Vector3.down * dropThickness;

                if (generateColldier)
                {
                    collider.mesh.AddPlane(flightABaseOutside, flightABaseInside, flightATopOutside, flightATopInside, 0);
                    collider.mesh.AddPlane(flightABaseInsideDrop, flightATopInsideDrop, flightABaseInside, flightATopInside, 0);
                    collider.mesh.AddPlane(flightABaseInsideDrop, flightABaseOutsideDrop, flightATopInsideDrop, flightATopOutsideDrop, 0);
                    collider.mesh.AddPlane(flightBBaseOutside, flightBBaseInside, flightBTopOutside, flightBTopInside, 0);
                    collider.mesh.AddPlane(flightBBaseInsideDrop, flightBTopInsideDrop, flightBBaseInside, flightBTopInside, 0);
                    collider.mesh.AddPlane(flightBBaseInsideDrop, flightBBaseOutsideDrop, flightBTopInsideDrop, flightBTopOutsideDrop, 0);
                }

                if (stepped)                //todo, flat generation
                {
                    float stepDepth = stairRun / (numberOfSteps);
                    float skipStep  = (stepDepth / (numberOfSteps - 1));
                    stepDepth += skipStep;
                    float stepRiser = height / numberOfSteps / 2;

                    Vector2 stepUvTopMin  = new Vector2(0, 0);
                    Vector2 stepUvTopMax  = new Vector2(useStairWidth, stepDepth);
                    Vector2 stepUvSideMin = new Vector2(0, 0);
                    Vector2 stepUvSideMax = new Vector2(useStairWidth, stepRiser);

                    //flight one
                    float   lerpIncrement         = 1.0f / (numberOfSteps - 1);
                    Vector3 flightATopOutsideStep = flightATopOutside + Vector3.down * stepHeight * 0.5f;
                    Vector3 flightATopInsideStep  = flightATopInside + Vector3.down * stepHeight * 0.5f;
                    for (int s = 0; s < numberOfSteps - 1; s++)
                    {
                        float   lerpValueAA = lerpIncrement * s;
                        Vector3 s0          = Vector3.Lerp(flightABaseOutside, flightATopOutsideStep, lerpValueAA);
                        Vector3 s1          = Vector3.Lerp(flightABaseInside, flightATopInsideStep, lerpValueAA);
                        Vector3 s2          = s0 + Vector3.up * stepRiser;
                        Vector3 s3          = s1 + Vector3.up * stepRiser;
                        Vector3 s4          = s2 + escalationFlatDir.normalized * stepDepth;
                        Vector3 s5          = s3 + escalationFlatDir.normalized * stepDepth;

                        //front
                        mesh.AddPlane(s0, s1, s2, s3, stepUvSideMin, stepUvSideMax, -escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB);
                        //top
                        mesh.AddPlane(s2, s3, s4, s5, stepUvTopMin, stepUvTopMax, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD);
                        //sides

                        float     lerpValueB = lerpIncrement * s;
                        Vector3   normal = escalationRight;
                        Vector3[] normals = { normal, normal, normal, normal };
                        Vector4   tangent = BuildRMesh.CalculateTangent(escalationFlatDir);
                        Vector4[] tangents = { tangent, tangent, tangent, tangent };
                        Vector3   s8 = Vector3.Lerp(flightABaseInsideDrop, flightATopInsideDrop, lerpValueB);
                        Vector3   s9 = Vector3.Lerp(flightABaseInsideDrop, flightATopInsideDrop, lerpValueB + lerpIncrement);
                        Vector2   uv5, uv3, uv8, uv9;
                        if (opening.surfaceB != null)
                        {
                            uv5 = opening.surfaceB.CalculateUV(new Vector2(s5.z, s5.y));
                            uv3 = opening.surfaceB.CalculateUV(new Vector2(s3.z, s3.y));
                            uv8 = opening.surfaceB.CalculateUV(new Vector2(s8.z, s8.y));
                            uv9 = opening.surfaceB.CalculateUV(new Vector2(s9.z, s9.y));
                        }
                        else
                        {
                            uv5 = new Vector2();
                            uv3 = new Vector2();
                            uv8 = new Vector2();
                            uv9 = new Vector2();
                        }

                        mesh.AddData(new[] { s3, s5, s8, s9 }, new[] { uv3, uv5, uv8, uv9 }, new[] { 0, 1, 2, 2, 1, 3 }, normals, tangents, internalWallSubmesh);

                        if (opening.surfaceB.tiled)
                        {
                            stepUvSideMin.x += 0.11f;
                            stepUvSideMin.y += 0.37f;
                            stepUvSideMax.x += 0.11f;
                            stepUvSideMax.y += 0.37f;
                        }
                        if (opening.surfaceD.tiled)
                        {
                            stepUvTopMin.x += 0.23f;
                            stepUvTopMin.y += 0.13f;
                            stepUvTopMax.x += 0.23f;
                            stepUvTopMax.y += 0.13f;
                        }
                    }
                    mesh.AddPlane(flightABaseInsideDrop, flightABaseOutsideDrop, flightATopInsideDrop, flightATopOutsideDrop, internalWallSubmesh);                    //underside

                    //flight two
                    Vector3 flightBTopOutsideStep = flightBTopOutside + Vector3.down * stepHeight * 0.5f;
                    Vector3 flightBTopInsideStep  = flightBTopInside + Vector3.down * stepHeight * 0.5f;
                    for (int s = 0; s < numberOfSteps - 1; s++)
                    {
                        float   lerpValue = lerpIncrement * s;
                        Vector3 s0        = Vector3.Lerp(flightBBaseOutside, flightBTopOutsideStep, lerpValue);
                        Vector3 s1        = Vector3.Lerp(flightBBaseInside, flightBTopInsideStep, lerpValue);
                        Vector3 s2        = s0 + Vector3.up * stepRiser;
                        Vector3 s3        = s1 + Vector3.up * stepRiser;
                        Vector3 s4        = s2 - escalationFlatDir.normalized * stepDepth;
                        Vector3 s5        = s3 - escalationFlatDir.normalized * stepDepth;
                        //front
                        mesh.AddPlane(s0, s1, s2, s3, stepUvSideMin, stepUvSideMax, escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB);
                        //top
                        mesh.AddPlane(s2, s3, s4, s5, stepUvTopMin, stepUvTopMax, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD);

                        //sides
                        float     lerpValueB = lerpIncrement * s;
                        Vector3   normal = escalationRight;
                        Vector3[] normals = { normal, normal, normal, normal };
                        Vector4   tangent = BuildRMesh.CalculateTangent(escalationFlatDir);
                        Vector4[] tangents = { tangent, tangent, tangent, tangent };
                        Vector3   s8 = Vector3.Lerp(flightBBaseInsideDrop, flightBTopInsideDrop, lerpValueB);
                        Vector3   s9 = Vector3.Lerp(flightBBaseInsideDrop, flightBTopInsideDrop, lerpValueB + lerpIncrement);
                        Vector2   uv5, uv3, uv8, uv9;
                        if (opening.surfaceB != null)
                        {
                            uv5 = opening.surfaceB.CalculateUV(new Vector2(s5.z, s5.y));
                            uv3 = opening.surfaceB.CalculateUV(new Vector2(s3.z, s3.y));
                            uv8 = opening.surfaceB.CalculateUV(new Vector2(s8.z, s8.y));
                            uv9 = opening.surfaceB.CalculateUV(new Vector2(s9.z, s9.y));
                        }
                        else
                        {
                            uv5 = new Vector2();
                            uv3 = new Vector2();
                            uv8 = new Vector2();
                            uv9 = new Vector2();
                        }

                        mesh.AddData(new[] { s3, s5, s8, s9 }, new[] { uv3, uv5, uv8, uv9 }, new[] { 0, 1, 2, 2, 1, 3 }, normals, tangents, internalWallSubmesh);
                    }
                    mesh.AddPlane(flightBBaseInsideDrop, flightBBaseOutsideDrop, flightBTopInsideDrop, flightBTopOutsideDrop, internalWallSubmesh);                    //underside
                }
            }
        }
Esempio n. 10
0
        private static void ToMesh(ref BuildRMesh mesh, ref Shape shape, float roofBaseHeight, float meshHeight, int[] facadeIndices, IVolume volume, int submesh, Surface surface, bool generateDormers = false)
        {
            //TODO fix this error properly
            if (shape == null)
            {
                Debug.Log("ToMesh: Error to fix");
                return;
            }
            List <Edge> edges     = new List <Edge>(shape.edges);
            List <Edge> baseEdges = new List <Edge>(shape.baseEdges);

            float shapeHeight = shape.HeighestPoint();
            float heightScale = meshHeight / shapeHeight;
            bool  isFloor     = meshHeight < 0.00001f;

            Dictionary <Node, int>          shapeConnectionCount = new Dictionary <Node, int>();
            Dictionary <Node, List <Node> > shapeConnections     = new Dictionary <Node, List <Node> >();
            int edgeCount = edges.Count;

            for (int e = 0; e < edgeCount; e++)
            {
                Edge edge = edges[e];

                if (edge.length < Mathf.Epsilon)
                {
                    continue;
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeA))
                {
                    shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeA, new List <Node> {
                        edge.nodeB
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeA]++;
                    if (!shapeConnections[edge.nodeA].Contains(edge.nodeB))
                    {
                        shapeConnections[edge.nodeA].Add(edge.nodeB);
                    }
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeB))
                {
                    shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeB, new List <Node> {
                        edge.nodeA
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeB]++;
                    if (!shapeConnections[edge.nodeB].Contains(edge.nodeA))
                    {
                        shapeConnections[edge.nodeB].Add(edge.nodeA);
                    }
                }
            }

            int baseEdgeCount          = baseEdges.Count;
            List <Vector3[]> roofFaces = new List <Vector3[]>();

            for (int b = 0; b < baseEdgeCount; b++)
            {
                int  facadeIndex = facadeIndices[b];
                bool isGabled    = volume[facadeIndex].isGabled;
                if (!isGabled)
                {
                    int  facadeIndexLeft  = (facadeIndex - 1 + volume.numberOfFacades) % volume.numberOfFacades;
                    int  facadeIndexRight = (facadeIndex + 1) % volume.numberOfFacades;
                    bool isGabledLeft     = volume[facadeIndexLeft].isGabled;
                    bool isGabledRight    = volume[facadeIndexRight].isGabled;
                    Edge baseEdge         = baseEdges[b];
                    Node nodeA            = baseEdge.nodeA;
                    Node nodeB            = baseEdge.nodeB;

                    Node        currentNode = nodeA;
                    Node        lastNode    = nodeB;
                    int         itMax       = 50;
                    List <Node> edgeShape   = new List <Node>()
                    {
                        nodeA
                    };

                    while (currentNode != nodeB)
                    {
                        List <Node> nodeConnections     = shapeConnections[currentNode];
                        int         nodeConnectionCount = nodeConnections.Count;
                        float       minAngle            = Mathf.Infinity;
                        Node        nextNode            = null;
                        Vector2     currentDirection    = (currentNode.position - lastNode.position).normalized;
                        for (int n = 0; n < nodeConnectionCount; n++)
                        {
                            Node connectingNode = nodeConnections[n];
                            if (connectingNode == lastNode)
                            {
                                continue;                           //end this circus!
                            }
                            Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized;
                            float   nodeAngle     = SignAngleDirection(currentDirection, nextDirection);
                            if (nodeAngle < minAngle)
                            {
                                minAngle = nodeAngle;
                                nextNode = connectingNode;
                            }
                        }
                        if (nextNode != null)
                        {
                            edgeShape.Add(nextNode);
                            lastNode    = currentNode;
                            currentNode = nextNode;
                        }


                        itMax--;
                        if (itMax < 0)
                        {
                            break;
                        }
                    }

                    int edgeShapeCount = edgeShape.Count;

                    if (edgeShapeCount == 4 && generateDormers)
                    {
                        Vector3[] edgeShapeV3 = new Vector3[4];
                        edgeShapeV3[0] = new Vector3(edgeShape[0].position.x, roofBaseHeight, edgeShape[0].position.y);
                        edgeShapeV3[1] = new Vector3(edgeShape[3].position.x, roofBaseHeight, edgeShape[3].position.y);
                        edgeShapeV3[2] = new Vector3(edgeShape[1].position.x, roofBaseHeight + meshHeight, edgeShape[1].position.y);
                        edgeShapeV3[3] = new Vector3(edgeShape[2].position.x, roofBaseHeight + meshHeight, edgeShape[2].position.y);
                        roofFaces.Add(edgeShapeV3);
                    }

                    if ((isGabledLeft || isGabledRight) && edgeShapeCount == 4)//modify shape if gables are detected
                    {
                        Vector3 p0     = edgeShape[0].position;
                        Vector3 p1     = edgeShape[3].position;
                        Vector3 p2     = edgeShape[1].position;
                        Vector3 vector = p1 - p0;
                        Vector3 dir    = vector.normalized;
                        Vector3 cross  = Vector3.Cross(Vector3.back, dir);

                        if (isGabledLeft)
                        {
                            float gableThickness = volume[facadeIndexLeft].gableThickness;
                            bool  simpleGable    = volume[facadeIndexLeft].simpleGable;
                            Gable gableStyle     = volume[facadeIndexLeft].gableStyle;
                            if (!simpleGable && gableStyle == null || !isFloor)
                            {
                                gableThickness = 0;
                            }
                            Vector3 newPointA = Vector3.Project(p2 - p1, cross) + dir * gableThickness;
                            edgeShape[1].position = edgeShape[0].position + new Vector2(newPointA.x, newPointA.y);
                        }
                        if (isGabledRight)
                        {
                            float gableThickness = volume[facadeIndexRight].gableThickness;
                            bool  simpleGable    = volume[facadeIndexRight].simpleGable;
                            Gable gableStyle     = volume[facadeIndexRight].gableStyle;
                            if (!simpleGable && gableStyle == null || !isFloor)
                            {
                                gableThickness = 0;
                            }
                            Vector3 newPointB = Vector3.Project(p2 - p1, cross) - dir * gableThickness;
                            edgeShape[2].position = edgeShape[3].position + new Vector2(newPointB.x, newPointB.y);
                        }
                    }


                    Vector3[] verts = new Vector3[edgeShapeCount];

                    Vector2[] uvs = new Vector2[edgeShapeCount];
                    Vector3   baseShapeDirection = ToV3(nodeB.position - nodeA.position).normalized;
                    float     uvAngle            = SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90;

                    Vector2[] faceShape = new Vector2[edgeShapeCount];
                    Vector3[] normals   = new Vector3[edgeShapeCount];
                    Vector4[] tangents  = new Vector4[edgeShapeCount];
                    Vector4   tangent   = BuildRMesh.CalculateTangent(baseShapeDirection);
                    for (int i = 0; i < edgeShapeCount; i++)
                    {
                        Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y);
                        verts[i] = newVert;

                        Vector2 baseUV     = (i == 0) ? Vector2.zero : new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z);
                        Vector2 newUV      = Rotate(baseUV, uvAngle);
                        float   faceHeight = edgeShape[i].height * heightScale;
                        newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight));
                        if (surface != null)
                        {
                            newUV = surface.CalculateUV(newUV);
                        }
                        uvs[i] = newUV;

                        faceShape[i] = edgeShape[i].position;//used for triangulation
                        //                    normals[i] = normal;
                        tangents[i] = tangent;
                    }
//                    int[] tris = EarClipper.Triangulate(faceShape, 0, -1);
                    int[] tris     = Poly2TriWrapper.Triangulate(faceShape, true);
                    int   triCount = tris.Length;
                    if (triCount < 3)
                    {
                        continue;
                    }

                    Vector3 normal = BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]);
                    for (int i = 0; i < edgeShapeCount; i++)
                    {
                        normals[i] = normal;//normCal[i].normalized;
                    }
                    mesh.AddData(verts, uvs, tris, normals, tangents, submesh);

                    if (isGabled)
                    {
                        for (int t = 0; t < triCount; t += 3)
                        {
                            if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0)
                            {
                                int beB = edgeShapeCount - 1;
                                if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB)
                                {
                                    Vector3 b0       = verts[0];
                                    Vector3 b1       = verts[beB];
                                    int     topIndex = 0;
                                    for (int tx = 0; tx < 3; tx++)
                                    {
                                        if (tris[t + tx] != 0 && tris[t + tx] != beB)
                                        {
                                            topIndex = tris[t + tx];
                                        }
                                    }
                                    Vector3 b2 = verts[topIndex];

                                    Vector3 baseV = b1 - b0;
                                    Vector3 dir   = baseV.normalized;
                                    Vector3 face  = Vector3.Cross(Vector3.up, dir);
                                    //                                float length = baseV.magnitude;
                                    Vector3 center = Vector3.Lerp(b0, b1, 0.5f);
                                    Vector3 up     = Vector3.Project(b2 - b0, Vector3.up);
                                    Vector3 b3     = center + up;
                                    mesh.AddTri(b0, b2, b3, face, submesh);  //left
                                    mesh.AddTri(b1, b3, b2, -face, submesh); //right
                                    mesh.AddTri(b0, b3, b1, dir, submesh);   //face

                                    //clear triangle
                                    tris[t]     = 0;
                                    tris[t + 1] = 0;
                                    tris[t + 2] = 0;
                                }
                            }
                        }
                    }
                }
                else if (isFloor)
                {
                    Roof roof     = volume.roof;
                    Edge baseEdge = baseEdges[b];
                    Node nodeA    = baseEdge.nodeA;
                    Node nodeB    = baseEdge.nodeB;

                    Vector3 p0 = new Vector3(nodeA.position.x, heightScale + roofBaseHeight, nodeA.position.y);
                    Vector3 p1 = new Vector3(nodeB.position.x, heightScale + roofBaseHeight, nodeB.position.y);

                    Vector3 baseV = p1 - p0;
                    Vector3 dir   = baseV.normalized;
                    Vector3 face  = Vector3.Cross(Vector3.up, dir).normalized;

                    Vector3 parapetEdgeModifier = dir * (roof.overhang - (roof.parapetFrontDepth + roof.parapetBackDepth)) * 1.05f;
                    p0 += parapetEdgeModifier;
                    p1 += -parapetEdgeModifier;
//                    p0 += face * (roof.parapetFrontDepth + roof.parapetBackDepth + roof.overhang);

                    VolumePoint volumePoint = volume[facadeIndices[b]];
                    bool        simpleGable = volumePoint.simpleGable;
                    Gable       gableStyle  = volume[facadeIndices[b]].gableStyle;
                    if (!simpleGable && gableStyle == null)
                    {
                        simpleGable = true;
                    }
                    float thickness        = volume[facadeIndices[b]].gableThickness;
                    float additionalHeight = volume[facadeIndices[b]].gableHeight;
                    float height           = roof.height + additionalHeight;

                    if (simpleGable)                                                        //generate a simple gable
                    {
                        int wallSubmesh = mesh.submeshLibrary.SubmeshAdd(roof.wallSurface); //surfaceMapping.IndexOf(roof.wallSurface);
                        if (wallSubmesh == -1)
                        {
                            wallSubmesh = submesh;
                        }

                        Vector3 g0 = p0;
                        Vector3 g1 = p0 + Vector3.up * additionalHeight;
                        Vector3 g2 = g1 + dir * roof.floorDepth * 0.5f;
                        Vector3 g3 = g2 + dir * roof.depth * 0.5f + Vector3.up * roof.height;

                        Vector3 g7 = p1;
                        Vector3 g6 = p1 + Vector3.up * additionalHeight;
                        Vector3 g5 = g6 - dir * roof.floorDepth * 0.5f;
                        Vector3 g4 = g5 - dir * roof.depth * 0.5f + Vector3.up * roof.height;

                        Vector3 gF = -face * thickness;

                        mesh.AddPlane(g0, g7, g1, g6, wallSubmesh);                     //bottom front
                        mesh.AddPlane(g7 + gF, g0 + gF, g6 + gF, g1 + gF, wallSubmesh); //bottom back
                        mesh.AddPlane(g1, g6, g1 + gF, g6 + gF, wallSubmesh);           //bottom top
                        mesh.AddPlane(g0, g1, g0 + gF, g1 + gF, wallSubmesh);           //bottom sides
                        mesh.AddPlane(g6, g7, g6 + gF, g7 + gF, wallSubmesh);


                        mesh.AddPlane(g2, g5, g3, g4, wallSubmesh);                     //top front
                        mesh.AddPlane(g5 + gF, g2 + gF, g4 + gF, g3 + gF, wallSubmesh); //top back
                        mesh.AddPlane(g2 + gF, g2, g3 + gF, g3, wallSubmesh);           //top sides
                        mesh.AddPlane(g5, g5 + gF, g4, g4 + gF, wallSubmesh);           //top sides

                        mesh.AddPlane(g3 + gF, g3, g4 + gF, g4, wallSubmesh);           //top top
                    }
                    else
                    {
                        Vector2 baseUV = new Vector2(0, volume.planHeight);
                        GableGenerator.Generate(ref mesh, gableStyle, p0, p1, height, thickness, baseUV);
                    }
                }
            }

            if (generateDormers)
            {
                DormerGenerator.Generate(ref mesh, volume, roofFaces);
            }
        }
Esempio n. 11
0
        public static void Generate(IBuilding building, IVolume volume, IFloorplan floorplan, int volumeFloor, VerticalOpening[] openings, BuildRMesh mesh, BuildRCollider collider)
        {
            SubmeshLibrary submeshLibrary = mesh.submeshLibrary;

            bool           generateColliders     = building.colliderType != BuildingColliderTypes.None;
            bool           generateMeshColliders = building.colliderType != BuildingColliderTypes.Primitive && generateColliders;
            BuildRCollider sendCollider          = (generateColliders) ? collider : null;

            collider.thickness = volume.wallThickness;
            if (!generateMeshColliders)
            {
                collider = null;
            }

            float   wallThickness = volume.wallThickness;
            float   wallUp        = volume.floorHeight - wallThickness;
            Vector3 wallUpV       = Vector3.up * wallUp;
            Vector3 floorBaseV    = Vector3.up * volume.baseHeight;

            int roomCount = floorplan.RoomCount;

            int actualFloor  = building.VolumeBaseFloor(volume) + volumeFloor;
            int openingCount = openings.Length;

            bool[]       openingBelow           = new bool[openingCount];
            bool[]       openingAbove           = new bool[openingCount];
            FlatBounds[] openingBounds          = new FlatBounds[openingCount];
            Vector2[][]  openingShapes          = new Vector2[openingCount][];
            bool[]       openingUsedInThisFloor = new bool[openingCount];
            for (int o = 0; o < openingCount; o++)
            {
                VerticalOpening opening = openings[o];
                if (!openings[o].FloorIsIncluded(actualFloor))
                {
                    continue;
                }
                openingBelow[o]  = opening.FloorIsIncluded(actualFloor - 1);
                openingAbove[o]  = opening.FloorIsIncluded(actualFloor + 1);
                openingShapes[o] = opening.PointsRotated();
                openingBounds[o] = new FlatBounds(openingShapes[o]);

                submeshLibrary.Add(opening.surfaceA);
                submeshLibrary.Add(opening.surfaceB);
                submeshLibrary.Add(opening.surfaceC);
                submeshLibrary.Add(opening.surfaceD);
            }

            Dictionary <int, List <Vector2Int> > externalWallAnchors = volume.facadeWallAnchors;

            Room[] rooms = floorplan.AllRooms();
            for (int r = 0; r < roomCount; r++)
            {
                Room room       = rooms[r];
                int  pointCount = room.numberOfPoints;

                Surface floorSurface   = null;
                Surface wallSurface    = null;
                Surface ceilingSurface = null;

                if (room.style != null)
                {
                    RoomStyle style = room.style;
                    floorSurface   = style.floorSurface;
                    wallSurface    = style.wallSurface;
                    ceilingSurface = style.ceilingSurface;
                }

                int floorSubmesh   = submeshLibrary.SubmeshAdd(floorSurface);
                int wallSubmesh    = submeshLibrary.SubmeshAdd(wallSurface);
                int ceilingSubmesh = submeshLibrary.SubmeshAdd(ceilingSurface);

                FloorplanUtil.RoomWall[] walls = FloorplanUtil.CalculatePoints(room, volume);
                Vector2[] roomArchorPoints     = FloorplanUtil.RoomArchorPoints(walls);

                Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right);

                Vector2[] offsetRoomAnchorPoints = QuickPolyOffset.Execute(roomArchorPoints, wallThickness);

                FlatBounds             roomBounds   = new FlatBounds(offsetRoomAnchorPoints);
                List <Vector2[]>       floorCuts    = new List <Vector2[]>();
                List <Vector2[]>       ceilingCuts  = new List <Vector2[]>();
                List <VerticalOpening> roomOpenings = new List <VerticalOpening>();
                for (int o = 0; o < openingCount; o++)
                {
                    if (openings[o].FloorIsIncluded(actualFloor))
                    {
                        if (roomBounds.Overlaps(openingBounds[o]))
                        {
                            if (CheckShapeWithinRoom(offsetRoomAnchorPoints, openingShapes[o]))
                            {
                                if (openingBelow[o])
                                {
                                    floorCuts.Add(openingShapes[o]);
                                }
                                if (openingAbove[o])
                                {
                                    ceilingCuts.Add(openingShapes[o]);
                                }
                                if (openingAbove[o] || openingBelow[o])
                                {
                                    roomOpenings.Add(openings[o]);
                                    openingUsedInThisFloor[o] = true;
                                }
                            }
                        }
                    }
                }

                int offsetPointBase = 0;
                for (int p = 0; p < pointCount; p++)//generate room walls
                {
                    FloorplanUtil.RoomWall wall = walls[p];
                    int wallPointCount          = wall.offsetPoints.Length;

                    List <RoomPortal> wallPortals = floorplan.GetWallPortals(room, p);
                    int wallPortalCount           = wallPortals.Count;

                    if (!wall.isExternal)
                    {
                        int     indexA    = offsetPointBase;
                        int     indexB    = (offsetPointBase + 1) % roomArchorPoints.Length;
                        Vector2 origBaseA = roomArchorPoints[indexA];
                        Vector2 origBaseB = roomArchorPoints[indexB];
                        Vector2 baseA     = offsetRoomAnchorPoints[indexA];
                        Vector2 baseB     = offsetRoomAnchorPoints[indexB];
                        Vector3 v0        = new Vector3(origBaseA.x, 0, origBaseA.y) + floorBaseV;
                        Vector3 v1        = new Vector3(origBaseB.x, 0, origBaseB.y) + floorBaseV;
                        Vector3 vOffset0  = new Vector3(baseA.x, 0, baseA.y) + floorBaseV;
                        Vector3 vOffset1  = new Vector3(baseB.x, 0, baseB.y) + floorBaseV;
                        if (wallPortalCount == 0)  //just draw the wall - no portals to cut

                        {
                            Vector3 v2 = vOffset1 + wallUpV;
                            Vector3 v3 = vOffset0 + wallUpV;

                            Vector2 minUV = Vector2.zero;
                            Vector2 maxUV = new Vector2(Vector2.Distance(baseA, baseB), wallUp);
                            if (wallSurface != null)
                            {
                                maxUV = wallSurface.CalculateUV(maxUV);
                            }
                            Vector3 wallDir     = (vOffset0 - vOffset1).normalized;
                            Vector3 wallNormal  = Vector3.Cross(Vector3.up, wallDir);
                            Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir);
                            mesh.AddPlane(vOffset1, vOffset0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface);

                            if (generateColliders)
                            {
                                collider.AddPlane(vOffset1, vOffset0, v2, v3);
                            }
                        }
                        else
                        {
                            List <float> useLaterals = new List <float>();
                            List <bool>  hasPortals  = new List <bool>();
                            for (int wp = 0; wp < wallPortalCount; wp++)
                            {
                                RoomPortal portal    = wallPortals[wp];
                                bool       hasPortal = room.HasPortal(portal);
                                hasPortals.Add(hasPortal);
                                if (hasPortal)
                                {
                                    useLaterals.Add(portal.lateralPosition);
                                }
                                else
                                {
                                    useLaterals.Add(1 - portal.lateralPosition);//portal from other wall - wall orientation is flipped
                                }
                            }

                            Vector3 wallVector               = vOffset1 - vOffset0;
                            Vector3 wallDirection            = wallVector.normalized;
                            Vector3 wallStart                = vOffset0;
                            Vector4 wallTangent              = BuildRMesh.CalculateTangent(wallDirection);
                            Vector3 wallNormal               = Vector3.Cross(Vector3.up, wallDirection);
                            Vector4 wallNormalTangent        = BuildRMesh.CalculateTangent(wallNormal);
                            Vector4 wallNormalTangentReverse = BuildRMesh.CalculateTangent(-wallNormal);

                            while (wallPortalCount > 0)
                            {
                                int        portalIndex = 0;
                                RoomPortal usePortal   = wallPortals[0];
                                float      lowestLat   = useLaterals[0];
                                for (int wp = 1; wp < wallPortalCount; wp++)
                                {
                                    if (useLaterals[wp] < lowestLat)
                                    {
                                        portalIndex = wp;
                                        usePortal   = wallPortals[wp];
                                        lowestLat   = useLaterals[wp];
                                    }
                                }

                                wallPortals.RemoveAt(portalIndex);
                                useLaterals.RemoveAt(portalIndex);
                                wallPortalCount--;

                                Vector3 vl0 = v0 + (-wallNormal + wallDirection) * wallThickness;
                                Vector3 vl1 = v1 + (-wallNormal - wallDirection) * wallThickness;

                                Vector3 portalCenter     = Vector3.Lerp(vl0, vl1, lowestLat);
                                Vector3 portalHalfvector = wallDirection * (usePortal.width * 0.5f);
                                Vector3 portalBase       = Vector3.up * (volume.floorHeight - usePortal.height) * usePortal.verticalPosition;
                                Vector3 portalUp         = portalBase + Vector3.up * usePortal.height;
                                Vector3 portalStart      = portalCenter - portalHalfvector;
                                Vector3 portalEnd        = portalCenter + portalHalfvector;

                                Vector2 initalWallUVMin = new Vector2(Vector3.Dot(portalStart, wallDirection), 0);
                                Vector2 initalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp);
                                mesh.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV, initalWallUVMin, initalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//initial wall
                                if (generateColliders)
                                {
                                    collider.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV);
                                }
                                if (usePortal.verticalPosition > 0)
                                {
                                    Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), 0);
                                    Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), portalBase.y);
                                    mesh.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//bottom
                                    if (generateColliders)
                                    {
                                        collider.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase);
                                    }
                                }
                                if (usePortal.verticalPosition < 1)
                                {
                                    Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), portalUp.y);
                                    Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), wallUp);
                                    mesh.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//top
                                    if (generateColliders)
                                    {
                                        collider.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV);
                                    }
                                }

                                if (hasPortals[portalIndex])//only do this once - from the room it's attached to
                                {
                                    //portal interior frame
                                    Vector3 portalDepth = wallNormal * wallThickness * 2;

                                    //sides
                                    mesh.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp, wallDirection, wallNormalTangentReverse, wallSubmesh);
                                    mesh.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp, -wallDirection, wallNormalTangent, wallSubmesh);

                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp);
                                        collider.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp);
                                    }

                                    //floor
                                    Vector2 minFloorUv = new Vector2((portalEnd + portalBase).z, (portalEnd + portalBase).x);
                                    Vector2 maxFloorUv = minFloorUv + new Vector2(wallThickness, usePortal.width);
                                    mesh.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase, minFloorUv, maxFloorUv, Vector3.up, wallTangent, floorSubmesh, floorSurface);
                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase);
                                    }

                                    //ceiling
                                    mesh.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp, Vector3.down, wallTangent, wallSubmesh);
                                    if (generateMeshColliders)
                                    {
                                        collider.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp);
                                    }
                                }

                                wallStart = portalEnd;//move the start for the next calculation
                            }

                            Vector2 finalWallUVMin = new Vector2(Vector3.Dot(vOffset1, wallDirection), 0);
                            Vector2 finalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp);
                            mesh.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV, finalWallUVMin, finalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//final wall section
                            if (generateColliders)
                            {
                                collider.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV);
                            }
                        }
                        offsetPointBase += 1;
                    }
                    else//external anchored wall
                    {
                        int    facadeIndex  = wall.facadeIndex;
                        Facade facadeDesign = volume.GetFacade(facadeIndex);
                        int    currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count - 1;
                        int    currentWallSectionIndex        = wall.offsetPointWallSection[0];
                        int    wallOffsetPoints = wall.offsetPoints.Length;
                        for (int w = 0; w < wallOffsetPoints - 1; w++)
                        {
                            int     roomPointIndex   = offsetPointBase + w;
                            Vector2 baseA            = offsetRoomAnchorPoints[roomPointIndex];
                            int     offsetIndexB     = (roomPointIndex + 1) % offsetRoomAnchorPoints.Length;
                            Vector2 baseB            = offsetRoomAnchorPoints[offsetIndexB];
                            Vector3 v0               = new Vector3(baseA.x, 0, baseA.y) + floorBaseV;
                            Vector3 v1               = new Vector3(baseB.x, 0, baseB.y) + floorBaseV;
                            int     wallSectionIndex = wall.offsetPointWallSection[w];

                            bool canGenerateWallSection = facadeDesign != null;

                            Vector3 wallVector = v0 - v1;
                            Vector3 wallDir    = wallVector.normalized;
                            float   wallLength = wallVector.magnitude;

                            if (!canGenerateWallSection)
                            {
                                if (wallSurface != null)
                                {
                                    submeshLibrary.Add(wallSurface);
                                }

                                Vector3 v2 = v1 + wallUpV;
                                Vector3 v3 = v0 + wallUpV;

                                Vector2 minUV       = Vector2.zero;
                                Vector2 maxUV       = new Vector2(Vector2.Distance(baseA, baseB), wallUp);
                                Vector3 wallNormal  = Vector3.Cross(Vector3.up, wallDir);
                                Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir);
                                mesh.AddPlane(v1, v0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface);

                                if (generateMeshColliders)
                                {
                                    collider.AddPlane(v1, v0, v2, v3);
                                }
                            }
                            else
                            {
                                WallSection section = facadeDesign.GetWallSection(wallSectionIndex, volumeFloor, currentFacadeWallSectionLength, volume.floors);
                                if (section.model != null)
                                {
                                    continue;//cannot account for custom meshes assume custom mesh does include interior mesh or if does - will be generated with the exterior
                                }
                                GenerationOutput generatedSection = GenerationOutput.CreateRawOutput();
                                Vector2          wallSectionSize  = new Vector2(wallLength, wallUp + wallThickness);
                                bool             cullOpening      = building.cullDoors && section.isDoor;
                                SubmeshLibrary   sectionLib       = new SubmeshLibrary();

                                if (wallSurface != null)
                                {
                                    sectionLib.Add(wallSurface);//add interior wall surface
                                    submeshLibrary.Add(wallSurface);
                                }

                                sectionLib.Add(section.openingSurface);//add windows - the only surface we'll use in the interior room
                                submeshLibrary.Add(section.openingSurface);

                                float offset = 0;
                                if (w == 0)
                                {
                                    offset = wallThickness;
                                }
                                if (w == wallOffsetPoints - 2)
                                {
                                    offset = -wallThickness;
                                }
                                WallSectionGenerator.Generate(section, generatedSection, wallSectionSize, true, wallThickness, cullOpening, null, sectionLib, offset);
                                int[]   mapping     = submeshLibrary.MapSubmeshes(generatedSection.raw.materials);
                                Vector3 curveNormal = Vector3.Cross(wallDir, Vector3.up);

                                Quaternion meshRot = Quaternion.LookRotation(curveNormal, Vector3.up);
                                Vector3    meshPos = new Vector3(v1.x, volume.baseHeight, v1.z) + wallDir * wallSectionSize.x + Vector3.up * wallSectionSize.y;
                                meshPos += meshRot * -new Vector3(wallSectionSize.x, wallSectionSize.y, 0) * 0.5f;
                                mesh.AddData(generatedSection.raw, mapping, meshPos, meshRot, Vector3.one);
                            }


                            currentWallSectionIndex++;
                            if (currentWallSectionIndex >= currentFacadeWallSectionLength)
                            {
                                //reached the end of the facade - move to the next one and continue
                                currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count;
                                currentWallSectionIndex        = 0;
                            }
                        }

                        offsetPointBase += wallPointCount - 1;
                    }
                }

                //FLOOR
                Vector2[]   mainShape      = offsetRoomAnchorPoints;
                Vector2[][] floorCutPoints = floorCuts.ToArray();
                int         floorVertCount = mainShape.Length;
                for (int flc = 0; flc < floorCutPoints.Length; flc++)
                {
                    floorVertCount += floorCutPoints[flc].Length;
                }

                Vector2[] allFloorPoints  = new Vector2[floorVertCount];
                int       mainShapeLength = mainShape.Length;
                for (int ms = 0; ms < mainShapeLength; ms++)
                {
                    allFloorPoints[ms] = mainShape[ms];
                }
                int cutPointIterator = mainShapeLength;
                for (int flc = 0; flc < floorCutPoints.Length; flc++)
                {
                    for (int flcp = 0; flcp < floorCutPoints[flc].Length; flcp++)
                    {
                        allFloorPoints[cutPointIterator] = floorCutPoints[flc][flcp];
                        cutPointIterator++;
                    }
                }

                Vector3[] floorPoints   = new Vector3[floorVertCount];
                Vector2[] floorUvs      = new Vector2[floorVertCount];
                Vector3[] floorNorms    = new Vector3[floorVertCount];
                Vector4[] floorTangents = new Vector4[floorVertCount];
                for (int rp = 0; rp < floorVertCount; rp++)
                {
                    floorPoints[rp] = new Vector3(allFloorPoints[rp].x, 0, allFloorPoints[rp].y) + floorBaseV;
                    Vector2 uv = allFloorPoints[rp];
                    if (floorSurface != null)
                    {
                        uv = floorSurface.CalculateUV(uv);
                    }
                    floorUvs[rp]      = uv;
                    floorNorms[rp]    = Vector3.up;
                    floorTangents[rp] = tangent;
                }

                int[] tris = Poly2TriWrapper.Triangulate(mainShape, true, floorCutPoints);

                mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, floorSubmesh);
                if (generateColliders)
                {
                    collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0);
                }

                //CEILING!
                Vector2[][] ceilingCutPoints = ceilingCuts.ToArray();
                int         ceilingVertCount = mainShape.Length;
                for (int flc = 0; flc < ceilingCutPoints.Length; flc++)
                {
                    ceilingVertCount += ceilingCutPoints[flc].Length;
                }

                Vector2[] allCeilingPoints = new Vector2[ceilingVertCount];
                for (int ms = 0; ms < mainShapeLength; ms++)
                {
                    allCeilingPoints[ms] = mainShape[ms];
                }
                cutPointIterator = mainShapeLength;
                for (int flc = 0; flc < ceilingCutPoints.Length; flc++)
                {
                    for (int flcp = 0; flcp < ceilingCutPoints[flc].Length; flcp++)
                    {
                        allCeilingPoints[cutPointIterator] = ceilingCutPoints[flc][flcp];
                        cutPointIterator++;
                    }
                }

                Vector3[] ceilingPoints   = new Vector3[ceilingVertCount];
                Vector2[] ceilingUvs      = new Vector2[ceilingVertCount];
                Vector3[] ceilingNorms    = new Vector3[ceilingVertCount];
                Vector4[] ceilingTangents = new Vector4[ceilingVertCount];
                for (int rp = 0; rp < ceilingVertCount; rp++)
                {
                    ceilingPoints[rp] = new Vector3(allCeilingPoints[rp].x, wallUp, allCeilingPoints[rp].y) + floorBaseV;
                    Vector2 uv = allCeilingPoints[rp];
                    if (floorSurface != null)
                    {
                        uv = ceilingSurface.CalculateUV(uv);
                    }
                    ceilingUvs[rp]      = uv;
                    ceilingNorms[rp]    = Vector3.down;
                    ceilingTangents[rp] = tangent;
                }

                tris = Poly2TriWrapper.Triangulate(mainShape, false, ceilingCutPoints);
                mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, ceilingSubmesh);
                if (generateColliders)
                {
                    collider.mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, 0);
                }

                for (int ob = 0; ob < openingCount; ob++)
                {
                    VerticalOpening opening      = openings[ob];
                    int             openingIndex = Array.IndexOf(openings, opening);
                    Vector3         basePosition = openingBounds[openingIndex].center;
                    basePosition.z = basePosition.y;
                    basePosition.y = volume.baseHeight;

                    if (roomOpenings.Contains(opening))//opening used in this floorplan
                    {
                        int externalWallSubmesh = wallSubmesh != -1 ? wallSubmesh : -1;
                        switch (opening.usage)
                        {
                        case VerticalOpening.Usages.Space:
                            if (ceilingCutPoints.Length <= ob)
                            {
                                continue;
                            }
                            Vector3   ceilingCutUpV = Vector3.up * wallThickness;
                            Vector2[] ceilingCut    = ceilingCutPoints[ob];
                            int       custSize      = ceilingCut.Length;
                            for (int cp = 0; cp < custSize; cp++)
                            {
                                int     indexA = (cp + 1) % custSize;
                                int     indexB = cp;
                                Vector3 cp0    = new Vector3(ceilingCut[indexA].x, wallUp, ceilingCut[indexA].y) + floorBaseV;
                                Vector3 cp1    = new Vector3(ceilingCut[indexB].x, wallUp, ceilingCut[indexB].y) + floorBaseV;
                                Vector3 cp2    = cp0 + ceilingCutUpV;
                                Vector3 cp3    = cp1 + ceilingCutUpV;
                                mesh.AddPlane(cp0, cp1, cp2, cp3, ceilingSubmesh);
                                if (generateColliders)
                                {
                                    collider.AddPlane(cp0, cp1, cp2, cp3);
                                }
                            }
                            break;

                        case VerticalOpening.Usages.Stairwell:
                            StaircaseGenerator.Generate(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider);
                            if (volumeFloor == volume.floors - 1 && opening.baseFloor + opening.floors > building.VolumeBaseFloor(volume) + volume.floors - 1 && volume.abovePlanCount == 0)
                            {
                                StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider);
                            }
                            break;

                        case VerticalOpening.Usages.Elevator:
                            ElevatorShaftGenerator.Generate(ref mesh, opening, actualFloor, basePosition, volume.floorHeight, externalWallSubmesh, sendCollider);
                            break;
                        }
                    }
                }
            }

            for (int ob = 0; ob < openingCount; ob++)
            {
                Vector2[] openingShape = openingShapes[ob];
                if (openingShape == null)
                {
                    continue;                      //opening not used by this floorplan
                }
                if (openingUsedInThisFloor[ob])
                {
                    continue;                            //opening already generated
                }
                //seal this opening from the void
                VerticalOpening opening      = openings[ob];
                int             openingIndex = Array.IndexOf(openings, opening);
                Vector3         basePosition = openingBounds[openingIndex].center;
                basePosition.z = basePosition.y;
                basePosition.y = 0;

                int       cutSize            = openingShape.Length;
                Vector3   sealingWallUpV     = Vector3.up * volume.floorHeight;
                int       sealWallSubmesh    = submeshLibrary.SubmeshAdd(opening.surfaceB);
                Vector2[] offsetOpeningShape = QuickPolyOffset.Execute(openingShape, wallThickness);
                for (int cp = 0; cp < cutSize; cp++)
                {
                    int     indexA = (cp + 1) % cutSize;
                    int     indexB = cp;
                    Vector2 p0     = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexA] : offsetOpeningShape[indexA];
                    Vector2 p1     = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexB] : offsetOpeningShape[indexB];
                    Vector3 cp0    = new Vector3(p0.x, 0, p0.y) + floorBaseV;
                    Vector3 cp1    = new Vector3(p1.x, 0, p1.y) + floorBaseV;
                    Vector3 cp2    = cp0 + sealingWallUpV;
                    Vector3 cp3    = cp1 + sealingWallUpV;
                    mesh.AddPlane(cp0, cp1, cp2, cp3, sealWallSubmesh);
                    if (generateColliders)
                    {
                        collider.AddPlane(cp0, cp1, cp2, cp3);
                    }
                }

                switch (opening.usage)
                {
                case VerticalOpening.Usages.Space:
                    //nothing to implement
                    break;

                case VerticalOpening.Usages.Stairwell:
                    //need stairs to connect used floors
                    StaircaseGenerator.GenerateStairs(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider);
                    if (volumeFloor == volume.floors - 1)
                    {
                        StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider);
                    }
                    break;

                case VerticalOpening.Usages.Elevator:
                    //nothing to implement
                    break;
                }
            }
        }
Esempio n. 12
0
        public static void BMesh(BuildRMesh mesh, float height, Surface surface, int submesh, Vector2[] shape, Rect clampUV, bool flipTri = false, Vector2[][] holes = null, BuildRCollider collider = null)
        {
            int shapeSize = shape.Length;

            bool[] useHole = new bool[0];
            if (holes != null)
            {
                int holeCount = holes.Length;
//                Debug.Log("BMesh "+holeCount);
                useHole = new bool[holeCount];
                for (int flc = 0; flc < holeCount; flc++)
                {
                    useHole[flc] = true;
                    int holeSize = holes[flc].Length;

//                    for(int h = 0; h < holeSize; h++)
//                    {
//                        Vector2 holePoint = holes[flc][h];
//                        holeIntersections[h] = PointInShape(holePoint, shape);
////                        Debug.Log("intersection length " + intersections.Length);
//                        useHole[flc] = holeIntersections[h].Length == 0;
//                    }

                    //                    for(int flcp = 0; flcp < holeSize; flcp++)
                    //                    {
//                                            if(!PointInPolygon(holes[flc][flcp], shape))
                    //                        {
                    //                            useHole[flc] = false;
                    //                            break;
                    //                        }
                    //                    }
                    if (useHole[flc])
                    {
                        shapeSize += holeSize;
                    }
                }
            }

            Vector2[] allFloorPoints  = new Vector2[shapeSize];
            int       mainShapeLength = shape.Length;

            for (int ms = 0; ms < mainShapeLength; ms++)
            {
                allFloorPoints[ms] = shape[ms];
            }
            int cutPointIterator = mainShapeLength;

            if (holes != null)
            {
                for (int flc = 0; flc < holes.Length; flc++)
                {
                    if (!useHole[flc])
                    {
                        continue;
                    }
                    for (int flcp = 0; flcp < holes[flc].Length; flcp++)
                    {
                        allFloorPoints[cutPointIterator] = holes[flc][flcp];
                        cutPointIterator++;
                    }
                }
            }

            FlatBounds bounds = new FlatBounds();

            if (clampUV.width > 0)
            {
                for (int fvc = 0; fvc < mainShapeLength; fvc++)
                {
                    bounds.Encapsulate(shape[fvc]);
                }
            }

            Vector3[] floorPoints   = new Vector3[shapeSize];
            Vector2[] floorUvs      = new Vector2[shapeSize];
            Vector3[] floorNorms    = new Vector3[shapeSize];
            Vector4[] floorTangents = new Vector4[shapeSize];
            Vector3   normal        = flipTri ? Vector3.up : Vector3.down;
            Vector4   tangent       = BuildRMesh.CalculateTangent(Vector3.right);

            for (int rp = 0; rp < shapeSize; rp++)
            {
                floorPoints[rp] = new Vector3(allFloorPoints[rp].x, height, allFloorPoints[rp].y);
                if (clampUV.width > 0)
                {
                    Vector2 clampedUV = new Vector2();
                    clampedUV.x  = ((floorPoints[rp].x - bounds.xMin) / bounds.width) * clampUV.width + clampUV.x;
                    clampedUV.y  = ((floorPoints[rp].z - bounds.yMin) / bounds.height) * clampUV.height + clampUV.y;
                    floorUvs[rp] = clampedUV;
                }
                else
                {
                    if (surface != null)
                    {
                        floorUvs[rp] = surface.CalculateUV(allFloorPoints[rp]);
                    }
                    else
                    {
                        floorUvs[rp] = allFloorPoints[rp];
                    }
                }
                floorNorms[rp]    = normal;
                floorTangents[rp] = tangent;
            }

            int[] tris = Triangulate(shape, flipTri, holes);

            //                Debug.Log(volumeFloor + " " + actualFloor + " " + floorPoints.Length + " " + tris.Length+" "+r);
            int useFloorSubmesh = submesh != -1 ? submesh : 0;

            mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, useFloorSubmesh);
            if (collider != null)
            {
                collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0);
            }
        }
Esempio n. 13
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;
                }
            }
        }
Esempio n. 15
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;
            }
        }
Esempio n. 16
0
        private const float HPI = 1.570796f;//half PI
        private static void Arc(ref BuildRMesh mesh, Gable design, Vector3 sectorSize, Vector3 p0, Vector3 p1, Vector2 basePosition, int submesh, Surface surface, bool convex, Vector2 baseUV)
        {
            Vector3 facadeVector    = p1 - p0;
            Vector3 facadeDirection = facadeVector.normalized;
            float   facadeWidth     = facadeVector.magnitude;
            Vector3 facadeNormal    = Vector3.Cross(Vector3.up, facadeDirection);

            Vector4 facadeTangentForward = BuildRMesh.CalculateTangent(facadeDirection);
            Vector4 facadeTangentLeft    = BuildRMesh.CalculateTangent(facadeNormal);
            Vector4 facadeTangentRight   = BuildRMesh.CalculateTangent(-facadeNormal);
            Vector4 facadeTangentBack    = BuildRMesh.CalculateTangent(-facadeDirection);

            float sectionWidth  = sectorSize.x;
            float sectionHeight = sectorSize.y;
            float thickness     = sectorSize.z;

            var segmentCount = design.segments;
            var vertCount    = segmentCount * 8 + 4;
            var verts        = new Vector3[vertCount];
            var uvs          = new Vector2[vertCount];
            var normals      = new Vector3[vertCount];
            var tangents     = new Vector4[vertCount];
            int triPart      = 24;
            //+ 12 for central section (6 front, 6 back)
            int     triCount  = (segmentCount - 1) * triPart + 12;
            var     triangles = new int[triCount];
            Vector3 back      = -facadeNormal * thickness;

            float arcLength = HPI * Mathf.Sqrt(2 * Mathf.Pow(sectorSize.x, 2) + 2 * Mathf.Pow(sectorSize.y, 2)) / 2f;

            //front

            //left
            verts[0] = p0 + facadeDirection * (basePosition.x + sectionWidth) + Vector3.up * basePosition.y;
            Vector2 leftBaseUV = baseUV + new Vector2(basePosition.x + sectionWidth, basePosition.y);

            uvs[0] = surface != null?surface.CalculateUV(leftBaseUV) : new Vector2(0, 0);

            normals[0]  = facadeNormal;
            tangents[0] = facadeTangentForward;
            //right
            verts[1] = p1 - facadeDirection * (basePosition.x + sectionWidth) + Vector3.up * basePosition.y;
            Vector2 rightBaseUV = baseUV + new Vector2(basePosition.x + facadeWidth - basePosition.x * 2 - sectionWidth, basePosition.y);

            uvs[1] = surface != null?surface.CalculateUV(rightBaseUV) : new Vector2(1, 0);

            normals[1]  = facadeNormal;
            tangents[1] = facadeTangentForward;

            //back
            //left
            int endVertIndexLeft = vertCount - 2;

            verts[endVertIndexLeft]    = verts[0] + back;
            uvs[endVertIndexLeft]      = uvs[1];
            normals[endVertIndexLeft]  = -facadeNormal;
            tangents[endVertIndexLeft] = facadeTangentBack;
            //right
            int endVertIndexRight = vertCount - 1;

            verts[endVertIndexRight]    = verts[1] + back;
            uvs[endVertIndexRight]      = uvs[0];
            normals[endVertIndexRight]  = -facadeNormal;
            tangents[endVertIndexRight] = facadeTangentBack;

            for (int i = 0; i < segmentCount; i++)
            {
                float percent     = i / (segmentCount - 1f);
                float arcDistance = arcLength * percent;
                float arcPercent  = convex ? percent : (1 - percent) + 2;
                float x           = Mathf.Sin(arcPercent * HPI);
                float y           = Mathf.Cos(arcPercent * HPI);

                if (!convex)
                {
                    x = (x + 1);
                    y = (y + 1);
                }

                Vector3 arcLeft  = facadeDirection * (-x * sectionWidth) + Vector3.up * y * sectionHeight;
                Vector3 arcRight = facadeDirection * (x * sectionWidth) + Vector3.up * y * sectionHeight;
                Vector3 vertA    = verts[0] + arcLeft;
                Vector3 vertB    = vertA + back;
                Vector3 vertC    = verts[1] + arcRight;
                Vector3 vertD    = vertC + back;

                //left
                verts[i + 2] = vertA;                    //front
                verts[i + 2 + segmentCount]     = vertA; //front top
                verts[i + 2 + segmentCount * 2] = vertB; //back top
                verts[i + 2 + segmentCount * 3] = vertB; //back

                uvs[i + 2] = surface != null?surface.CalculateUV(leftBaseUV + new Vector2(-x *sectionWidth, y *sectionHeight)) : new Vector2(0, 0);

                uvs[i + 2 + segmentCount] = surface != null?surface.CalculateUV(new Vector2(thickness, arcDistance)) : new Vector2(1, 0);

                uvs[i + 2 + segmentCount * 2] = surface != null?surface.CalculateUV(new Vector2(0, arcDistance)) : new Vector2(0, 1);

                uvs[i + 2 + segmentCount * 3] = surface != null?surface.CalculateUV(rightBaseUV + new Vector2(x *sectionWidth, y *sectionHeight)) : new Vector2(1, 1);


                //right
                verts[i + 2 + segmentCount * 4] = vertC; //front
                verts[i + 2 + segmentCount * 5] = vertC; //front top
                verts[i + 2 + segmentCount * 6] = vertD; //back top
                verts[i + 2 + segmentCount * 7] = vertD; //back

                uvs[i + 2 + segmentCount * 4] = surface != null?surface.CalculateUV(rightBaseUV + new Vector2(x *sectionWidth, y *sectionHeight)) : new Vector2(0, 0);

                uvs[i + 2 + segmentCount * 5] = surface != null?surface.CalculateUV(new Vector2(0, arcDistance)) : new Vector2(1, 0);

                uvs[i + 2 + segmentCount * 6] = surface != null?surface.CalculateUV(new Vector2(thickness, arcDistance)) : new Vector2(0, 1);

                uvs[i + 2 + segmentCount * 7] = surface != null?surface.CalculateUV(leftBaseUV + new Vector2(-x *sectionWidth, y *sectionHeight)) : new Vector2(1, 1);

                if (i < segmentCount - 1)
                {
                    //left

                    //front
                    triangles[i * triPart]     = 0;
                    triangles[i * triPart + 1] = i + 3;
                    triangles[i * triPart + 2] = i + 2;

                    //top
                    triangles[i * triPart + 3] = i + segmentCount + 2;
                    triangles[i * triPart + 4] = i + segmentCount + 3;
                    triangles[i * triPart + 5] = i + segmentCount * 2 + 2;
                    triangles[i * triPart + 6] = i + segmentCount + 3;
                    triangles[i * triPart + 7] = i + segmentCount * 2 + 3;
                    triangles[i * triPart + 8] = i + segmentCount * 2 + 2;

                    //back
                    triangles[i * triPart + 9]  = endVertIndexLeft;
                    triangles[i * triPart + 10] = i + 2 + segmentCount * 3;
                    triangles[i * triPart + 11] = i + 3 + segmentCount * 3;

                    //right

                    //front
                    triangles[i * triPart + 12] = 1;
                    triangles[i * triPart + 13] = i + segmentCount * 4 + 2;
                    triangles[i * triPart + 14] = i + segmentCount * 4 + 3;

                    //top
                    triangles[i * triPart + 15] = i + segmentCount * 5 + 3;
                    triangles[i * triPart + 16] = i + segmentCount * 5 + 2;
                    triangles[i * triPart + 17] = i + segmentCount * 6 + 2;
                    triangles[i * triPart + 18] = i + segmentCount * 5 + 3;
                    triangles[i * triPart + 19] = i + segmentCount * 6 + 2;
                    triangles[i * triPart + 20] = i + segmentCount * 6 + 3;

                    //back
                    triangles[i * triPart + 21] = endVertIndexRight;
                    triangles[i * triPart + 22] = i + 3 + segmentCount * 7;
                    triangles[i * triPart + 23] = i + 2 + segmentCount * 7;
                }

                //left
                normals[i + 2]  = facadeNormal;
                tangents[i + 2] = facadeTangentForward;

                Vector3 upNormalLeft = Vector3.Slerp(-facadeDirection, Vector3.up, percent);

                normals[i + 2 + segmentCount]  = upNormalLeft;
                tangents[i + 2 + segmentCount] = facadeTangentLeft;

                normals[i + 2 + segmentCount * 2]  = upNormalLeft;
                tangents[i + 2 + segmentCount * 2] = facadeTangentLeft;

                normals[i + 2 + segmentCount * 3]  = -facadeNormal;
                tangents[i + 2 + segmentCount * 3] = facadeTangentBack;

                //right
                normals[i + 2 + segmentCount * 4]  = facadeNormal;
                tangents[i + 2 + segmentCount * 4] = facadeTangentForward;

                Vector3 upNormalRight = Vector3.Slerp(facadeDirection, Vector3.up, percent);

                normals[i + 2 + segmentCount * 5]  = upNormalRight;
                tangents[i + 2 + segmentCount * 5] = facadeTangentRight;

                normals[i + 2 + segmentCount * 6]  = upNormalRight;
                tangents[i + 2 + segmentCount * 6] = facadeTangentRight;

                normals[i + 2 + segmentCount * 7]  = -facadeNormal;
                tangents[i + 2 + segmentCount * 7] = facadeTangentBack;
            }

            //inter arc faces
            //front
            triangles[triCount - 12] = 1;
            triangles[triCount - 11] = 0;
            triangles[triCount - 10] = 2;
            triangles[triCount - 9]  = 1;
            triangles[triCount - 8]  = 2;
            triangles[triCount - 7]  = segmentCount * 4 + 2;
            //back
            triangles[triCount - 6] = endVertIndexLeft;
            triangles[triCount - 5] = endVertIndexRight;
            triangles[triCount - 4] = 2 + segmentCount * 3;
            triangles[triCount - 3] = 2 + segmentCount * 3;
            triangles[triCount - 2] = endVertIndexRight;
            triangles[triCount - 1] = segmentCount * 7 + 2;//1;


            mesh.AddData(verts, uvs, triangles, normals, tangents, submesh);
        }
Esempio n. 17
0
        public static void Generate(ref BuildRMesh mesh, Gable design, Vector3 p0, Vector3 p1, float height, float thickness, Vector2 baseUV)
        {
            int     gableSectionCount = design.count;
            Vector2 designSize        = new Vector2();

            for (int g = 0; g < gableSectionCount; g++)
            {
                designSize += design[g].GetSize();
            }
            Vector2 actualSize  = new Vector2(Vector3.Distance(p0, p1), height);
            Vector2 designScale = new Vector2((actualSize.x / 2) / designSize.x, actualSize.y / designSize.y);

            Vector2 basePosition    = Vector2.zero;
            Vector3 facadeVector    = p1 - p0;
            Vector3 facadeDirection = facadeVector.normalized;
            float   facadeWidth     = facadeVector.magnitude;
            Vector3 facadeNormal    = Vector3.Cross(Vector3.up, facadeDirection);

            Vector4 facadeTangentForward = BuildRMesh.CalculateTangent(facadeDirection);
            Vector4 facadeTangentLeft    = BuildRMesh.CalculateTangent(facadeNormal);
            Vector4 facadeTangentRight   = BuildRMesh.CalculateTangent(-facadeNormal);
            Vector4 facadeTangentBack    = BuildRMesh.CalculateTangent(-facadeDirection);

            Surface surface = design.surface;
            int     submesh = mesh.submeshLibrary.SubmeshAdd(surface);//surfaceMapping.IndexOf(surface);

            if (submesh == -1)
            {
                submesh = 0;
            }
            Vector3 back = -facadeNormal * thickness;

            for (int g = 0; g < gableSectionCount; g++)
            {
                float   sectionWidth = design[g].size.x * designScale.x;
                float   sectionHeight = design[g].size.y * designScale.y;
                Vector3 g0, g1, g2, g3;

                switch (design[g].type)
                {
                case GablePart.Types.Vertical:

                    g0 = p0 + facadeDirection * basePosition.x + Vector3.up * basePosition.y;
                    g1 = p1 - facadeDirection * basePosition.x + Vector3.up * basePosition.y;
                    g2 = g0 + Vector3.up * sectionHeight;
                    g3 = g1 + Vector3.up * sectionHeight;

                    Vector2 uvMax = baseUV + basePosition + new Vector2(facadeWidth - basePosition.x * 2, sectionHeight);
                    mesh.AddPlane(g0, g1, g2, g3, baseUV + basePosition, uvMax, facadeNormal, facadeTangentForward, submesh, surface);
                    Vector2 uvB0 = baseUV + basePosition + new Vector2(0, 0);
                    Vector2 uvB1 = baseUV + basePosition + new Vector2(facadeWidth - basePosition.x * 2, sectionHeight);
                    mesh.AddPlane(g1 + back, g0 + back, g3 + back, g2 + back, uvB0, uvB1, -facadeNormal, facadeTangentBack, submesh, surface);

                    var     gb0     = g0 + back;
                    var     gb1     = g1 + back;
                    var     gb2     = g2 + back;
                    var     gb3     = g3 + back;
                    Vector2 baseVUV = new Vector2(0, basePosition.y);
                    mesh.AddPlane(gb0, g0, gb2, g2, baseVUV, new Vector2(thickness, basePosition.y + sectionHeight), -facadeDirection, facadeTangentLeft, submesh, surface);
                    mesh.AddPlane(g1, gb1, g3, gb3, baseVUV, new Vector2(thickness, basePosition.y + sectionHeight), facadeDirection, facadeTangentRight, submesh, surface);

                    basePosition.y += sectionHeight;
                    break;

                case GablePart.Types.Horizonal:

                    g0 = p0 + facadeDirection * basePosition.x + Vector3.up * basePosition.y;
                    g1 = p1 - facadeDirection * basePosition.x + Vector3.up * basePosition.y;
                    g2 = g0 + facadeDirection * sectionWidth;
                    g3 = g1 - facadeDirection * sectionWidth;

                    Vector4 tangent = BuildRMesh.CalculateTangent(facadeDirection);
                    mesh.AddPlane(g0, g2, g0 + back, g2 + back, Vector3.zero, new Vector2(sectionWidth, thickness), Vector3.up, tangent, submesh, surface);
                    mesh.AddPlane(g3, g1, g3 + back, g1 + back, Vector3.zero, new Vector2(sectionWidth, thickness), Vector3.up, tangent, submesh, surface);

                    basePosition.x += sectionWidth;
                    break;

                case GablePart.Types.Diagonal:

                    Vector3 gd0 = p0 + facadeDirection * basePosition.x + Vector3.up * basePosition.y;
                    Vector3 gd1 = p1 - facadeDirection * basePosition.x + Vector3.up * basePosition.y;
                    Vector3 gd2 = gd0 + facadeDirection * sectionWidth + Vector3.up * sectionHeight;
                    Vector3 gd3 = gd1 - facadeDirection * sectionWidth + Vector3.up * sectionHeight;

                    Vector3 gdb0 = gd0 + back;
                    Vector3 gdb1 = gd1 + back;
                    Vector3 gdb2 = gd2 + back;
                    Vector3 gdb3 = gd3 + back;

                    Vector2 uv0 = baseUV + basePosition;
                    Vector2 uv1 = baseUV + new Vector2(basePosition.x + facadeWidth - basePosition.x * 2, basePosition.y);
                    Vector2 uv2 = baseUV + new Vector2(basePosition.x + sectionWidth, basePosition.y + sectionHeight);
                    Vector2 uv3 = baseUV + new Vector2(basePosition.x + facadeWidth - basePosition.x * 2 - sectionWidth, basePosition.y + sectionHeight);
                    mesh.AddPlaneComplex(gd0, gd1, gd2, gd3, uv0, uv1, uv2, uv3, facadeNormal, facadeTangentForward, submesh, surface);    //face
                    mesh.AddPlaneComplex(gdb1, gdb0, gdb3, gdb2, uv0, uv1, uv2, uv3, -facadeNormal, facadeTangentBack, submesh, surface);  //face

                    Vector3   leftNorm     = Vector3.Cross(-facadeNormal, (gd2 - gd0).normalized);
                    Vector3[] leftNorms    = { leftNorm, leftNorm, leftNorm, leftNorm };
                    Vector4   leftTangent  = facadeTangentLeft;
                    Vector4[] leftTangents = { leftTangent, leftTangent, leftTangent, leftTangent };

                    Vector3[] leftFace  = { gdb0, gd0, gdb2, gd2 };
                    float     faceWidth = Vector3.Distance(gd0, gd2);
                    Vector2   sideUV0   = Vector2.zero;
                    Vector2   sideUV1   = surface != null?surface.CalculateUV(new Vector2(thickness, 0)) : new Vector2(1, 0);

                    Vector2 sideUV2 = surface != null?surface.CalculateUV(new Vector2(0, faceWidth)) : new Vector2(0, 1);

                    Vector2 sideUV3 = surface != null?surface.CalculateUV(new Vector2(thickness, faceWidth)) : new Vector2(1, 1);

                    Vector2[] leftFaceUV = { sideUV0, sideUV1, sideUV2, sideUV3 };
                    mesh.AddData(leftFace, leftFaceUV, new[] { 0, 2, 1, 2, 3, 1 }, leftNorms, leftTangents, submesh);

                    Vector3   rightNorm     = Vector3.Cross(-facadeNormal, (gd1 - gd3).normalized);
                    Vector3[] rightNorms    = { rightNorm, rightNorm, rightNorm, rightNorm };
                    Vector4   rightTangent  = facadeTangentRight;
                    Vector4[] rightTangents = { rightTangent, rightTangent, rightTangent, rightTangent };

                    Vector3[] rightFace   = { gd1, gdb1, gd3, gdb3 };
                    Vector2[] rightFaceUV = { sideUV0, sideUV1, sideUV2, sideUV3 };    //todo
                    mesh.AddData(rightFace, rightFaceUV, new[] { 0, 2, 1, 2, 3, 1 }, rightNorms, rightTangents, submesh);

                    basePosition.x += sectionWidth;
                    basePosition.y += sectionHeight;
                    break;

                case GablePart.Types.Concave:

                    Arc(ref mesh, design, new Vector3(sectionWidth, sectionHeight, thickness), p0, p1, basePosition, submesh, surface, false, baseUV);

                    basePosition.x += sectionWidth;
                    basePosition.y += sectionHeight;
                    break;

                case GablePart.Types.Convex:

                    Arc(ref mesh, design, new Vector3(sectionWidth, sectionHeight, thickness), p0, p1, basePosition, submesh, surface, true, baseUV);

                    basePosition.x += sectionWidth;
                    basePosition.y += sectionHeight;
                    break;
                }
            }
        }
Esempio n. 18
0
        private static void ToMesh(ref BuildRMesh mesh, Shape shape, bool[] gabled, float roofBaseHeight, float meshHeight, int submesh, Surface surface)
        {
            List <Edge> edges     = new List <Edge>(shape.edges);
            List <Edge> baseEdges = new List <Edge>(shape.baseEdges);

            float shapeHeight  = shape.HeighestPoint();
            float designHeight = meshHeight;
            float heightScale  = designHeight / shapeHeight;

            Dictionary <Node, int>          shapeConnectionCount = new Dictionary <Node, int>();
            Dictionary <Node, List <Node> > shapeConnections     = new Dictionary <Node, List <Node> >();
            int edgeCount = edges.Count;

            for (int e = 0; e < edgeCount; e++)
            {
                Edge edge = edges[e];


                //                                                Node nodeA = edge.nodeA;
                //                                                Node nodeB = edge.nodeB;
                //                                                Vector3 na = new Vector3(nodeA.position.x, roofBaseHeight * 1.5f, nodeA.position.y);
                //                                                Vector3 nb = new Vector3(nodeB.position.x, roofBaseHeight * 1.5f, nodeB.position.y);
                //                                                Debug.DrawLine(na, nb, Color.blue);

                if (edge.length < Mathf.Epsilon)
                {
                    continue;
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeA))
                {
                    shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeA, new List <Node> {
                        edge.nodeB
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeA]++;
                    if (!shapeConnections[edge.nodeA].Contains(edge.nodeB))
                    {
                        shapeConnections[edge.nodeA].Add(edge.nodeB);
                    }
                }

                if (!shapeConnectionCount.ContainsKey(edge.nodeB))
                {
                    shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape...
                    shapeConnections.Add(edge.nodeB, new List <Node> {
                        edge.nodeA
                    });
                }
                else
                {
                    shapeConnectionCount[edge.nodeB]++;
                    if (!shapeConnections[edge.nodeB].Contains(edge.nodeA))
                    {
                        shapeConnections[edge.nodeB].Add(edge.nodeA);
                    }
                }


                //                Vector3 na = new Vector3(edge.nodeA.position.x + 75, roofBaseHeight * 2 + edge.nodeA.height, edge.nodeA.position.y);
                //                Vector3 nb = new Vector3(edge.nodeB.position.x + 75, roofBaseHeight * 2 + edge.nodeB.height, edge.nodeB.position.y);
                //                Debug.DrawLine(na, nb, new Color(1,0,1,0.24f));
                //
                //                GizmoLabel.Label(edge.nodeA.ToString(), na);
                //                GizmoLabel.Label(edge.nodeB.ToString(), nb);
            }

            int baseEdgeCount = baseEdges.Count;

            for (int b = 0; b < baseEdgeCount; b++)
            {
                Edge baseEdge = baseEdges[b];
                Node nodeA    = baseEdge.nodeA;
                Node nodeB    = baseEdge.nodeB;
                //                Color col = new Color(Random.value, Random.value, Random.value, 0.5f);
                //                Vector3 na = new Vector3(nodeA.position.x + 75, roofBaseHeight * 2, nodeA.position.y);
                //                Vector3 nb = new Vector3(nodeB.position.x + 75, roofBaseHeight * 2, nodeB.position.y);
                //                Debug.DrawLine(na, nb, col);//base edge

                Node        currentNode = nodeA;
                Node        lastNode    = nodeB;
                int         itMax       = 50;
                List <Node> edgeShape   = new List <Node>()
                {
                    nodeA
                };

                while (currentNode != nodeB)
                {
                    List <Node> nodeConnections     = shapeConnections[currentNode];
                    int         nodeConnectionCount = nodeConnections.Count;
                    float       minAngle            = Mathf.Infinity;
                    Node        nextNode            = null;
                    Vector2     currentDirection    = (currentNode.position - lastNode.position).normalized;
                    for (int n = 0; n < nodeConnectionCount; n++)
                    {
                        Node connectingNode = nodeConnections[n];
                        if (connectingNode == lastNode)
                        {
                            continue;
                        }
                        Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized;
                        float   nodeAngle     = JMath.SignAngleDirection(currentDirection, nextDirection);
                        if (nodeAngle < minAngle)
                        {
                            minAngle = nodeAngle;
                            nextNode = connectingNode;
                        }
                    }
                    if (nextNode != null)
                    {
                        edgeShape.Add(nextNode);
                        lastNode    = currentNode;
                        currentNode = nextNode;
                    }


                    itMax--;
                    if (itMax < 0)
                    {
                        break;
                    }
                    //                    if(edgeShape.Count == 3) break;
                }

                int edgeShapeCount = edgeShape.Count;

                Vector3[] verts = new Vector3[edgeShapeCount];

                Vector2[] uvs = new Vector2[edgeShapeCount];
                Vector3   baseShapeDirection = Utils.ToV3(nodeB.position - nodeA.position).normalized;
                float     uvAngle            = JMath.SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90;

                Vector2[] faceShape = new Vector2[edgeShapeCount];
                Vector3[] normals   = new Vector3[edgeShapeCount];
                Vector4[] tangents  = new Vector4[edgeShapeCount];
//                Vector3 normal = Vector3.up;//BuildRMesh.CalculateNormal(); TODO
                Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection);
                for (int i = 0; i < edgeShapeCount; i++)
                {
                    float   testHAdd = 0;//5 + b;
                    Vector3 newVert  = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight + testHAdd, edgeShape[i].position.y);
                    verts[i] = newVert;

                    Vector2 baseUV     = (i == 0) ? Vector2.zero : new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z);
                    Vector2 newUV      = JMath.Rotate(baseUV, uvAngle);
                    float   faceHeight = edgeShape[i].height * heightScale;
                    newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight));
                    if (surface != null)
                    {
                        newUV = surface.CalculateUV(newUV);
                    }
                    uvs[i] = newUV;

                    faceShape[i] = edgeShape[i].position;//used for triangulation
//                    normals[i] = normal;
                    tangents[i] = tangent;
                }
//                int[] tris = EarClipper.Triangulate(faceShape, 0, -1);
                int[] tris     = Poly2TriWrapper.Triangulate(faceShape);
                int   triCount = tris.Length;

                Vector3 normal = BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]);
//                Vector3[] normCal = new Vector3[edgeShapeCount];
//                for (int t = 0; t < triCount; t += 3)
//                {
//                    int[] triIndicies = {tris[t], tris[t + 1], tris[t + 2]};
//                    Vector3 newNormal = BuildRMesh.CalculateNormal(verts[triIndicies[0]], verts[triIndicies[1]], verts[triIndicies[2]]);
//                    for(int i = 0; i < 3; i++)
//                        normCal[triIndicies[i]] = newNormal;
//                }
                for (int i = 0; i < edgeShapeCount; i++)
                {
                    normals[i] = normal;//normCal[i].normalized;
                }
                mesh.AddData(verts, uvs, tris, normals, tangents, submesh);


                if (gabled[b])
                {
                    for (int t = 0; t < triCount; t += 3)
                    {
                        if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0)
                        {
                            int beB = edgeShapeCount - 1;
                            if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB)
                            {
                                Vector3 b0       = verts[0];
                                Vector3 b1       = verts[beB];
                                int     topIndex = 0;
                                for (int tx = 0; tx < 3; tx++)
                                {
                                    if (tris[t + tx] != 0 && tris[t + tx] != beB)
                                    {
                                        topIndex = tris[t + tx];
                                    }
                                }
                                Vector3 b2 = verts[topIndex];

                                Vector3 baseV = b1 - b0;
                                Vector3 dir   = baseV.normalized;
                                Vector3 face  = Vector3.Cross(Vector3.up, dir);
                                //                                float length = baseV.magnitude;
                                Vector3 center = Vector3.Lerp(b0, b1, 0.5f);
                                Vector3 up     = Vector3.Project(b2 - b0, Vector3.up);
                                Vector3 b3     = center + up;
                                mesh.AddTri(b0, b2, b3, face, submesh);  //left
                                mesh.AddTri(b1, b3, b2, -face, submesh); //right
                                mesh.AddTri(b0, b3, b1, dir, submesh);   //face

                                //clear triangle
                                tris[t]     = 0;
                                tris[t + 1] = 0;
                                tris[t + 2] = 0;
                            }
                        }
                    }
                }

                //                                for (int i = 0; i < edgeShapeCount; i++)
                //                                {
                //                                    Node nodeAS = edgeShape[i];
                //                                    Node nodeBS = edgeShape[(i + 1) % edgeShapeCount];
                //                                    Vector3 nas = new Vector3(nodeAS.position.x + 75, roofBaseHeight * 5 + b, nodeAS.position.y);
                //                                    Vector3 nbs = new Vector3(nodeBS.position.x + 75, roofBaseHeight * 5 + b, nodeBS.position.y);
                //                                    Debug.DrawLine(nas, nbs + Vector3.up, col);//Color.yellow);
                //                                }
            }

            //Assumption - each based edge is a single shape
            //There are no shapes without a base edge
            //Enumerate through the base edges
            //Build the shape
            //use angle to find shape clockwise or something
            //triangulate the shape and add to mesh
            //node data will provide height information
            //???
            //profit



            //            int itMax = 5000;
            //            while(unmappedNodes.Count > 0)
            //            {
            //                Node currentNode = unmappedNodes[0];
            //                unmappedNodes.RemoveAt(0);
            //
            //
            //                itMax--;
            //                if(itMax < 0)
            //                    return;
            //            }
        }