Exemple #1
0
        private static void Pitched(BuildRMesh mesh, Vector3[] points, Roof design, int submesh)
        {
            int numberOfVolumePoints = points.Length;

            Vector2[] volumePoints = new Vector2[numberOfVolumePoints];
            for (int i = 0; i < numberOfVolumePoints; i++)
            {
                volumePoints[i] = new Vector2(points[i].x, points[i].z);
            }

            OffsetSkeleton offsetPoly = new OffsetSkeleton(volumePoints);

            offsetPoly.Execute();
        }
Exemple #2
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);
        }
Exemple #3
0
        public static void OnInspectorGUI(Building _building)
        {
            EditorGUILayout.BeginVertical(GUILayout.Width(BuildingEditor.MAIN_GUI_WIDTH));

            Volume volume = BuildingVolumeEditor.VolumeSelectorInspectorGUI(_building);

            if (volume != null)
            {
                BuildingEditor.volume = volume;
            }
            else
            {
                volume = BuildingEditor.volume;
            }

            if (volume != null)
            {
                Undo.RecordObject(BuildingEditor.volume, "Roof Modification");
                Roof roof = volume.roof;

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Enable");
                roof.exists = EditorGUILayout.Toggle(roof.exists);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Open Interior");
                roof.interiorOpen = EditorGUILayout.Toggle(roof.interiorOpen);
                EditorGUILayout.EndHorizontal();

//                EditorGUI.BeginDisabledGroup(BuildingEditor.volume.abovePlans.Count > 0);
//                if (BuildingEditor.volume.abovePlans.Count > 0)
//                    roof.type = Roof.Types.Flat;
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Type");
                roof.type = (Roof.Types)EditorGUILayout.EnumPopup(roof.type);
                EditorGUILayout.EndHorizontal();
//                EditorGUI.EndDisabledGroup();

                if (roof.type != Roof.Types.Flat)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Height");
                    roof.height = EditorGUILayout.Slider(roof.height, 0, 20);//TODO setting for max building roof height
                    EditorGUILayout.EndHorizontal();
                }

//                if (roof.type == Roof.Types.Gambrel)
//                {
//                    EditorGUILayout.BeginHorizontal();
//                    EditorGUILayout.LabelField("Sub Height");
//                    roof.heightB = EditorGUILayout.Slider(roof.heightB, 0, 20);//TODO setting for max building roof height
//                    EditorGUILayout.EndHorizontal();
//                }

                if (roof.type == Roof.Types.Mansard)//|| roof.type == Roof.Types.Gambrel)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Depth");
                    roof.depth = EditorGUILayout.Slider(roof.depth, 0, 5);
                    EditorGUILayout.EndHorizontal();
                }

                if (roof.type == Roof.Types.Mansard)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Floor Depth");
                    roof.floorDepth = EditorGUILayout.Slider(roof.floorDepth, 0, 5);
                    EditorGUILayout.EndHorizontal();
                }

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Overhang");
                roof.overhang = EditorGUILayout.Slider(roof.overhang, 0, 5);
                EditorGUILayout.EndHorizontal();

                //                EditorGUILayout.BeginHorizontal();
                //two directions of the ridge
                //                string[] options = { "Short", "Long" };
                //                roof.direction = EditorGUILayout.Popup(roof.direction, options);
                //                EditorGUILayout.EndHorizontal();

//                if (roof.type == Roof.Types.Sawtooth)
//                {
//                    EditorGUILayout.BeginHorizontal();
//                    EditorGUILayout.LabelField("Overhang");
//                    roof.sawtoothTeeth = EditorGUILayout.IntSlider(roof.sawtoothTeeth, 0, 10);
//                    EditorGUILayout.EndHorizontal();
//                }

//                if (roof.type == Roof.Types.Barrel)
//                {
//                    EditorGUILayout.BeginHorizontal();
//                    EditorGUILayout.LabelField("Segments");
//                    roof.barrelSegments = EditorGUILayout.IntSlider(roof.barrelSegments, 0, 10);
//                    EditorGUILayout.EndHorizontal();
//                }

                EditorGUILayout.BeginVertical("box");
                EditorGUILayout.LabelField("Textures");

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Main");
                roof.mainSurface = EditorGUILayout.ObjectField(roof.mainSurface, typeof(Surface), false) as Surface;
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Wall");
                roof.wallSurface = EditorGUILayout.ObjectField(roof.wallSurface, typeof(Surface), false) as Surface;
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Floor");
                roof.floorSurface = EditorGUILayout.ObjectField(roof.floorSurface, typeof(Surface), false) as Surface;
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.EndVertical();

                EditorGUILayout.BeginVertical("box");
                EditorGUILayout.LabelField("Parapet");

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Enabled");
                roof.parapet = EditorGUILayout.Toggle(roof.parapet);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Type");
                roof.parapetStyle = (Roof.ParapetStyles)EditorGUILayout.EnumPopup(roof.parapetStyle);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Height");
                roof.parapetHeight = EditorGUILayout.Slider(roof.parapetHeight, 0.01f, 3);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Front Extrusion");
                roof.parapetFrontDepth = EditorGUILayout.Slider(roof.parapetFrontDepth, 0.01f, 1);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Back Extrusion");
                roof.parapetBackDepth = EditorGUILayout.Slider(roof.parapetBackDepth, 0.01f, 1);
                EditorGUILayout.EndHorizontal();

                if (roof.parapetStyle == Roof.ParapetStyles.Battlement)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Battlement Height Ratio");
                    roof.battlementHeightRatio = EditorGUILayout.Slider(roof.battlementHeightRatio, 0.01f, 1);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Battlement Spacing");
                    roof.battlementSpacing = EditorGUILayout.Slider(roof.battlementSpacing, 0.5f, 5);
                    EditorGUILayout.EndHorizontal();
                }
                EditorGUILayout.EndVertical();

                //DORMERS
                EditorGUILayout.BeginVertical("box");
                EditorGUILayout.LabelField("Dormer");

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Enabled");
                roof.hasDormers = EditorGUILayout.Toggle(roof.hasDormers);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Width");
                roof.dormerWidth = EditorGUILayout.Slider(roof.dormerWidth, 0, 4);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Height");
                roof.dormerHeight = EditorGUILayout.Slider(roof.dormerHeight, 0, 3);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Roof Height");
                roof.dormerRoofHeight = EditorGUILayout.Slider(roof.dormerRoofHeight, 0, 3);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Spacing");
                roof.minimumDormerSpacing = EditorGUILayout.Slider(roof.minimumDormerSpacing, 0, 5);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Rows");
                roof.dormerRows = EditorGUILayout.IntSlider(roof.dormerRows, 1, 4);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField("Style");
                roof.wallSection = (WallSection)EditorGUILayout.ObjectField(roof.wallSection, typeof(WallSection), false);
                EditorGUILayout.EndHorizontal();

                if (roof.wallSection != null)
                {
                    GUILayout.Label(roof.wallSection.previewTexture);
                }

                EditorGUILayout.EndVertical();


                EditorGUILayout.BeginVertical("box");
                EditorGUILayout.LabelField("Gables");

                for (int g = 0; g < volume.numberOfPoints; g++)
                {
                    if (g > 0)
                    {
                        EditorGUILayout.Space();
                    }
                    RoofFacadeInspectorGUI(volume, g);
                }

                EditorGUILayout.EndVertical();

                BuildingEditor.volume.roof = roof;


                if (BuildingEditor.volume != null && BuildingEditor.volume.isModified)
                {
                    _building.MarkModified();
                }

                if (_building.isModified || GUI.changed)
                {
                    Repaint();
                }
            }
            EditorGUILayout.EndVertical();
        }
        //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);
                    }
                }
            }
        }
Exemple #5
0
        private static void Flat(IBuilding building, IVolume volume, BuildRMesh mesh, BuildRCollider collider, Vector2[] points, float roofBaseHeight, Roof design, int submesh, Surface surface, Rect clampUV)
        {
            BuildRVolumeUtil.VolumeShape[] roofPoints = BuildRVolumeUtil.GetTopShape(building, volume, points);
            int roofShapeCount = roofPoints.Length;

            for (int r = 0; r < roofShapeCount; r++)
            {
                Poly2TriWrapper.BMesh(mesh, roofBaseHeight, surface, submesh, roofPoints[r].outer, clampUV, true, roofPoints[r].holes, collider);
            }
        }
Exemple #6
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;
            }
        }
Exemple #7
0
        public static bool Generate(BuildRMesh mesh, BuildRCollider collider, Vector2[] points, int[] facadeIndices, float roofBaseHeight, IVolume volume)
        {
            if (points.Length == 0)
            {
                return(false);
            }

            if (BuildrUtils.SelfIntersectingPoly(points))
            {
                return(false);
            }

            Roof  design     = volume.roof;
            float floorWidth = design.floorDepth;
            float roofDepth  = design.depth;
            float roofHeight = design.height;

            Surface mainSurface  = design.mainSurface;
            Surface floorSurface = design.floorSurface;
            int     mainSubmesh  = mesh.submeshLibrary.SubmeshAdd(mainSurface);
            int     floorSubmesh = mesh.submeshLibrary.SubmeshAdd(floorSurface);

            //mansard floor
            if (floorWidth > 0)
            {
                OffsetSkeleton offsetFloorPoly = new OffsetSkeleton(points, null, floorWidth);
                offsetFloorPoly.direction = 1;
                offsetFloorPoly.Execute();
                Shape floorShape = offsetFloorPoly.shape;

                if (floorShape != null)
                {
                    ToMesh(ref mesh, ref floorShape, roofBaseHeight, 0, facadeIndices, volume, floorSubmesh, design.floorSurface);

                    points = new Vector2[floorShape.terminatedNodeCount];
                    for (int i = 0; i < floorShape.terminatedNodeCount; i++)
                    {
                        points[i] = floorShape.TerminatedNode(i).position;
                    }
                }
                else
                {
                    return(false);
                    //todo
                }
            }

            if (points.Length == 0)
            {
                return(false);
            }

            //mansard pitch
            OffsetSkeleton offsetRoofPoly = new OffsetSkeleton(points, null, roofDepth);

            offsetRoofPoly.direction = 1;
            offsetRoofPoly.Execute();
            Shape roofShape = offsetRoofPoly.shape;

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

            if (facadeIndices.Length < roofShape.baseEdges.Count)
            {
                return(false);
            }

            ToMesh(ref mesh, ref roofShape, roofBaseHeight, roofHeight, facadeIndices, volume, mainSubmesh, mainSurface, design.hasDormers);

            points = new Vector2[roofShape.terminatedNodeCount];
            for (int i = 0; i < roofShape.terminatedNodeCount; i++)
            {
                points[i] = roofShape.TerminatedNode(i).position;
            }

            //mansard top
            ToMesh(ref mesh, points, roofBaseHeight + roofHeight, facadeIndices, volume, floorSubmesh, floorSurface);

            return(true);
        }
Exemple #8
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);
            }
        }