예제 #1
0
    private static void AddData(Vector3[] verts, Vector2[] uvs, int[] tris, int subMesh, bool flipped)
    {
        int           textureSubmesh = subMesh;
        BuildrTexture texture        = textures[textureSubmesh];
        Vector2       uvScale        = Vector2.one;

        if (texture.tiled)
        {
            uvScale.x = (1.0f / texture.textureUnitSize.x);
            uvScale.y = (1.0f / texture.textureUnitSize.y);
            if (texture.patterned)
            {
                Vector2 uvunits = texture.tileUnitUV;
                uvScale.x = Mathf.Max(Mathf.Floor(uvScale.x / uvunits.x), 0) * uvunits.x;
                uvScale.y = Mathf.Max(Mathf.Floor(uvScale.y / uvunits.y), 0) * uvunits.y;
            }
        }

        int numberOfUVs = uvs.Length;

        for (int i = 0; i < numberOfUVs; i++)
        {
            uvs[i].Scale(uvScale);
            if (flipped)
            {
                Vector2 flippedUV = new Vector2(uvs[i].y, uvs[i].x);
                uvs[i] = flippedUV;
            }
        }

        mesh.AddData(verts, uvs, tris, textureSubmesh);
    }
예제 #2
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
//        timestart = Time.realtimeSinceStartup;
        data     = _data;
        mesh     = _mesh;
        textures = data.textures.ToArray();
        BuildrPlan plan = data.plan;

        int facadeIndex = 0;

        numberOfFacades = 0;
        int numberOfVolumes = data.plan.numberOfVolumes;

        LogTimer("Start");

        //define rectangles that represent the facades
        packedTexturePositions.Clear();
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }
                int      indexA = f;
                int      indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector2z p0     = plan.points[volume.points[indexA]];
                Vector2z p1     = plan.points[volume.points[indexB]];

                float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER;
                int   floorBase   = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);

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

                float floorHeight  = data.floorHeight;
                float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER;
                if (facadeHeight < 0)
                {
                    facadeWidth  = 0;
                    facadeHeight = 0;
                }

                Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight);
                packedTexturePositions.Add(newFacadeRect);

                numberOfFacades++;
            }
        }

        //Build ROOF
        DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh();

        dynMeshRoof.name         = "Roof Mesh";
        dynMeshRoof.subMeshCount = textures.Length;
        BuildrRoof.Build(dynMeshRoof, data, true);
        dynMeshRoof.CheckMaxTextureUVs(data);
        LogTimer("Roof A");

        roofTextures.Clear();
        roofTextureIndex.Clear();
        foreach (BuildrRoofDesign roofDesign in data.roofs)
        {
            foreach (int textureIndex in roofDesign.textureValues)
            {
                if (!roofTextureIndex.Contains(textureIndex))
                {
                    BuildrTexture bTexture = data.textures[textureIndex];
                    Vector2       largestSubmeshPlaneSize = new Vector2(1, 1);
                    Vector2       minWorldUvSize          = dynMeshRoof.MinWorldUvSize(textureIndex);
                    Vector2       maxWorldUvSize          = dynMeshRoof.MaxWorldUvSize(textureIndex);
                    largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x;
                    largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y;
                    int  roofTextureWidth    = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER);
                    int  roofTextureHeight   = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER);
                    Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight);
                    packedTexturePositions.Add(newRoofTexutureRect);
                    roofTextures.Add(bTexture);
                    roofTextureIndex.Add(textureIndex);
                }
            }
        }

        //run a custom packer to define their postions
        textureWidth = RectanglePack.Pack(packedTexturePositions, ATLAS_PADDING);

        //determine the resize scale and apply that to the rects
        packedScale = 1;
        int numberOfRects = packedTexturePositions.Count;

        if (textureWidth > MAXIMUM_TEXTURESIZE)
        {
            packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth;
            for (int i = 0; i < numberOfRects; i++)
            {
                Rect thisRect = packedTexturePositions[i];
                thisRect.x               *= packedScale;
                thisRect.y               *= packedScale;
                thisRect.width           *= packedScale;
                thisRect.height          *= packedScale;
                packedTexturePositions[i] = thisRect;
                //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]);
            }
            textureWidth = Mathf.RoundToInt(packedScale * textureWidth);
        }
        else
        {
            textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two
        }
        //Debug.Log("Texture Width "+textureWidth);
        //TODO: maybe restrict the resize to a power of two?
        LogTimer("Packed Rect Generated");

        textureSize = textureWidth * textureWidth;
        colourArray = new Color32[textureSize];
        //TestRectColours();//this test paints all the facades with rainbow colours - real pretty
        BuildTextures();

        LogTimer("texture created");
        Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true);

        packedTexture.filterMode = FilterMode.Bilinear;
        packedTexture.SetPixels32(colourArray);
        packedTexture.Apply(true, false);
        LogTimer("apply");

        if (data.LODTextureAtlas != null)
        {
            Object.DestroyImmediate(data.LODTextureAtlas);
        }
        data.LODTextureAtlas      = packedTexture;
        data.LODTextureAtlas.name = "Low Detail Texture";

        //build the model with new uvs

        if (data.drawUnderside)
        {
            for (int s = 0; s < numberOfVolumes; s++)
            {
                BuildrVolume volume = plan.volumes[s];
                int          numberOfVolumePoints = volume.points.Count;
                Vector3[]    newEndVerts          = new Vector3[numberOfVolumePoints];
                Vector2[]    newEndUVs            = new Vector2[numberOfVolumePoints];
                for (int i = 0; i < numberOfVolumePoints; i++)
                {
                    newEndVerts[i] = plan.points[volume.points[i]].vector3;
                    newEndUVs[i]   = Vector2.zero;
                }

                List <int> tris = new List <int>(data.plan.GetTrianglesBySectorBase(s));
                tris.Reverse();
                mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0);
            }
        }
        LogTimer("Floor");

        //Build facades
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }
                int     indexA = f;
                int     indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector3 p0     = plan.points[volume.points[indexA]].vector3;
                Vector3 p1     = plan.points[volume.points[indexB]].vector3;

                int floorBase      = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                Vector3 wallHeight       = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart;

                p0 += floorHeightStart;
                p1 += floorHeightStart;

                Vector3 w0 = p0;
                Vector3 w1 = p1;
                Vector3 w2 = w0 + wallHeight;
                Vector3 w3 = w1 + wallHeight;

                Rect facadeRect = packedTexturePositions[facadeIndex];

                float   imageSize = textureWidth;
                Vector2 uvMin     = new Vector2(facadeRect.xMin / imageSize, facadeRect.yMin / imageSize);
                Vector2 uvMax     = new Vector2(facadeRect.xMax / imageSize, facadeRect.yMax / imageSize);

                mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0);
                facadeIndex++;
            }
        }
        LogTimer("Facades");

        //ROOF Textures
        int         roofRectBase  = numberOfFacades;
        List <Rect> newAtlasRects = new List <Rect>();

        for (int i = roofRectBase; i < packedTexturePositions.Count; i++)
        {
            Rect uvRect = new Rect();//generate a UV based rectangle off the packed one
            uvRect.x      = packedTexturePositions[i].x / textureWidth;
            uvRect.y      = packedTexturePositions[i].y / textureWidth;
            uvRect.width  = packedTexturePositions[i].width / textureWidth;
            uvRect.height = packedTexturePositions[i].height / textureWidth;
            newAtlasRects.Add(uvRect);
        }
        dynMeshRoof.Atlas(roofTextureIndex.ToArray(), newAtlasRects.ToArray(), data.textures.ToArray());
        //Add the atlased mesh data to the main model data at submesh 0
        mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0);

        LogTimer("Roof B");

        data     = null;
        mesh     = null;
        textures = null;
        //atlasRects = null;

        LogTimer("Done");

        System.GC.Collect();
    }
    /// <summary>
    /// Generate the detail meshes and return the export object
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public static BuildrDetailExportObject Build(DynamicMeshGenericMultiMaterialMesh mesh, BuildrData data)
    {
        BuildrDetailExportObject exportObject = new BuildrDetailExportObject();
        List<Texture2D> detailTextures = new List<Texture2D>();
        List<int> detailSubmeshesWithTextures = new List<int>();
        int numberOfDetails = data.details.Count;
        mesh.Clear();
        mesh.subMeshCount = numberOfDetails;

        for(int d = 0; d < numberOfDetails; d++)
        {
            BuildrDetail detail = data.details[d];
            if(detail.mesh == null)
                continue;
            int faceIndex = detail.face;
            Vector3 position = Vector3.zero;
            BuildrPlan plan = data.plan;
            int numberOfVolumes = plan.numberOfVolumes;
            Vector2 faceUv = detail.faceUv;
            Quaternion faceAngle = Quaternion.identity;
            //Place the detail mesh
            if (detail.type == BuildrDetail.Types.Facade)
            {
                //find facade
                int facadeCount = 0;
                bool facadeFound = false;
                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volume = plan.volumes[s];
                    int numberOfVolumePoints = volume.points.Count;
                    for (int p = 0; p < numberOfVolumePoints; p++)
                    {
                        if (facadeCount == faceIndex)
                        {
                            int indexA = p;
                            int indexB = (p + 1) % numberOfVolumePoints;
                            Vector3 p0 = plan.points[volume.points[indexA]].vector3;
                            Vector3 p1 = plan.points[volume.points[indexB]].vector3;
                            Vector3 basePosition = Vector3.Lerp(p0, p1, faceUv.x);
                            Vector3 detailHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight * faceUv.y);
                            Vector3 facadeCross = Vector3.Cross(Vector3.up, p1 - p0).normalized;
                            Vector3 detailDepth = facadeCross * detail.faceHeight;
                            faceAngle = Quaternion.LookRotation(facadeCross);
                            position = basePosition + detailHeight + detailDepth;
                            facadeFound = true;
                            break;
                        }
                        facadeCount++;
                    }
                    if (facadeFound)
                        break;
                }
            }
            else//roof detail
            {
                BuildrVolume volume = plan.volumes[Mathf.Clamp(0,numberOfVolumes-1,faceIndex)];
                int numberOfVolumePoints = volume.points.Count;
                Vector3 minimumRoofPoint = plan.points[volume.points[0]].vector3;
                Vector3 maximumRoofPoint = minimumRoofPoint;
                for (int p = 1; p < numberOfVolumePoints; p++)
                {
                    Vector3 p0 = plan.points[volume.points[p]].vector3;
                    if (p0.x < minimumRoofPoint.x) minimumRoofPoint.x = p0.x;
                    if (p0.z < minimumRoofPoint.y) minimumRoofPoint.y = p0.z;
                    if (p0.x > maximumRoofPoint.x) maximumRoofPoint.x = p0.x;
                    if (p0.z > maximumRoofPoint.y) maximumRoofPoint.y = p0.z;
                }
                position.x = Mathf.Lerp(minimumRoofPoint.x, maximumRoofPoint.x, faceUv.x);
                position.z = Mathf.Lerp(minimumRoofPoint.y, maximumRoofPoint.y, faceUv.y);
                position.y = volume.numberOfFloors * data.floorHeight + detail.faceHeight;
            }

            Quaternion userRotation = Quaternion.Euler(detail.userRotation);
            int vertexCount = detail.mesh.vertexCount;
            Vector3[] verts = new Vector3[vertexCount];
            Quaternion rotate = faceAngle * userRotation;
            for (int i = 0; i < vertexCount; i++)
            {
                Vector3 sourceVertex = Vector3.Scale(detail.mesh.vertices[i], detail.scale);
                Vector3 outputVertex = (rotate) * sourceVertex + position;
                verts[i] = outputVertex;
            }
            mesh.AddData(verts, detail.mesh.uv, detail.mesh.triangles, d);
            detail.worldPosition = position;
            detail.worldRotation = rotate;

            if (detail.material.mainTexture != null)
            {
        #if UNITY_EDITOR
                string texturePath = AssetDatabase.GetAssetPath(detail.material.mainTexture);
                TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath);

                if (!textureImporter.isReadable)
                {
                    Debug.LogWarning("The texture you have selected is not readable. Cannot render");
                    return exportObject;
                }

                detailTextures.Add((Texture2D)detail.material.mainTexture);
                detailSubmeshesWithTextures.Add(d);
        #endif
            }
        }

        if(detailtexture!=null)
            Object.DestroyImmediate(detailtexture);

        List<Mesh> outputMeshes = new List<Mesh>();
        if (detailSubmeshesWithTextures.Count > 0)
        {
            Rect[] textureRects = BuildrTexturePacker2.Pack(out detailtexture, detailTextures.ToArray(), 512);
            if(detailSubmeshesWithTextures.Count > 0) mesh.Atlas(detailSubmeshesWithTextures.ToArray(), textureRects);
            mesh.CollapseSubmeshes();
            mesh.Build();
            int numberOfMeshes = mesh.meshCount;
            for (int i = 0; i < numberOfMeshes; i++)
                outputMeshes.Add(mesh[i].mesh);
        }

        exportObject.detailMeshes = outputMeshes.ToArray();
        exportObject.texture = detailtexture;
        return exportObject;
        /*if (detailMat == null)
                detailMat = new Material(Shader.Find("Diffuse"));
            detailMat.mainTexture = detailtexture;
            List<Mesh> outputMeshes = new List<Mesh>();
            for (int i = 0; i < numberOfMeshes; i++)
            {
                outputMeshes.Add(mesh[i].mesh);
                GameObject details = new GameObject("details " + i);
                details.AddComponent<MeshFilter>().mesh = mesh[i].mesh;
                details.AddComponent<MeshRenderer>().sharedMaterial = detailMat;
                detailGameobjects.Add(details);
            }
        }
        //        Debug.Log("BuildR Detail Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec");
        return detailGameobjects.ToArray();*/
    }
예제 #4
0
    public void UpdateRender()
    {
        if (track.numberOfCurves == 0)
        {
            return;
        }

        track.RecalculateCurves();
        float trackMeshRes = track.meshResolution;

        float bumperDistanceA = 0;
        float bumperDistanceB = 0;


        int   numberOfCurves = track.numberOfCurves;
        bool  renderTrack    = track.render;
        float UVOffset       = 0;
        int   polyCount      = 0;

        for (int i = 0; i < numberOfCurves; i++)
        {
            TrackBuildRPoint curve = track[i];

            DynamicMeshGenericMultiMaterialMesh dynamicTrackMesh    = curve.dynamicTrackMesh;
            DynamicMeshGenericMultiMaterialMesh dynamicBoundaryMesh = curve.dynamicBoundaryMesh;
            DynamicMeshGenericMultiMaterialMesh dynamicOffroadMesh  = curve.dynamicOffroadMesh;
            DynamicMeshGenericMultiMaterialMesh dynamicBumperMesh   = curve.dynamicBumperMesh;
            DynamicMeshGenericMultiMaterialMesh dynamicColliderMesh = curve.dynamicColliderMesh;
            DynamicMeshGenericMultiMaterialMesh dynamicBottomMesh   = curve.dynamicBottomMesh;

            if (!curve.render || !renderTrack)
            {
                dynamicTrackMesh.Clear();
                dynamicBoundaryMesh.Clear();
                dynamicColliderMesh.Clear();
                dynamicOffroadMesh.Clear();
                dynamicBumperMesh.Clear();
                dynamicBottomMesh.Clear();
            }

            if (curve.shouldReRender && curve.render && renderTrack)
            {
                dynamicTrackMesh.Clear();
                dynamicTrackMesh.subMeshCount = 1;
                dynamicBoundaryMesh.Clear();
                dynamicBoundaryMesh.subMeshCount = 1;
                dynamicColliderMesh.Clear();
                dynamicColliderMesh.subMeshCount = 1;
                dynamicOffroadMesh.Clear();
                dynamicOffroadMesh.subMeshCount = 1;
                dynamicBumperMesh.Clear();
                dynamicBumperMesh.subMeshCount = 1;
                dynamicBottomMesh.Clear();
                dynamicBottomMesh.subMeshCount = 1;

                dynamicTrackMesh.name    = "curve " + i + " track mesh";
                dynamicBoundaryMesh.name = "curve " + i + " boundary mesh";
                dynamicColliderMesh.name = "curve " + i + " trackCollider mesh";
                dynamicOffroadMesh.name  = "curve " + i + " offroad mesh";
                dynamicBumperMesh.name   = "curve " + i + " bumper mesh";
                dynamicBottomMesh.name   = "curve " + i + " bottom mesh";

                bool trackTextureFlip    = (track.numberOfTextures > 0) ? track.Texture(curve.trackTextureStyleIndex).flipped : false;
                bool boundaryTextureFlip = (track.numberOfTextures > 0) ? track.Texture(curve.boundaryTextureStyleIndex).flipped : false;
                bool bumperTextureFlip   = (track.numberOfTextures > 0) ? track.Texture(curve.bumperTextureStyleIndex).flipped : false;
                bool bottomTextureFlip   = (track.numberOfTextures > 0) ? track.Texture(curve.bottomTextureStyleIndex).flipped : false;

                int   storedPointSize = curve.storedPointSize;
                float curveLength     = curve.arcLength;
                //Store these points so we can use previous values when Bezier clips itself
                Vector3 leftPointA  = curve.sampledLeftBoundaryPoints[0];
                Vector3 rightPointA = curve.sampledRightBoundaryPoints[0];
                Vector3 leftPointB  = curve.sampledLeftBoundaryPoints[0];
                Vector3 rightPointB = curve.sampledRightBoundaryPoints[0];
                for (int p = 0; p < storedPointSize - 1; p++)
                {
                    float   tA           = curve.normalisedT[p];
                    float   tB           = curve.normalisedT[p + 1];
                    int     sampleIndexA = p;
                    int     sampleIndexB = sampleIndexA + 1;
                    Vector3 pointA       = curve.sampledPoints[sampleIndexA];
                    Vector3 pointB       = curve.sampledPoints[sampleIndexB];
                    float   trackWidthA  = curve.sampledWidths[sampleIndexA] * 0.5f;
                    float   trackWidthB  = curve.sampledWidths[sampleIndexB] * 0.5f;
                    float   trackCrownA  = curve.sampledCrowns[sampleIndexA];
                    float   trackCrownB  = curve.sampledCrowns[sampleIndexB];
                    Vector3 trackUpA     = curve.sampledTrackUps[sampleIndexA];
                    Vector3 trackUpB     = curve.sampledTrackUps[sampleIndexB];
                    Vector3 trackCrossA  = curve.sampledTrackCrosses[sampleIndexA];
                    Vector3 trackCrossB  = curve.sampledTrackCrosses[sampleIndexB];
                    float   trackAngle   = curve.sampledAngles[sampleIndexA];

                    if (trackUpA == Vector3.zero || trackUpB == Vector3.zero)
                    {
                        return;
                    }

                    //TrackBuildRTexture texture = track.Texture(curve.trackTextureStyleIndex) ;// track.trackTexture;
                    int       pointANumber     = Mathf.Max(Mathf.CeilToInt(trackWidthA / trackMeshRes / 2) * 2, 2); //number of verts along line A
                    int       pointBNumber     = Mathf.Max(Mathf.CeilToInt(trackWidthB / trackMeshRes / 2) * 2, 2); //number of verts along line B
                    int       numberOfNewVerts = pointANumber + pointBNumber;
                    Vector3[] uncrownedVerts   = new Vector3[numberOfNewVerts];
                    if (curve.clipArrayLeft[sampleIndexA])
                    {
                        leftPointA = (pointA + (trackCrossA * -trackWidthA));
                    }
                    if (curve.clipArrayRight[sampleIndexA])
                    {
                        rightPointA = (pointA + (trackCrossA * trackWidthA));
                    }
                    float curveLengthA = (curveLength * tA) / trackWidthA + UVOffset;
                    float curveLengthB = (curveLength * tB) / trackWidthB + UVOffset;
                    float lerpASize    = 1.0f / (pointANumber - 1);

                    //track vertex/uv data for point nextNormIndex
                    Vector3[] newAPoints     = new Vector3[pointANumber];
                    Vector3[] newTrackPoints = new Vector3[pointANumber + pointBNumber];
                    Vector2[] newTrackUVs    = new Vector2[pointANumber + pointBNumber];
                    for (int pa = 0; pa < pointANumber; pa++)
                    {
                        float   lerpValue     = lerpASize * pa;
                        Vector3 crownVector   = Quaternion.LookRotation(trackUpA) * new Vector3(0, 0, Mathf.Sin(lerpValue * Mathf.PI) * trackCrownA);
                        Vector3 uncrownedVert = Vector3.Lerp(leftPointA, rightPointA, lerpValue);
                        uncrownedVerts[pa] = uncrownedVert;
                        Vector3 newVert = uncrownedVert + crownVector;
                        newAPoints[pa]     = newVert;
                        newTrackPoints[pa] = newVert;
                        Vector2 newUV = (!trackTextureFlip) ? new Vector2(lerpValue, curveLengthA) : new Vector2(curveLengthA, lerpValue);
                        newTrackUVs[pa] = newUV;
                    }

                    //track vertex/uv data for point prevNormIndex
                    if (curve.clipArrayLeft[sampleIndexB])
                    {
                        leftPointB = (pointB + (trackCrossB * -trackWidthB));
                    }
                    if (curve.clipArrayRight[sampleIndexB])
                    {
                        rightPointB = (pointB + (trackCrossB * trackWidthB));
                    }
                    float     lerpBSize  = 1.0f / (pointBNumber - 1);
                    Vector3[] newBPoints = new Vector3[pointBNumber];
                    for (int pb = 0; pb < pointBNumber; pb++)
                    {
                        float   lerpValue     = lerpBSize * pb;
                        Vector3 crownVector   = Quaternion.LookRotation(trackUpB) * new Vector3(0, 0, Mathf.Sin(lerpValue * Mathf.PI) * trackCrownB);
                        Vector3 uncrownedVert = Vector3.Lerp(leftPointB, rightPointB, lerpValue);
                        uncrownedVerts[pb + pointANumber] = uncrownedVert;
                        Vector3 newVert = uncrownedVert + crownVector;
                        newBPoints[pb] = newVert;
                        newTrackPoints[pb + pointANumber] = newVert;
                        Vector2 newUV = (!trackTextureFlip) ? new Vector2(lerpValue, curveLengthB) : new Vector2(curveLengthB, lerpValue);
                        newTrackUVs[pb + pointANumber] = newUV;
                    }
                    int   baseTriPointA     = 0;
                    int   baseTriPointB     = pointANumber;
                    int   triPointA         = baseTriPointA;
                    int   triPointB         = baseTriPointB;
                    int   newTriPointCountA = 1;
                    int   newTriPointCountB = 1;
                    int[] newTrackTris      = new int[(numberOfNewVerts - 2) * 3];
                    for (int v = 0; v < numberOfNewVerts - 2; v++)
                    {
                        int newTriPointA = baseTriPointA + newTriPointCountA;
                        int newTriPointB = baseTriPointB + newTriPointCountB;

                        float newTriPointADist, newTriPointBDist;
                        if (newTriPointA >= baseTriPointA + pointANumber)
                        {
                            newTriPointADist = float.PositiveInfinity;
                        }
                        else
                        {
                            newTriPointADist = Vector3.SqrMagnitude(uncrownedVerts[newTriPointA] - uncrownedVerts[baseTriPointA]);
                        }

                        if (newTriPointB >= baseTriPointB + pointBNumber)
                        {
                            newTriPointBDist = float.PositiveInfinity;
                        }
                        else
                        {
                            newTriPointBDist = Vector3.SqrMagnitude(uncrownedVerts[newTriPointB] - uncrownedVerts[baseTriPointB]);
                        }

                        if (newTriPointADist < newTriPointBDist)
                        {
                            newTrackTris[v * 3]     = triPointA;
                            newTrackTris[v * 3 + 1] = triPointB;
                            newTrackTris[v * 3 + 2] = newTriPointA;
                            triPointA = newTriPointA;
                            newTriPointCountA++;
                        }
                        else
                        {
                            newTrackTris[v * 3]     = triPointA;
                            newTrackTris[v * 3 + 1] = triPointB;
                            newTrackTris[v * 3 + 2] = newTriPointB;
                            triPointB = newTriPointB;
                            newTriPointCountB++;
                        }
                    }
                    dynamicTrackMesh.AddData(newTrackPoints, newTrackUVs, newTrackTris, 0);
                    dynamicColliderMesh.AddData(newTrackPoints, newTrackUVs, newTrackTris, 0);

                    //Boundary
                    float trackBoundaryWallHeight = curve.boundaryHeight;// track.boundaryHeight;

                    Vector3 leftBoundaryPointA, leftBoundaryPointB, rightBoundaryPointA, rightBoundaryPointB;
                    if (track.disconnectBoundary)
                    {
                        leftBoundaryPointA  = curve.sampledLeftBoundaryPoints[sampleIndexA];
                        leftBoundaryPointB  = curve.sampledLeftBoundaryPoints[sampleIndexB];
                        rightBoundaryPointA = curve.sampledRightBoundaryPoints[sampleIndexA];
                        rightBoundaryPointB = curve.sampledRightBoundaryPoints[sampleIndexB];
                    }
                    else
                    {
                        leftBoundaryPointA  = leftPointA;
                        leftBoundaryPointB  = leftPointB;
                        rightBoundaryPointA = rightPointA;
                        rightBoundaryPointB = rightPointB;
                    }

                    Vector3[] newWallVerts;
                    Vector2[] newWallUVs;
                    int[]     newWallTris;

                    //Boundary Render Mesh
                    if (curve.renderBounds)
                    {
                        //LEFT
                        newWallVerts = new[] { leftBoundaryPointA, leftBoundaryPointB, leftBoundaryPointA + trackUpA * trackBoundaryWallHeight, leftBoundaryPointB + trackUpB * trackBoundaryWallHeight };

                        if (!boundaryTextureFlip)
                        {
                            newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), }
                        }
                        ;
                        else
                        {
                            newWallUVs = new[] { new Vector2(1, curveLengthA), new Vector2(1, curveLengthB), new Vector2(0, curveLengthA), new Vector2(0, curveLengthB), }
                        };
                        newWallTris = new[] { 1, 0, 2, 1, 2, 3 };
                        //                    newWallTris = (boundaryTextureFlip) ? (new[] { 1, 0, 2, 1, 2, 3 }) : (new[] { 0,2,1,2,3,1 });
                        //                    newWallTris = (!track.renderBoundaryWallReverse) ? new[] { 1, 0, 2, 1, 2, 3 } : new[] { 1, 0, 2, 1, 2, 3, 0, 1, 2, 2, 1, 3 };
                        dynamicBoundaryMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        if (track.renderBoundaryWallReverse)
                        {
                            newWallTris = new[] { 0, 1, 2, 2, 1, 3 };
                            //                        newWallTris = (boundaryTextureFlip) ? (new[] { 0, 1, 2, 2, 1, 3 }) : (new[] { 0, 2, 1, 2, 3, 1 });
                            dynamicBoundaryMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        }

                        //RIGHT
                        newWallVerts = (new[] { rightBoundaryPointA, rightBoundaryPointB, rightBoundaryPointA + trackUpA * trackBoundaryWallHeight, rightBoundaryPointB + trackUpB * trackBoundaryWallHeight });
                        //newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), };
                        if (!boundaryTextureFlip)
                        {
                            newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), }
                        }
                        ;
                        else
                        {
                            newWallUVs = new[] { new Vector2(1, curveLengthA), new Vector2(1, curveLengthB), new Vector2(0, curveLengthA), new Vector2(0, curveLengthB), }
                        };

                        newWallTris = new[] { 0, 1, 2, 2, 1, 3 };
                        //newWallTris = (!track.renderBoundaryWallReverse) ? new[] { 0, 1, 2, 2, 1, 3 } : new[] { 1, 0, 2, 1, 2, 3, 0, 1, 2, 2, 1, 3 };
                        dynamicBoundaryMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        if (track.renderBoundaryWallReverse)
                        {
                            newWallTris = new[] { 1, 0, 2, 1, 2, 3 };
                            dynamicBoundaryMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        }
                    }

                    if (curve.trackCollider)
                    {
                        //COLLIDER walls for on track border
                        float trackColliderWallHeight = track.trackColliderWallHeight;
                        if (curve.colliderSides)
                        {
                            newWallVerts = (new[] { leftBoundaryPointA, leftBoundaryPointB, leftBoundaryPointA + trackUpA * trackColliderWallHeight, leftBoundaryPointB + trackUpB * trackColliderWallHeight });
                            newWallUVs   = (new[] { Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero });
                            newWallTris  = (new[] { 1, 0, 2, 1, 2, 3 });
                            dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            newWallVerts = (new[] { rightBoundaryPointA, rightBoundaryPointB, rightBoundaryPointA + trackUpA * trackColliderWallHeight, rightBoundaryPointB + trackUpB * trackColliderWallHeight });
                            newWallUVs   = (new[] { Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero });
                            newWallTris  = (new[] { 0, 1, 2, 2, 1, 3 });
                            dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        }

                        //offroad bits
                        if (track.disconnectBoundary)
                        {
                            Vector2 offroadTextureSize = Vector2.one;
                            if (track.numberOfTextures > 0)
                            {
                                offroadTextureSize = track.Texture(curve.offroadTextureStyleIndex).textureUnitSize;// track.offroadTexture.textureUnitSize;
                            }
                            newWallVerts = (new[] { leftPointA, leftPointB, leftBoundaryPointA, leftBoundaryPointB });
                            newWallUVs   = (new[] { new Vector2(leftPointA.x / offroadTextureSize.x, leftPointA.z / offroadTextureSize.y), new Vector2(leftPointB.x / offroadTextureSize.x, leftPointB.z / offroadTextureSize.y), new Vector2(leftBoundaryPointA.x / offroadTextureSize.x, leftBoundaryPointA.z / offroadTextureSize.y), new Vector2(leftBoundaryPointB.x / offroadTextureSize.x, leftBoundaryPointB.z / offroadTextureSize.y) });
                            newWallTris  = (new[] { 1, 0, 2, 1, 2, 3 });
                            dynamicOffroadMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);

                            newWallVerts = (new[] { rightPointA, rightPointB, rightBoundaryPointA, rightBoundaryPointB });
                            newWallUVs   = (new[] { new Vector2(rightPointA.x / offroadTextureSize.x, rightPointA.z / offroadTextureSize.y), new Vector2(rightPointB.x / offroadTextureSize.x, rightPointB.z / offroadTextureSize.y), new Vector2(rightBoundaryPointA.x / offroadTextureSize.x, rightBoundaryPointA.z / offroadTextureSize.y), new Vector2(rightBoundaryPointB.x / offroadTextureSize.x, rightBoundaryPointB.z / offroadTextureSize.y) });
                            newWallTris  = (new[] { 0, 1, 2, 2, 1, 3 });
                            dynamicOffroadMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);

                            newWallVerts = (new[] { leftPointA, leftPointB, leftBoundaryPointA, leftBoundaryPointB });
                            newWallUVs   = (new[] { Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero });
                            newWallTris  = (new[] { 1, 0, 2, 1, 2, 3 });
                            dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            newWallVerts = (new[] { rightPointA, rightPointB, rightBoundaryPointA, rightBoundaryPointB });
                            newWallUVs   = (new[] { Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero });
                            newWallTris  = (new[] { 0, 1, 2, 2, 1, 3 });
                            dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        }

                        if (track.includeColliderRoof)
                        {
                            newWallVerts = (new[] { leftBoundaryPointA + trackUpA * trackColliderWallHeight, leftBoundaryPointB + trackUpB * trackColliderWallHeight, rightBoundaryPointA + trackUpA * trackColliderWallHeight, rightBoundaryPointB + trackUpB * trackColliderWallHeight });
                            newWallUVs   = (new[] { Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero });
                            newWallTris  = (new[] { 1, 0, 2, 1, 2, 3 });
                            dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        }
                    }

                    if ((track.trackBumpers && curve.generateBumpers) || curve.generateBumpers)
                    {
                        float   bumperWidth          = track.bumperWidth;
                        float   bumperHeight         = track.bumperHeight;
                        Vector3 bumperRaisedA        = trackUpA * bumperHeight;
                        Vector3 bumperRaisedB        = trackUpB * bumperHeight;
                        float   trackAngleThreashold = track.bumperAngleThresold;

                        //left bumpers
                        if (trackAngle >= trackAngleThreashold)
                        {
                            Vector3 offroadEdgeDirectionA = (leftBoundaryPointA - leftPointA).normalized;
                            Vector3 trackEdgeDirectionA   = (newAPoints[1] - newAPoints[0]).normalized;
                            Vector3 bumperDirectionA      = (Vector3.Project(offroadEdgeDirectionA, trackUpA) - trackEdgeDirectionA).normalized;
                            Vector3 offroadEdgeDirectionB = (leftBoundaryPointB - leftPointB).normalized;
                            Vector3 trackEdgeDirectionB   = (newBPoints[1] - newBPoints[0]).normalized;
                            Vector3 bumperDirectionB      = (Vector3.Project(offroadEdgeDirectionB, trackUpB) - trackEdgeDirectionB).normalized;
                            float   trackEdgeA            = Vector3.Distance(pointA, leftPointA);
                            float   offroadEdgeA          = Vector3.Distance(pointA, leftBoundaryPointA);
                            bool    offroadBumper         = (trackEdgeA < (offroadEdgeA - bumperWidth));
                            Vector3 bumperLeft0           = (offroadBumper ? leftPointA + bumperDirectionA * bumperWidth : leftBoundaryPointA) + bumperRaisedA;
                            Vector3 bumperLeft1           = (offroadBumper ? leftPointA : bumperLeft0 - (bumperDirectionA * bumperWidth) - bumperRaisedB);//bumperLeft0 + (trackEdgeDirectionA * bumperWidth)) - bumperRaisedB;

                            Vector3 bumperLeft2 = (offroadBumper ? leftPointB + bumperDirectionB * bumperWidth : leftBoundaryPointB) + bumperRaisedB;
                            Vector3 bumperLeft3 = (offroadBumper ? leftPointB : bumperLeft2 - (bumperDirectionB * bumperWidth) - bumperRaisedB);

                            float bumperSegmentDistanceA = Vector3.Distance(bumperLeft0, bumperLeft2);
                            float uvStartA, uvEndA;
                            if (track.numberOfTextures > 0)
                            {
                                uvStartA = bumperDistanceA / track.Texture(curve.bumperTextureStyleIndex).textureUnitSize.y;                            // track.bumperTexture.textureUnitSize.y;
                                uvEndA   = (bumperDistanceA + bumperSegmentDistanceA) / track.Texture(curve.bumperTextureStyleIndex).textureUnitSize.y; // track.bumperTexture.textureUnitSize.y;
                            }
                            else
                            {
                                uvStartA = bumperDistanceA;                            // track.bumperTexture.textureUnitSize.y;
                                uvEndA   = (bumperDistanceA + bumperSegmentDistanceA); // track.bumperTexture.textureUnitSize.y;
                            }
                            newWallVerts = (new[] { bumperLeft0, bumperLeft1, bumperLeft2, bumperLeft3 });
                            if (!bumperTextureFlip)
                            {
                                newWallUVs = (new[] { new Vector2(uvStartA, 1), new Vector2(uvStartA, 0), new Vector2(uvEndA, 1), new Vector2(uvEndA, 0) });
                            }
                            else
                            {
                                newWallUVs = (new[] { new Vector2(1, uvStartA), new Vector2(0, uvStartA), new Vector2(1, uvEndA), new Vector2(0, uvEndA) });
                            }
                            newWallTris = (new[] { 1, 0, 2, 1, 2, 3 });
                            dynamicBumperMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            bumperDistanceA += bumperSegmentDistanceA;

                            newWallVerts = (new[] { bumperLeft0, bumperLeft1, bumperLeft2, bumperLeft3 });
                            newWallUVs   = (new[] { Vector2.zero, Vector2.zero, Vector2.zero, Vector2.zero });
                            newWallTris  = (new[] { 1, 0, 2, 1, 2, 3 });
                            dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                        }

                        //Right bumpers
                        if (trackAngle < -trackAngleThreashold)
                        {
                            Vector3 trackEdgeDirectionA = (newAPoints[pointANumber - 2] - newAPoints[pointANumber - 1]).normalized;
                            Vector3 trackEdgeDirectionB = (newBPoints[pointBNumber - 2] - newBPoints[pointBNumber - 1]).normalized;

                            Vector3 bumperRight0 = ((Vector3.Distance(pointA, rightPointA) < (Vector3.Distance(pointA, rightBoundaryPointA) - bumperWidth)) ? rightPointA : rightBoundaryPointA) + bumperRaisedA;
                            Vector3 bumperRight1 = bumperRight0 + (trackEdgeDirectionA * bumperWidth);

                            Vector3 bumperRight2 = ((Vector3.Distance(pointB, rightPointB) < (Vector3.Distance(pointB, rightBoundaryPointB) - bumperWidth)) ? rightPointB : rightBoundaryPointB) + bumperRaisedB;
                            Vector3 bumperRight3 = bumperRight2 + (trackEdgeDirectionB * bumperWidth);

                            float bumperSegmentDistanceB = Vector3.Distance(bumperRight0, bumperRight2);
                            //float bumperSegmentDistanceA = Vector3.Distance(bumperLeft0, bumperLeft2);

                            float uvStartB, uvEndB;
                            if (track.numberOfTextures > 0)
                            {
                                uvStartB = bumperDistanceB / track.Texture(curve.bumperTextureStyleIndex).textureUnitSize.y;                            // track.bumperTexture.textureUnitSize.y;
                                uvEndB   = (bumperDistanceB + bumperSegmentDistanceB) / track.Texture(curve.bumperTextureStyleIndex).textureUnitSize.y; // track.bumperTexture.textureUnitSize.y;
                            }
                            else
                            {
                                uvStartB = bumperDistanceB;
                                uvEndB   = (bumperDistanceB + bumperSegmentDistanceB);
                            }
                            newWallVerts = (new[] { bumperRight0, bumperRight1, bumperRight2, bumperRight3 });
                            if (!bumperTextureFlip)
                            {
                                newWallUVs = (new[] { new Vector2(uvStartB, 1), new Vector2(uvStartB, 0), new Vector2(uvEndB, 1), new Vector2(uvEndB, 0) });
                            }
                            else
                            {
                                newWallUVs = (new[] { new Vector2(1, uvStartB), new Vector2(0, uvStartB), new Vector2(1, uvEndB), new Vector2(0, uvEndB) });
                            }
//                            newWallTris = (new[] { 1, 0, 2, 1, 2, 3 });
                            newWallTris = (new[] { 0, 1, 2, 1, 3, 2 });
                            dynamicBumperMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            bumperDistanceB += bumperSegmentDistanceB;
                        }
                    }


                    //Track Bottom Mesh
                    if (curve.extrudeTrack || curve.extrudeTrackBottom)
                    {
                        float   extrusionLength = curve.extrudeLength;
                        Vector3 extrusionA      = -trackUpA * extrusionLength;
                        Vector3 extrusionB      = -trackUpB * extrusionLength;
                        Vector3 pl0             = leftBoundaryPointA;
                        Vector3 pl1             = leftBoundaryPointB;
                        Vector3 pl2             = leftBoundaryPointA + extrusionA;
                        Vector3 pl3             = leftBoundaryPointB + extrusionB;
                        Vector3 pr0             = rightBoundaryPointA;
                        Vector3 pr1             = rightBoundaryPointB;
                        Vector3 pr2             = rightBoundaryPointA + extrusionA;
                        Vector3 pr3             = rightBoundaryPointB + extrusionB;

                        float   bevelLerp = 0.5f - curve.extrudeBevel * 0.3333f;
                        Vector3 bevelOutA = trackCrossA.normalized * (trackWidthA * 0.5f);
                        Vector3 bevelOutB = trackCrossB.normalized * (trackWidthB * 0.5f);
                        Vector3 pl2b      = Vector3.Lerp(pl2 - bevelOutA, pr2 + bevelOutA, bevelLerp);
                        Vector3 pl3b      = Vector3.Lerp(pl3 - bevelOutB, pr3 + bevelOutB, bevelLerp);
                        Vector3 pr2b      = Vector3.Lerp(pr2 + bevelOutA, pl2 - bevelOutA, bevelLerp);
                        Vector3 pr3b      = Vector3.Lerp(pr3 + bevelOutB, pl3 - bevelOutB, bevelLerp);

                        if (curve.extrudeTrack)
                        {
                            //LEFT

                            newWallVerts = new[] { pl0, pl1, pl2b, pl3b };

                            if (!bottomTextureFlip)
                            {
                                newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), }
                            }
                            ;
                            else
                            {
                                newWallUVs = new[] { new Vector2(1, curveLengthA), new Vector2(1, curveLengthB), new Vector2(0, curveLengthA), new Vector2(0, curveLengthB), }
                            };
                            newWallTris = new[] { 1, 0, 2, 1, 2, 3 };
                            dynamicBottomMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            if (curve.trackCollider)
                            {
                                dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            }

                            //RIGHT
                            newWallVerts = (new[] { pr0, pr1, pr2b, pr3b });
                            if (!bottomTextureFlip)
                            {
                                newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), }
                            }
                            ;
                            else
                            {
                                newWallUVs = new[] { new Vector2(1, curveLengthA), new Vector2(1, curveLengthB), new Vector2(0, curveLengthA), new Vector2(0, curveLengthB), }
                            };

                            newWallTris = new[] { 0, 1, 2, 2, 1, 3 };
                            dynamicBottomMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            if (curve.trackCollider)
                            {
                                dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            }

                            if (curve.extrudeCurveEnd)
                            {
                                //Ends
                                if (p == 0)
                                {
                                    newWallVerts = (new[] { pl0, pl2b, pr0, pr2b });
                                    if (!bottomTextureFlip)
                                    {
                                        newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), }
                                    }
                                    ;
                                    else
                                    {
                                        newWallUVs = new[] { new Vector2(1, curveLengthA), new Vector2(1, curveLengthB), new Vector2(0, curveLengthA), new Vector2(0, curveLengthB), }
                                    };
                                    newWallTris = new[] { 1, 0, 2, 1, 2, 3 };
                                    dynamicBottomMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                                    if (curve.trackCollider)
                                    {
                                        dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                                    }
                                }
                                if (p == storedPointSize - 2)
                                {
                                    newWallVerts = (new[] { pl1, pl3b, pr1, pr3b });
                                    if (!bottomTextureFlip)
                                    {
                                        newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), }
                                    }
                                    ;
                                    else
                                    {
                                        newWallUVs = new[] { new Vector2(1, curveLengthA), new Vector2(1, curveLengthB), new Vector2(0, curveLengthA), new Vector2(0, curveLengthB), }
                                    };
                                    newWallTris = new[] { 0, 1, 2, 2, 1, 3 };
                                    dynamicBottomMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                                    if (curve.trackCollider)
                                    {
                                        dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                                    }
                                }
                            }
                        }

                        if (curve.extrudeTrackBottom)
                        {
                            if (!curve.extrudeTrack)
                            {
                                newWallVerts = new[] { pl0, pl1, pr0, pr1 }
                            }
                            ;
                            else
                            {
                                newWallVerts = new[] { pl2b, pl3b, pr2b, pr3b }
                            };

                            if (!bottomTextureFlip)
                            {
                                newWallUVs = new[] { new Vector2(curveLengthA, 0), new Vector2(curveLengthB, 0), new Vector2(curveLengthA, 1), new Vector2(curveLengthB, 1), }
                            }
                            ;
                            else
                            {
                                newWallUVs = new[] { new Vector2(1, curveLengthA), new Vector2(1, curveLengthB), new Vector2(0, curveLengthA), new Vector2(0, curveLengthB), }
                            };

                            newWallTris = new[] { 1, 0, 2, 1, 2, 3 };
                            dynamicBottomMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            if (curve.trackCollider)
                            {
                                dynamicColliderMesh.AddData(newWallVerts, newWallUVs, newWallTris, 0);
                            }
                        }
                    }

                    if (p == storedPointSize - 2)
                    {
                        UVOffset = curveLengthB;
                    }
                }

                if (curve.holder != null)
                {
                    DestroyImmediate(curve.holder);
                }

                GameObject newCurveMeshHolder = new GameObject("curve " + (i + 1));
                newCurveMeshHolder.transform.parent        = transform;
                newCurveMeshHolder.transform.localPosition = Vector3.zero;
                curve.holder = newCurveMeshHolder;
                int numberOfMeshes;
                if (!dynamicTrackMesh.isEmpty)
                {
                    dynamicTrackMesh.name = "Curve " + i + " Track Mesh";
                    dynamicTrackMesh.Build();
                    numberOfMeshes = dynamicTrackMesh.meshCount;
                    for (int m = 0; m < numberOfMeshes; m++)
                    {
                        GameObject newMeshHolder = new GameObject("model " + (m + 1));
                        newMeshHolder.transform.parent        = curve.holder.transform;
                        newMeshHolder.transform.localPosition = Vector3.zero;
                        newMeshHolder.AddComponent <MeshFilter>().sharedMesh = dynamicTrackMesh[m].mesh;
                        if (track.numberOfTextures > 0)
                        {
                            newMeshHolder.AddComponent <MeshRenderer>().material = track.Texture(curve.trackTextureStyleIndex).GetMaterial();// track.trackTexture.material;
                        }
#if UNITY_EDITOR
                        EditorUtility.SetSelectedWireframeHidden(newMeshHolder.renderer, !track.showWireframe);
#endif
                    }
                }


                if (!dynamicBoundaryMesh.isEmpty)
                {
                    dynamicBoundaryMesh.Build();
                    numberOfMeshes = dynamicBoundaryMesh.meshCount;
                    for (int m = 0; m < numberOfMeshes; m++)
                    {
                        GameObject newMeshHolder = new GameObject("boundary " + (m + 1));
                        newMeshHolder.transform.parent        = curve.holder.transform;
                        newMeshHolder.transform.localPosition = Vector3.zero;
                        newMeshHolder.AddComponent <MeshFilter>().sharedMesh = dynamicBoundaryMesh[m].mesh;
                        if (track.numberOfTextures > 0)
                        {
                            newMeshHolder.AddComponent <MeshRenderer>().material = track.Texture(curve.boundaryTextureStyleIndex).GetMaterial();// track.trackTexture.material;
                        }
#if UNITY_EDITOR
                        EditorUtility.SetSelectedWireframeHidden(newMeshHolder.renderer, !track.showWireframe);
#endif
                    }
                }

                if (track.disconnectBoundary && !dynamicOffroadMesh.isEmpty)
                {
                    dynamicOffroadMesh.Build();
                    numberOfMeshes = dynamicOffroadMesh.meshCount;
                    for (int m = 0; m < numberOfMeshes; m++)
                    {
                        GameObject newMeshHolder = new GameObject("offroad " + (m + 1));
                        newMeshHolder.transform.parent        = curve.holder.transform;
                        newMeshHolder.transform.localPosition = Vector3.zero;
                        newMeshHolder.AddComponent <MeshFilter>().sharedMesh = dynamicOffroadMesh[m].mesh;
                        if (track.numberOfTextures > 0)
                        {
                            newMeshHolder.AddComponent <MeshRenderer>().material = track.Texture(curve.offroadTextureStyleIndex).GetMaterial();// track.offroadTexture.material;
                        }
#if UNITY_EDITOR
                        EditorUtility.SetSelectedWireframeHidden(newMeshHolder.renderer, !track.showWireframe);
#endif
                    }
                }

                if (track.includeCollider && curve.trackCollider && !dynamicColliderMesh.isEmpty)
                {
                    dynamicColliderMesh.Build();
                    int numberOfColliderMeshes = dynamicColliderMesh.meshCount;
                    for (int m = 0; m < numberOfColliderMeshes; m++)
                    {
                        GameObject newMeshHolder = new GameObject("trackCollider " + (m + 1));
                        newMeshHolder.transform.parent        = curve.holder.transform;
                        newMeshHolder.transform.localPosition = Vector3.zero;
                        newMeshHolder.AddComponent <MeshCollider>().sharedMesh = dynamicColliderMesh[m].mesh;
                    }
                }

                if (track.trackBumpers && !dynamicBumperMesh.isEmpty)
                {
                    dynamicBumperMesh.Build();
                    numberOfMeshes = dynamicBumperMesh.meshCount;
                    for (int m = 0; m < numberOfMeshes; m++)
                    {
                        GameObject newMeshHolder = new GameObject("bumper " + (m + 1));
                        newMeshHolder.transform.parent        = curve.holder.transform;
                        newMeshHolder.transform.localPosition = Vector3.zero;
                        newMeshHolder.AddComponent <MeshFilter>().sharedMesh = dynamicBumperMesh[m].mesh;
                        if (track.numberOfTextures > 0)
                        {
                            newMeshHolder.AddComponent <MeshRenderer>().material = track.Texture(curve.bumperTextureStyleIndex).GetMaterial();// track.bumperTexture.material;
                        }
#if UNITY_EDITOR
                        EditorUtility.SetSelectedWireframeHidden(newMeshHolder.renderer, !track.showWireframe);
#endif
                    }
                }

                if (!dynamicBottomMesh.isEmpty)
                {
                    dynamicBottomMesh.Build();
                    numberOfMeshes = dynamicBottomMesh.meshCount;
                    for (int m = 0; m < numberOfMeshes; m++)
                    {
                        GameObject newMeshHolder = new GameObject("bottom " + (m + 1));
                        newMeshHolder.transform.parent        = curve.holder.transform;
                        newMeshHolder.transform.localPosition = Vector3.zero;
                        newMeshHolder.AddComponent <MeshFilter>().sharedMesh = dynamicBottomMesh[m].mesh;
                        if (track.numberOfTextures > 0)
                        {
                            newMeshHolder.AddComponent <MeshRenderer>().material = track.Texture(curve.bottomTextureStyleIndex).GetMaterial();// track.trackTexture.material;
                        }
#if UNITY_EDITOR
                        EditorUtility.SetSelectedWireframeHidden(newMeshHolder.renderer, !track.showWireframe);
#endif
                    }
                }
            }
            else
            {
                if (curve.holder != null && (!curve.render || !renderTrack))
                {
                    DestroyImmediate(curve.holder);
                }
            }

            polyCount += dynamicBottomMesh.triangleCount / 3;
            polyCount += dynamicBoundaryMesh.triangleCount / 3;
            polyCount += dynamicBumperMesh.triangleCount / 3;
            polyCount += dynamicOffroadMesh.triangleCount / 3;
            polyCount += dynamicTrackMesh.triangleCount / 3;
        }

        track.TrackRendered();

        track.lastPolycount = polyCount;

#if UNITY_EDITOR
        EditorUtility.UnloadUnusedAssets();
#endif
    }
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {

//        timestart = Time.realtimeSinceStartup;
        data = _data;
        mesh = _mesh;
        textures = data.textures.ToArray();
        BuildrPlan plan = data.plan;

        int facadeIndex = 0;
        numberOfFacades = 0;
        int numberOfVolumes = data.plan.numberOfVolumes;

        LogTimer("Start");

        //define rectangles that represent the facades
        packedTexturePositions.Clear();
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                    continue;
                int indexA = f;
                int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector2z p0 = plan.points[volume.points[indexA]];
                Vector2z p1 = plan.points[volume.points[indexB]];

                float facadeWidth = Vector2z.Distance(p0, p1) * PIXELS_PER_METER;
                int floorBase = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);

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

                float floorHeight = data.floorHeight;
                float facadeHeight = (volume.numberOfFloors - floorBase) * floorHeight * PIXELS_PER_METER;
                if (facadeHeight < 0)
                {
                    facadeWidth = 0;
                    facadeHeight = 0;
                }

                Rect newFacadeRect = new Rect(0, 0, facadeWidth, facadeHeight);
                packedTexturePositions.Add(newFacadeRect);

                numberOfFacades++;
            }
        }

        //Build ROOF
        DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh();
        dynMeshRoof.name = "Roof Mesh";
        dynMeshRoof.subMeshCount = textures.Length;
        BuildrRoof.Build(dynMeshRoof, data, true);
        dynMeshRoof.CheckMaxTextureUVs(data);
        LogTimer("Roof A");

        roofTextures.Clear();
        roofTextureIndex.Clear();
        foreach (BuildrRoofDesign roofDesign in data.roofs)
        {
            foreach (int textureIndex in roofDesign.textureValues)
            {
                if (!roofTextureIndex.Contains(textureIndex))
                {
                    BuildrTexture bTexture = data.textures[textureIndex];
                    Vector2 largestSubmeshPlaneSize = new Vector2(1,1);
                    Vector2 minWorldUvSize = dynMeshRoof.MinWorldUvSize(textureIndex);
                    Vector2 maxWorldUvSize = dynMeshRoof.MaxWorldUvSize(textureIndex);
                    largestSubmeshPlaneSize.x = maxWorldUvSize.x - minWorldUvSize.x;
                    largestSubmeshPlaneSize.y = maxWorldUvSize.y - minWorldUvSize.y;
                    int roofTextureWidth = Mathf.RoundToInt(largestSubmeshPlaneSize.x * PIXELS_PER_METER);
                    int roofTextureHeight = Mathf.RoundToInt(largestSubmeshPlaneSize.y * PIXELS_PER_METER);
                    Rect newRoofTexutureRect = new Rect(0, 0, roofTextureWidth, roofTextureHeight);
                    packedTexturePositions.Add(newRoofTexutureRect);
                    roofTextures.Add(bTexture);
                    roofTextureIndex.Add(textureIndex);
                }
            }
        }

        //run a custom packer to define their postions
        textureWidth = RectanglePack.Pack(packedTexturePositions,ATLAS_PADDING);

        //determine the resize scale and apply that to the rects
        packedScale = 1;
        int numberOfRects = packedTexturePositions.Count;
        if (textureWidth > MAXIMUM_TEXTURESIZE)
        {
            packedScale = MAXIMUM_TEXTURESIZE / (float)textureWidth;
            for (int i = 0; i < numberOfRects; i++)
            {
                Rect thisRect = packedTexturePositions[i];
                thisRect.x *= packedScale;
                thisRect.y *= packedScale;
                thisRect.width *= packedScale;
                thisRect.height *= packedScale;
                packedTexturePositions[i] = thisRect;
                //Debug.Log("Rects "+roofTextures[i-+packedTexturePositions[i]);
            }
            textureWidth = Mathf.RoundToInt(packedScale * textureWidth);
        }
        else
        {
            textureWidth = (int)Mathf.Pow(2, (Mathf.FloorToInt(Mathf.Log(textureWidth - 1, 2)) + 1));//find the next power of two
        }
        //Debug.Log("Texture Width "+textureWidth);
        //TODO: maybe restrict the resize to a power of two?
        LogTimer("Packed Rect Generated");

        textureSize = textureWidth * textureWidth;
        colourArray = new Color32[textureSize];
        //TestRectColours();//this test paints all the facades with rainbow colours - real pretty
        BuildTextures();

        LogTimer("texture created");
        Texture2D packedTexture = new Texture2D(textureWidth, textureWidth, TextureFormat.ARGB32, true);
        packedTexture.filterMode = FilterMode.Bilinear;
        packedTexture.SetPixels32(colourArray);
        packedTexture.Apply(true, false);
        LogTimer("apply");

        if (data.LODTextureAtlas != null)
            Object.DestroyImmediate(data.LODTextureAtlas);
        data.LODTextureAtlas = packedTexture;
        data.LODTextureAtlas.name = "Low Detail Texture";

        //build the model with new uvs

        if (data.drawUnderside)
        {
            for (int s = 0; s < numberOfVolumes; s++)
            {
                BuildrVolume volume = plan.volumes[s];
                int numberOfVolumePoints = volume.points.Count;
                Vector3[] newEndVerts = new Vector3[numberOfVolumePoints];
                Vector2[] newEndUVs = new Vector2[numberOfVolumePoints];
                for (int i = 0; i < numberOfVolumePoints; i++)
                {
                    newEndVerts[i] = plan.points[volume.points[i]].vector3;
                    newEndUVs[i] = Vector2.zero;
                }

                List<int> tris = new List<int>(data.plan.GetTrianglesBySectorBase(s));
                tris.Reverse();
                mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0);
            }
        }
        LogTimer("Floor");

        //Build facades
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                    continue;
                int indexA = f;
                int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector3 p0 = plan.points[volume.points[indexA]].vector3;
                Vector3 p1 = plan.points[volume.points[indexB]].vector3;

                int floorBase = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                Vector3 wallHeight = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart;

                p0 += floorHeightStart;
                p1 += floorHeightStart;

                Vector3 w0 = p0;
                Vector3 w1 = p1;
                Vector3 w2 = w0 + wallHeight;
                Vector3 w3 = w1 + wallHeight;

                Rect facadeRect = packedTexturePositions[facadeIndex];

                float imageSize = textureWidth;
                Vector2 uvMin = new Vector2(facadeRect.xMin / imageSize, facadeRect.yMin / imageSize);
                Vector2 uvMax = new Vector2(facadeRect.xMax / imageSize, facadeRect.yMax / imageSize);

                mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0);
                facadeIndex++;
            }
        }
        LogTimer("Facades");

        //ROOF Textures
        int roofRectBase = numberOfFacades;
        List<Rect> newAtlasRects = new List<Rect>();
        for (int i = roofRectBase; i < packedTexturePositions.Count; i++)
        {
            Rect uvRect = new Rect();//generate a UV based rectangle off the packed one
            uvRect.x = packedTexturePositions[i].x / textureWidth;
            uvRect.y = packedTexturePositions[i].y / textureWidth;
            uvRect.width = packedTexturePositions[i].width / textureWidth;
            uvRect.height = packedTexturePositions[i].height / textureWidth;
            newAtlasRects.Add(uvRect);
        }
        dynMeshRoof.Atlas(roofTextureIndex.ToArray(), newAtlasRects.ToArray(), data.textures.ToArray());
        //Add the atlased mesh data to the main model data at submesh 0
        mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0);
        
        LogTimer("Roof B");

        data = null;
        mesh = null;
        textures = null;
        //atlasRects = null;

        LogTimer("Done");

        System.GC.Collect();
    }
예제 #6
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data, Rect[] uvConstraints)
    {
        data = _data;
        mesh = _mesh;
        textures = data.textures.ToArray();
        BuildrFacadeDesign facadeDesign = data.facades[0];
        BuildrPlan plan = data.plan;
        int numberOfVolumes = plan.numberOfVolumes;

        if(plan.numberOfFacades != uvConstraints.Length)
            Debug.LogError("Incompatible amount of uv constraints " + plan.numberOfFacades +" uvc: "+ uvConstraints.Length);

        float largestDepthValue = 0;//deepest value of a bay design in the building
        foreach (BuildrBay bay in data.bays)
            largestDepthValue = Mathf.Max(largestDepthValue, bay.deepestValue);//get the deepest value
        foreach (BuildrFacadeDesign facade in data.facades)
            largestDepthValue = Mathf.Max(largestDepthValue, facade.simpleBay.deepestValue);//get the deepest value

        int facadeCount = 0;
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int numberOfVolumePoints = volume.points.Count;
            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                    continue;

                int indexAM = Mathf.Abs((f - 1) % numberOfVolumePoints);
                int indexA = f;
                int indexB = (f + 1) % numberOfVolumePoints;
                int indexBP = (f + 2) % numberOfVolumePoints;
                Vector3 p0m = plan.points[volume.points[indexAM]].vector3;
                Vector3 p0 = plan.points[volume.points[indexA]].vector3;
                Vector3 p1 = plan.points[volume.points[indexB]].vector3;
                Vector3 p1p = plan.points[volume.points[indexBP]].vector3;

                facadeCount++;

                float realFadeWidth = Vector3.Distance(p0, p1);
                float facadeWidth = realFadeWidth - largestDepthValue * 2.0f;
                Vector3 facadeDirection = (p1 - p0).normalized;
                Vector3 facadeCross = Vector3.Cross(facadeDirection, Vector3.up).normalized;
                Vector3 lastFacadeDirection = (p0 - p0m).normalized;
                Vector3 nextFacadeDirection = (p1p - p1).normalized;

                //only bother with facade directions when facade may intersect inverted geometry
                float facadeDirDotL = Vector3.Dot(-facadeDirection, lastFacadeDirection);
                float facadeCrossDotL = Vector3.Dot(-facadeCross, lastFacadeDirection);
                if (facadeDirDotL <= 0 || facadeCrossDotL <= 0) lastFacadeDirection = -facadeCross;

                float facadeDirDotN = Vector3.Dot(-facadeDirection, nextFacadeDirection);
                float facadeCrossDotN = Vector3.Dot(-facadeCross, nextFacadeDirection);
                if (facadeDirDotN <= 0 || facadeCrossDotN <= 0) nextFacadeDirection = facadeCross;


                int floorBase = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;
                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                p0 += floorHeightStart;
                BuildrVolumeStylesUnit[] styleUnits = volume.styles.GetContentsByFacade(volume.points[indexA]);
                int floorPatternSize = 0;
                List<int> facadePatternReference = new List<int>();//this contains a list of all the facade style indices to refence when looking for the appropriate style per floor
                int patternCount = 0;
                foreach (BuildrVolumeStylesUnit styleUnit in styleUnits)//need to knw how big all the styles are together so we can loop through them
                {
                    floorPatternSize += styleUnit.floors;
                    for (int i = 0; i < styleUnit.floors; i++)
                        facadePatternReference.Add(patternCount);
                    patternCount++;
                }
                facadePatternReference.Reverse();

                int rows = numberOfFloors;

                float foundationHeight = data.foundationHeight;
                if (foundationHeight > 0 && floorBase == 0)
                {
                    int subMesh = _data.foundationTexture;
                    Vector3 foundationVector = Vector3.up * -foundationHeight;
                    Vector3 w0 = p0 + foundationVector;
                    Vector3 w1 = p1 + foundationVector;
                    Vector3 w2 = p0;
                    Vector3 w3 = p1;
                    AddPlane(w0, w1, w2, w3, subMesh, false, new Vector2(0, -foundationHeight), new Vector2(facadeWidth, 0));
                }

                Vector2 facadeUV = Vector2.zero;

                for (int r = 0; r < rows; r++)
                {
                    bool firstRow = r == 0;
                    bool lastRow = r == (rows - 1);
                    //Get the facade style id
                    //need to loop through the facade designs floor by floor until we get to the right one
                    float currentHeight = floorHeight * r;
                    Vector3 facadeFloorBaseVector = p0 + Vector3.up * currentHeight;
                    int modFloor = (r % floorPatternSize);
                    int modFloorPlus = ((r + 1) % floorPatternSize);
                    int modFloorMinus = (r > 0) ? ((r - 1) % floorPatternSize) : 0;
                    BuildrFacadeDesign lastFacadeDesign = null;
                    BuildrFacadeDesign nextFacadeDesign = null;

                    facadeDesign = data.facades[styleUnits[facadePatternReference[modFloor]].styleID];
                    nextFacadeDesign = data.facades[styleUnits[facadePatternReference[modFloorPlus]].styleID];
                    lastFacadeDesign = data.facades[styleUnits[facadePatternReference[modFloorMinus]].styleID];

                    bool isBlankWall = !facadeDesign.hasWindows;
                    if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                    {
                        if(data.bays.Count == 0 || facadeDesign.bayPattern.Count == 0)
                            isBlankWall = true;
                        else
                        {
                            BuildrBay firstBay = data.bays[facadeDesign.bayPattern[0]];
                            if (firstBay.openingWidth > facadeWidth) isBlankWall = true;
                            if (facadeDesign.bayPattern.Count == 0) isBlankWall = true;
                        }
                    }
                    else
                    {
                        if (facadeDesign.simpleBay.openingWidth + facadeDesign.simpleBay.minimumBayWidth > facadeWidth)
                            isBlankWall = true;
                    }

                    Vector3 windowBase = facadeFloorBaseVector;
                    facadeUV.x = 0;
                    facadeUV.y += currentHeight;
                    if (!isBlankWall)
                    {
                        float patternSize = 0;//the space the pattern fills, there will be a gap that will be distributed to all bay styles
                        int numberOfBays = 0;
                        BuildrBay[] bayDesignPattern;
                        int numberOfBayDesigns;
                        if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                        {
                            numberOfBayDesigns = facadeDesign.bayPattern.Count;
                            bayDesignPattern = new BuildrBay[numberOfBayDesigns];
                            for (int i = 0; i < numberOfBayDesigns; i++)
                            {
                                bayDesignPattern[i] = data.bays[facadeDesign.bayPattern[i]];
                            }
                        }
                        else
                        {
                            bayDesignPattern = new[] { facadeDesign.simpleBay };
                            numberOfBayDesigns = 1;
                        }
                        //start with first window width - we'll be adding to this until we have filled the facade width
                        int it = 100;
                        while (true)
                        {
                            int patternModIndex = numberOfBays % numberOfBayDesigns;
                            float patternAddition = bayDesignPattern[patternModIndex].openingWidth + bayDesignPattern[patternModIndex].minimumBayWidth;
                            if (patternSize + patternAddition < facadeWidth)
                            {
                                patternSize += patternAddition;
                                numberOfBays++;
                            }
                            else
                                break;
                            it--;
                            if (it < 0)
                                break;
                        }

                        float perBayAdditionalSpacing = (facadeWidth - patternSize) / numberOfBays;
                        for (int c = 0; c < numberOfBays; c++)
                        {
                            BuildrBay bayStyle;
                            BuildrBay lastBay;
                            BuildrBay nextBay;
                            bool firstColumn = c == 0;
                            bool lastColumn = c == numberOfBays - 1;
                            if (facadeDesign.type == BuildrFacadeDesign.types.patterned)
                            {
                                int numberOfBayStyles = facadeDesign.bayPattern.Count;
                                bayStyle = bayDesignPattern[c % numberOfBayStyles];
                                int lastBayIndex = (c > 0) ? (c - 1) % numberOfBayStyles : 0;
                                lastBay = bayDesignPattern[lastBayIndex];
                                nextBay = bayDesignPattern[(c + 1) % numberOfBayStyles];
                            }
                            else
                            {
                                bayStyle = facadeDesign.simpleBay;
                                lastBay = facadeDesign.simpleBay;
                                nextBay = facadeDesign.simpleBay;
                            }
                            float actualWindowSpacing = bayStyle.minimumBayWidth + perBayAdditionalSpacing;
                            float leftWidth = actualWindowSpacing * bayStyle.openingWidthRatio;
                            float rightWidth = actualWindowSpacing - leftWidth;
                            float openingWidth = bayStyle.openingWidth;

                            if (firstColumn) leftWidth += largestDepthValue;
                            if (lastColumn) rightWidth += largestDepthValue;

                            //                            float openingHeight = bayStyle.openingHeight;
                            BuildrTexture columnTexture = textures[bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture)];
                            Vector2 columnuvunits = columnTexture.tileUnitUV;
                            float openingHeight = bayStyle.openingHeight;
                            if (columnTexture.patterned) openingHeight = Mathf.Round(bayStyle.openingHeight / columnuvunits.y) * columnuvunits.y;
                            //if (bayStyle.openingHeight == floorHeight) bayStyle.openingHeight = floorHeight;

                            float rowBottomHeight = ((floorHeight - openingHeight) * bayStyle.openingHeightRatio);
                            if (columnTexture.patterned) rowBottomHeight = Mathf.Ceil(rowBottomHeight / columnuvunits.y) * columnuvunits.y;

                            float rowTopHeight = (floorHeight - rowBottomHeight - openingHeight);

                            bool previousBayIdentical = bayStyle == lastBay;
                            bool nextBayIdentical = bayStyle == nextBay;
                            if (previousBayIdentical && !firstColumn)
                                leftWidth = actualWindowSpacing;//if next design is identical - add the two parts together the reduce polycount

                            Vector3 w0, w1, w2, w3;
                            float windowSideDepth, bottomDepth;

                            if (!bayStyle.isOpening)
                            {
                                int wallSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.WallTexture);
                                bool wallFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.WallTexture);
                                float bayWidthSize = openingWidth + actualWindowSpacing;
                                if (firstColumn || lastColumn) bayWidthSize += largestDepthValue;
                                Vector3 bayWidth = facadeDirection * bayWidthSize;
                                Vector3 bayHeight = Vector3.up * floorHeight;
                                Vector3 bayDepth = facadeCross * largestDepthValue;
                                w0 = windowBase;
                                w1 = windowBase + bayWidth;
                                w2 = windowBase + bayHeight;
                                w3 = windowBase + bayWidth + bayHeight;
                                Vector2 bayOpeningUVEnd = facadeUV + new Vector2(openingWidth + actualWindowSpacing, floorHeight);
                                AddPlane(w0, w1, w2, w3, wallSubMesh, wallFlipped, facadeUV, bayOpeningUVEnd);

                                Vector2 UVEnd = new Vector2(1, floorHeight);
                                if (!previousBayIdentical && !firstColumn)//left
                                {
                                    Vector3 wA = w0 + bayDepth;
                                    Vector3 wB = w2 + bayDepth;
                                    AddPlane(w2, wB, w0, wA, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }

                                if (!nextBayIdentical && !lastColumn)//right
                                {
                                    Vector3 wA = w1 + bayDepth;
                                    Vector3 wB = w3 + bayDepth;
                                    AddPlane(w1, wA, w3, wB, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }

                                if (lastFacadeDesign != facadeDesign && !firstRow)//bottom
                                {
                                    Vector3 wA = w0 + ((!firstColumn) ? facadeCross*largestDepthValue : -lastFacadeDirection*largestDepthValue);
                                    Vector3 wB = w1 + ((!lastColumn) ? facadeCross*largestDepthValue : nextFacadeDirection*largestDepthValue);
                                    AddPlane(w0, wA, w1, wB, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }
                                if (nextFacadeDesign != facadeDesign && !lastRow)//top
                                {
                                    Vector3 wA = w2 + ((!firstColumn) ? facadeCross*largestDepthValue : -lastFacadeDirection*largestDepthValue);
                                    Vector3 wB = w3 + ((!lastColumn) ? facadeCross*largestDepthValue : nextFacadeDirection*largestDepthValue);
                                    AddPlane(w3, wB, w2, wA, wallSubMesh, wallFlipped, Vector2.zero, UVEnd);
                                }

                                windowBase = w1;//move base vertor to next bay
                                facadeUV.x += bayWidthSize;
                                continue;//bay filled - move onto next bay
                            }

                            var verts = new Vector3[16];
                            verts[0] = windowBase;
                            verts[1] = verts[0] + leftWidth * facadeDirection;
                            verts[2] = verts[1] + openingWidth * facadeDirection;
                            verts[3] = verts[2] + rightWidth * facadeDirection;
                            windowBase = (nextBayIdentical) ? verts[2] : verts[3];//move to next window - if next design is identical - well add the two parts together the reduce polycount
                            facadeUV.x += (nextBayIdentical) ? openingWidth : openingWidth + rightWidth;

                            Vector3 rowBottomVector = Vector3.up * rowBottomHeight;
                            verts[4] = verts[0] + rowBottomVector;
                            verts[5] = verts[1] + rowBottomVector;
                            verts[6] = verts[2] + rowBottomVector;
                            verts[7] = verts[3] + rowBottomVector;

                            Vector3 openingVector = Vector3.up * openingHeight;
                            verts[8] = verts[4] + openingVector;
                            verts[9] = verts[5] + openingVector;
                            verts[10] = verts[6] + openingVector;
                            verts[11] = verts[7] + openingVector;

                            Vector3 rowTopVector = Vector3.up * rowTopHeight;
                            verts[12] = verts[8] + rowTopVector;
                            verts[13] = verts[9] + rowTopVector;
                            verts[14] = verts[10] + rowTopVector;
                            verts[15] = verts[11] + rowTopVector;

                            Vector3 openingDepthVector = facadeCross * bayStyle.openingDepth;
                            Vector3 crossDepthVector = facadeCross * bayStyle.crossDepth;
                            Vector3 rowDepthVector = facadeCross * bayStyle.rowDepth;
                            Vector3 columnDepthVector = facadeCross * bayStyle.columnDepth;
                            Vector3 largestDepthVector = facadeCross * largestDepthValue;
                            Vector2 uvStart, uvEnd;

                            int windowSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningBackTexture);
                            int submeshBottom = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningSillTexture);
                            int submeshTop = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningCeilingTexture);
                            int columnSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.ColumnTexture);
                            int crossSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.CrossTexture);
                            int rowSubMesh = bayStyle.GetTexture(BuildrBay.TextureNames.RowTexture);
                            bool windowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningBackTexture);
                            bool flippedBottom = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningSillTexture);
                            bool flippedTop = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningCeilingTexture);
                            bool columnFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.ColumnTexture);
                            bool crossFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.CrossTexture);
                            bool rowFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.RowTexture);
                            int windowBoxSubmesh = bayStyle.GetTexture(BuildrBay.TextureNames.OpeningSideTexture);
                            bool windowBoxFlipped = bayStyle.IsFlipped(BuildrBay.TextureNames.OpeningSideTexture);

                            ///WINDOWS
                            w0 = verts[5] + openingDepthVector;
                            w1 = verts[6] + openingDepthVector;
                            w2 = verts[9] + openingDepthVector;
                            w3 = verts[10] + openingDepthVector;
                            Vector2 windowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight);
                            Vector2 windowUVEnd = windowUVStart + new Vector2(openingWidth, openingHeight);
                            if (bayStyle.renderBack && !data.cullBays)
                                AddPlane(w0, w1, w2, w3, windowSubMesh, windowFlipped, windowUVStart, windowUVEnd);

                            //Window Sides
                            w0 = verts[5] + largestDepthVector;
                            w1 = verts[6] + largestDepthVector;
                            w2 = verts[9] + largestDepthVector;
                            w3 = verts[10] + largestDepthVector;
                            windowSideDepth = Mathf.Min(bayStyle.columnDepth, bayStyle.openingDepth) - largestDepthValue;//Window Left
                            float columnDiff = bayStyle.columnDepth - bayStyle.openingDepth;
                            if (data.renderInteriors)//Inner Window Walls
                            {
                                //left
                                uvStart = facadeUV + new Vector2(leftWidth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 leftDepthVector = facadeCross * windowSideDepth;
                                if (firstColumn) leftDepthVector = facadeCross * -largestDepthValue;
                                Vector3 wl0 = w0 + leftDepthVector;
                                Vector3 wl2 = w2 + leftDepthVector;
                                AddPlane(wl0, w0, wl2, w2, windowBoxSubmesh, windowBoxFlipped, uvStart, uvEnd);
                                //right
                                uvStart = facadeUV + new Vector2(leftWidth + openingWidth - windowSideDepth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 rightDepthVector = facadeCross * windowSideDepth;
                                if (lastColumn) rightDepthVector = facadeCross * -largestDepthValue;
                                Vector3 wr1 = w1 + rightDepthVector;
                                Vector3 wr3 = w3 + rightDepthVector;
                                AddPlane(wr3, w3, wr1, w1, windowBoxSubmesh, windowBoxFlipped, uvEnd, uvStart);
                            }

                            if (columnDiff > 0 || !data.renderInteriors)//External Window Sides
                            {
                                //left
                                uvStart = facadeUV + new Vector2(leftWidth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(columnDiff, openingHeight);
                                Vector3 sideDepthVectorA = facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                Vector3 sideDepthVectorB = facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                if (firstColumn) sideDepthVectorA = facadeCross * -largestDepthValue;
                                Vector3 wd0l = w0 + sideDepthVectorA;
                                Vector3 wd1l = w2 + sideDepthVectorA;
                                Vector3 wd2l = w0 + sideDepthVectorB;
                                Vector3 wd3l = w2 + sideDepthVectorB;
                                AddPlane(wd0l, wd2l, wd1l, wd3l, windowBoxSubmesh, windowBoxFlipped, uvStart, uvEnd);
                                //      right                          
                                uvStart = facadeUV + new Vector2(leftWidth + openingWidth - windowSideDepth, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                sideDepthVectorA = facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                sideDepthVectorB = facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                if (lastColumn) sideDepthVectorA = facadeCross * -largestDepthValue;
                                Vector3 wd0r = w1 + sideDepthVectorA;
                                Vector3 wd1r = w3 + sideDepthVectorA;
                                Vector3 wd2r = w1 + sideDepthVectorB;
                                Vector3 wd3r = w3 + sideDepthVectorB;
                                AddPlane(wd1r, wd3r, wd0r, wd2r, windowBoxSubmesh, windowBoxFlipped, uvStart, uvEnd);
                            }

                            //Window Row Sides/Sills
                            bottomDepth = Mathf.Min(bayStyle.rowDepth, bayStyle.openingDepth) - largestDepthValue;
                            float rowDiff = bayStyle.rowDepth - bayStyle.openingDepth;
                            if (data.renderInteriors)//Window Sill Interiors
                            {
                                uvStart = new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, bottomDepth);

//                                if (rowBottomHeight > 0)//Bottom
//                                {
                                    Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                    Vector3 wl0 = w0 + bottomDepthVector;
                                    Vector3 wl1 = w1 + bottomDepthVector;
                                    AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                }
//                                if (rowTopHeight > 0)//Top
//                                {
                                    Vector3 topDepthVector = facadeCross * bottomDepth;
                                    Vector3 wl2 = w2 + topDepthVector;
                                    Vector3 wl3 = w3 + topDepthVector;
                                    AddPlane(w2, w3, wl2, wl3, submeshTop, flippedTop, uvStart, uvEnd);
//                                }
                            }

                            if (rowDiff > 0 || !data.renderInteriors)//Window External Sills
                            {
                                uvStart = facadeUV + new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, rowDiff);

//                                if (rowBottomHeight > 0)//Bottom
//                                {
                                    Vector3 wd0l = w0 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd1l = w1 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd2l = w0 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    Vector3 wd3l = w1 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    AddPlane(wd0l, wd1l, wd2l, wd3l, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                }

//                                if (rowTopHeight > 0)//Top
//                                {
                                    Vector3 wd0r = w2 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd1r = w3 + facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    Vector3 wd2r = w2 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    Vector3 wd3r = w3 + facadeCross * (bayStyle.openingDepth - largestDepthValue);
                                    AddPlane(wd1r, wd0r, wd3r, wd2r, submeshTop, flippedTop, uvStart, uvEnd);
//                                }
                            }

                            ///COLUMNS
                            //Column Face
                            if (leftWidth > 0)//Column Face Left
                            {
                                Vector3 leftColumnDepthVector = (!firstColumn) ? columnDepthVector : Vector3.zero;
                                w0 = verts[4] + leftColumnDepthVector;
                                w1 = verts[5] + leftColumnDepthVector;
                                w2 = verts[8] + leftColumnDepthVector;
                                w3 = verts[9] + leftColumnDepthVector;
                                Vector2 leftColumnUVStart = facadeUV + new Vector2(0, rowBottomHeight);
                                Vector2 leftColumnUVEnd = leftColumnUVStart + new Vector2(leftWidth, openingHeight);
                                AddPlane(w0, w1, w2, w3, columnSubMesh, columnFlipped, leftColumnUVStart, leftColumnUVEnd);

                                if (!firstColumn)//Left Column Top Bottom
                                {
                                    w0 = verts[4] + largestDepthVector;
                                    w1 = verts[5] + largestDepthVector;
                                    w2 = verts[8] + largestDepthVector;
                                    w3 = verts[9] + largestDepthVector;

                                    bottomDepth = Mathf.Min(bayStyle.crossDepth, bayStyle.columnDepth) - largestDepthValue;
                                    float colDiff = bayStyle.crossDepth - bayStyle.columnDepth;
                                    if (bottomDepth != 0)
                                    {
                                        if (data.renderInteriors)
                                        {
                                            uvStart = new Vector2(0, 0);
                                            uvEnd = uvStart + new Vector2(leftWidth, bottomDepth);
                                            Vector3 bottomDepthVector = facadeCross * bottomDepth;
//                                            if(rowBottomHeight>0)
//                                            {
                                                Vector3 wl0 = w0 + bottomDepthVector;
                                                Vector3 wl1 = w1 + bottomDepthVector;
                                                AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                            }
//                                            if(rowTopHeight > 0)
//                                            {
                                                Vector3 wl2 = w2 + bottomDepthVector;
                                                Vector3 wl3 = w3 + bottomDepthVector;
                                                AddPlane(w2, w3, wl2, wl3, submeshTop, flippedTop, uvStart, uvEnd);
//                                            }
                                        }

                                        if (colDiff > 0 || !data.renderInteriors)
                                        {
                                            uvStart = new Vector2(0, rowBottomHeight);
                                            uvEnd = uvStart + new Vector2(rowDiff, openingHeight);
//                                            if(rowBottomHeight > 0)//Bottom
//                                            {
                                                Vector3 wd0l = w0 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1l = w1 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2l = w0 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3l = w1 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd2l, wd0l, wd3l, wd1l, submeshBottom, flippedBottom, uvStart, uvEnd);
//                                            }
//                                            if(rowTopHeight > 0)//Top
//                                            {
                                                Vector3 wd0r = w2 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1r = w3 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2r = w2 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3r = w3 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd3r, wd1r, wd2r, wd0r, submeshTop, flippedTop, uvStart, uvEnd);
//                                            }
                                        }
                                    }
                                }
                            }
                            if ((!nextBayIdentical || lastColumn) && rightWidth > 0)//Column Right
                            {
                                Vector3 rightColumeDepthVector = (!lastColumn) ? columnDepthVector : Vector3.zero;
                                w0 = verts[6] + rightColumeDepthVector;
                                w1 = verts[7] + rightColumeDepthVector;
                                w2 = verts[10] + rightColumeDepthVector;
                                w3 = verts[11] + rightColumeDepthVector;
                                Vector2 rightColumnUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight);
                                Vector2 rightColumnUVEnd = rightColumnUVStart + new Vector2(rightWidth, openingHeight);
                                AddPlane(w0, w1, w2, w3, columnSubMesh, columnFlipped, rightColumnUVStart, rightColumnUVEnd);
                                if (!lastColumn)//Right Column Top Bottom
                                {
                                    w0 = verts[6] + largestDepthVector;
                                    w1 = verts[7] + largestDepthVector;
                                    w2 = verts[10] + largestDepthVector;
                                    w3 = verts[11] + largestDepthVector;

                                    bottomDepth = Mathf.Min(bayStyle.crossDepth, bayStyle.columnDepth) - largestDepthValue;//Window Left
                                    float colDiff = bayStyle.crossDepth - bayStyle.columnDepth;
                                    if (bottomDepth != 0)
                                    {
                                        if (data.renderInteriors)
                                        {
                                            uvStart = new Vector2(leftWidth+openingWidth, 0);
                                            uvEnd = uvStart + new Vector2(rightWidth, bottomDepth);
                                            Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                            if (rowBottomHeight > 0)
                                            {
                                                Vector3 wl0 = w0 + bottomDepthVector;
                                                Vector3 wl1 = w1 + bottomDepthVector;
                                                AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                            }
                                            if (rowTopHeight > 0)
                                            {
                                                Vector3 wl2 = w2 + bottomDepthVector;
                                                Vector3 wl3 = w3 + bottomDepthVector;
                                                AddPlane(wl3, wl2, w3, w2, submeshTop, flippedTop, uvStart, uvEnd);
                                            }
                                        }

                                        if (colDiff > 0 || !data.renderInteriors)
                                        {
                                            uvStart = facadeUV + new Vector2(0, rowBottomHeight);
                                            uvEnd = uvStart + new Vector2(rowDiff, openingHeight);
                                            if (rowBottomHeight > 0)//Bottom
                                            {
                                                Vector3 wd0l = w0 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1l = w1 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2l = w0 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3l = w1 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd2l, wd0l, wd3l, wd1l, submeshBottom, flippedBottom, uvStart, uvEnd);
                                            }
                                            if (rowTopHeight > 0)//Top
                                            {
                                                Vector3 wd0r = w2 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd1r = w3 + facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                                Vector3 wd2r = w2 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                Vector3 wd3r = w3 + facadeCross * (bayStyle.columnDepth - largestDepthValue);
                                                AddPlane(wd3r, wd1r, wd2r, wd0r, submeshTop, flippedTop, uvStart, uvEnd);
                                            }
                                        }
                                    }
                                }
                            }

                            ///ROWS
                            //Row Bottom
                            w0 = verts[1] + rowDepthVector;
                            w1 = verts[2] + rowDepthVector;
                            w2 = verts[5] + rowDepthVector;
                            w3 = verts[6] + rowDepthVector;
                            if (rowBottomHeight > 0)
                            {
                                Vector2 bottomRowUVStart = facadeUV + new Vector2(leftWidth, 0);
                                Vector2 bottomRowUVEnd = bottomRowUVStart + new Vector2(openingWidth, rowBottomHeight);
                                AddPlane(w0, w1, w2, w3, rowSubMesh, rowFlipped, bottomRowUVStart, bottomRowUVEnd);

                                //Row Sides
                                w0 = verts[1] + largestDepthVector;
                                w1 = verts[2] + largestDepthVector;
                                w2 = verts[5] + largestDepthVector;
                                w3 = verts[6] + largestDepthVector;
                                uvStart = facadeUV + new Vector2(0, 0);
                                uvEnd = uvStart + new Vector2(largestDepthValue, rowBottomHeight);
                                if (leftWidth > 0)//Left Side
                                {
                                    Vector3 sideDepthVectorA = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorB = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if(firstColumn)
                                    {
                                        sideDepthVectorA = facadeCross * -largestDepthValue;
                                    }
//                                    uvEnd.x = largestDepthValue;//Vector3.Distance(sideDepthVectorA, sideDepthVectorB);
//                                    uvEnd.y = Vector3.Distance(sideDepthVectorA,sideDepthVectorB);
                                    Vector3 wd0l = w0 + sideDepthVectorA;
                                    Vector3 wd1l = w2 + sideDepthVectorA;
                                    Vector3 wd2l = w0 + sideDepthVectorB;
                                    Vector3 wd3l = w2 + sideDepthVectorB;
                                    AddPlane(wd0l, wd2l, wd1l, wd3l, rowSubMesh, rowFlipped, uvStart, uvEnd);
                                }

//                                if (rightWidth > 0)//Right Side
//                                {
                                    Vector3 sideDepthVectorC = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorD = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if (lastColumn) sideDepthVectorC = facadeCross * -largestDepthValue;
                                    Vector3 wd0r = w1 + sideDepthVectorC;
                                    Vector3 wd1r = w3 + sideDepthVectorC;
                                    Vector3 wd2r = w1 + sideDepthVectorD;
                                    Vector3 wd3r = w3 + sideDepthVectorD;
                                    AddPlane(wd1r, wd3r, wd0r, wd2r, rowSubMesh, rowFlipped, uvStart, uvEnd);
//                                }
                            }

                            //Row Top
                            w0 = verts[9] + rowDepthVector;
                            w1 = verts[10] + rowDepthVector;
                            w2 = verts[13] + rowDepthVector;
                            w3 = verts[14] + rowDepthVector;

                            if (rowTopHeight > 0)
                            {
                                Vector2 topRowUVStart = facadeUV + new Vector2(leftWidth, rowBottomHeight + openingHeight);
                                Vector2 topRowUVEnd = topRowUVStart + new Vector2(openingWidth, rowTopHeight);
                                AddPlane(w0, w1, w2, w3, rowSubMesh, rowFlipped, topRowUVStart, topRowUVEnd);

                                //Row Sides
                                w0 = verts[9] + largestDepthVector;
                                w1 = verts[10] + largestDepthVector;
                                w2 = verts[13] + largestDepthVector;
                                w3 = verts[14] + largestDepthVector;
                                uvStart = facadeUV + new Vector2(0, rowBottomHeight+openingHeight);
                                uvEnd = uvStart + new Vector2(largestDepthValue, rowTopHeight);
                                if (leftWidth > 0)//Left Side
                                {
                                    Vector3 sideDepthVectorA = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorB = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if (firstColumn) sideDepthVectorA = facadeCross * -largestDepthValue;
                                    Vector3 wd0l = w0 + sideDepthVectorA;
                                    Vector3 wd1l = w2 + sideDepthVectorA;
                                    Vector3 wd2l = w0 + sideDepthVectorB;
                                    Vector3 wd3l = w2 + sideDepthVectorB;
                                    AddPlane(wd0l, wd2l, wd1l, wd3l, rowSubMesh, rowFlipped, uvStart, uvEnd);
                                }

//                                if (rightWidth > 0)//Right Side
//                                {
                                    Vector3 sideDepthVectorC = facadeCross * (bayStyle.crossDepth - largestDepthValue);
                                    Vector3 sideDepthVectorD = facadeCross * (bayStyle.rowDepth - largestDepthValue);
                                    if (lastColumn) sideDepthVectorC = facadeCross * -largestDepthValue;
                                    Vector3 wd0r = w1 + sideDepthVectorC;
                                    Vector3 wd1r = w3 + sideDepthVectorC;
                                    Vector3 wd2r = w1 + sideDepthVectorD;
                                    Vector3 wd3r = w3 + sideDepthVectorD;
                                    AddPlane(wd1r, wd3r, wd0r, wd2r, rowSubMesh, rowFlipped, uvStart, uvEnd);
//                                }
                            }

                            //Cross Left Bottom
                            Vector3 leftCrossDepthVector = (!firstColumn) ? crossDepthVector : Vector3.zero;
                            w0 = verts[0] + leftCrossDepthVector;
                            w1 = verts[1] + leftCrossDepthVector;
                            w2 = verts[4] + leftCrossDepthVector;
                            w3 = verts[5] + leftCrossDepthVector;
                            Vector2 crossLBUVStart = facadeUV + new Vector2(0, 0);
                            Vector2 crossLBUVEnd = crossLBUVStart + new Vector2(leftWidth, rowBottomHeight);
                            AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossLBUVStart, crossLBUVEnd);
                           
                            //Cross Left Top
                            if (rowTopHeight > 0)
                            {
                                w0 = verts[8] + leftCrossDepthVector;
                                w1 = verts[9] + leftCrossDepthVector;
                                w2 = verts[12] + leftCrossDepthVector;
                                w3 = verts[13] + leftCrossDepthVector;
                                Vector2 crossLTUVStart = facadeUV + new Vector2(0, rowBottomHeight + openingHeight);
                                Vector2 crossLTUVEnd = crossLTUVStart + new Vector2(leftWidth, rowTopHeight);
                                AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossLTUVStart, crossLTUVEnd);
                            }

                            if ((!nextBayIdentical || lastColumn) && rightWidth > 0)
                            {
                                if(lastColumn) crossDepthVector = Vector3.zero;//zero the ends of buildings
                                //Cross Right Bottom
                                w0 = verts[2] + crossDepthVector;
                                w1 = verts[3] + crossDepthVector;
                                w2 = verts[6] + crossDepthVector;
                                w3 = verts[7] + crossDepthVector;
                                Vector2 crossRBUVStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                                Vector2 crossRBUVEnd = crossRBUVStart + new Vector2(rightWidth, rowBottomHeight);
                                AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossRBUVStart, crossRBUVEnd);

                                //Cross Right Top
                                if (rowTopHeight > 0)
                                {
                                    w0 = verts[10] + crossDepthVector;
                                    w1 = verts[11] + crossDepthVector;
                                    w2 = verts[14] + crossDepthVector;
                                    w3 = verts[15] + crossDepthVector;
                                    Vector2 crossRTUVStart = facadeUV + new Vector2(leftWidth + openingWidth, rowBottomHeight + openingHeight);
                                    Vector2 crossRTUVEnd = crossRTUVStart + new Vector2(rightWidth, rowTopHeight);
                                    AddPlane(w0, w1, w2, w3, crossSubMesh, crossFlipped, crossRTUVStart, crossRTUVEnd);
                                }
                            }

                            ///FACADE BOTTOMS
                            if (lastFacadeDesign != facadeDesign && rowBottomHeight > 0)
                            {
                                //Row Bottom
                                w0 = verts[1] + largestDepthVector;
                                w1 = verts[2] + largestDepthVector;

                                bottomDepth = bayStyle.rowDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, bottomDepth);

                                Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                Vector3 wl0 = w0 + bottomDepthVector;
                                Vector3 wl1 = w1 + bottomDepthVector;
                                AddPlane(w0, w1, wl0, wl1, submeshBottom, flippedBottom, uvStart, uvEnd);

                                if(!firstColumn)
                                {
                                    //Left Cross Bottom
                                    w0 = verts[0] + largestDepthVector;
                                    w1 = verts[1] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(leftWidth, bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(w0, w1, wl0, wl1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }

                                //Right Cross Bottom
                                if ((!nextBayIdentical && !lastColumn) && rightWidth > 0)
                                {
                                    w0 = verts[2] + largestDepthVector;
                                    w1 = verts[3] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(leftWidth + openingWidth, 0);
                                    uvEnd = uvStart + new Vector2(rightWidth, bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(w0, w1, wl0, wl1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }
                            }


                            ///FACADE TOPS
                            if (nextFacadeDesign != facadeDesign && rowTopHeight > 0)
                            {
                                //Row Top
                                w0 = verts[13] + largestDepthVector;
                                w1 = verts[14] + largestDepthVector;

                                bottomDepth = bayStyle.rowDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(leftWidth, 0);
                                uvEnd = uvStart + new Vector2(openingWidth, bottomDepth);

                                Vector3 bottomDepthVector = facadeCross * bottomDepth;
                                Vector3 wl0 = w0 + bottomDepthVector;
                                Vector3 wl1 = w1 + bottomDepthVector;
                                AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);

                                //Left Cross Top
                                if (!firstColumn)
                                {
                                    w0 = verts[12] + largestDepthVector;
                                    w1 = verts[13] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(leftWidth,bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }

                                //Right Cross Top
                                if ((!nextBayIdentical && !lastColumn) && rightWidth > 0)
                                {
                                    w0 = verts[14] + largestDepthVector;
                                    w1 = verts[15] + largestDepthVector;

                                    bottomDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(leftWidth+openingWidth, 0);
                                    uvEnd = uvStart + new Vector2(rightWidth, bottomDepth);

                                    bottomDepthVector = facadeCross * bottomDepth;
                                    wl0 = w0 + bottomDepthVector;
                                    wl1 = w1 + bottomDepthVector;
                                    AddPlane(wl0, wl1, w0, w1, submeshBottom, flippedBottom, uvStart, uvEnd);
                                }
                            }

                            ///BAY SIDES
                            // LEFT
                            if(!previousBayIdentical)
                            {
                                //Column
                                w1 = verts[4] + largestDepthVector;
                                w3 = verts[8] + largestDepthVector;
                                windowSideDepth = bayStyle.columnDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 depthVector = facadeCross * windowSideDepth;
                                Vector3 wr1 = w1 + depthVector;
                                Vector3 wr3 = w3 + depthVector;
                                AddPlane(wr3, w3, wr1, w1, columnSubMesh, columnFlipped, uvStart, uvEnd);

                                //Cross Bottom
                                w1 = verts[0] + largestDepthVector;
                                w3 = verts[4] + largestDepthVector;
                                windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, 0);
                                uvEnd = uvStart + new Vector2(windowSideDepth, rowBottomHeight);
                                depthVector = facadeCross * windowSideDepth;
                                wr1 = w1 + depthVector;
                                wr3 = w3 + depthVector;
                                AddPlane(wr3, w3, wr1, w1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                //Cross Top
                                if (rowTopHeight > 0)
                                {
                                    w1 = verts[8] + largestDepthVector;
                                    w3 = verts[12] + largestDepthVector;
                                    windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(windowSideDepth, rowTopHeight);
                                    depthVector = facadeCross * windowSideDepth;
                                    wr1 = w1 + depthVector;
                                    wr3 = w3 + depthVector;
                                    AddPlane(wr3, w3, wr1, w1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                }
                            }

                            //RIGHT
                            if (!nextBayIdentical && !lastColumn)
                            {
                                //Column Sides
                                w1 = verts[7] + largestDepthVector;
                                w3 = verts[11] + largestDepthVector;
                                windowSideDepth = bayStyle.columnDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, rowBottomHeight);
                                uvEnd = uvStart + new Vector2(windowSideDepth, openingHeight);
                                Vector3 depthVector = facadeCross * windowSideDepth;
                                Vector3 wr1 = w1 + depthVector;
                                Vector3 wr3 = w3 + depthVector;
                                AddPlane(w3, wr3, w1, wr1, columnSubMesh, columnFlipped, uvStart, uvEnd);

                                //Cross Bottom
                                w1 = verts[3] + largestDepthVector;
                                w3 = verts[7] + largestDepthVector;
                                windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                uvStart = facadeUV + new Vector2(0, 0);
                                uvEnd = uvStart + new Vector2(windowSideDepth, rowBottomHeight);
                                depthVector = facadeCross * windowSideDepth;
                                wr1 = w1 + depthVector;
                                wr3 = w3 + depthVector;
                                AddPlane(w3, wr3, w1, wr1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                //Cross Top
                                if (rowTopHeight > 0)
                                {
                                    w1 = verts[11] + largestDepthVector;
                                    w3 = verts[15] + largestDepthVector;
                                    windowSideDepth = bayStyle.crossDepth - largestDepthValue;
                                    uvStart = facadeUV + new Vector2(0, 0);
                                    uvEnd = uvStart + new Vector2(windowSideDepth, rowTopHeight);
                                    depthVector = facadeCross * windowSideDepth;
                                    wr1 = w1 + depthVector;
                                    wr3 = w3 + depthVector;
                                    AddPlane(w3, wr3, w1, wr1, crossSubMesh, crossFlipped, uvStart, uvEnd);
                                }
                            }
                        }
                    }
                    else
                    {
                        // windowless wall
                        Vector3 wallVector = (facadeDirection * (facadeWidth+largestDepthValue*2.0f));
                        Vector3 wallHeightVector = Vector3.up * floorHeight;
                        Vector3 w0 = facadeFloorBaseVector;
                        Vector3 w1 = facadeFloorBaseVector + wallVector;
                        Vector3 w2 = facadeFloorBaseVector + wallHeightVector;
                        Vector3 w3 = facadeFloorBaseVector + wallVector + wallHeightVector;
                        int wallSubmesh = facadeDesign.simpleBay.GetTexture(BuildrBay.TextureNames.WallTexture);
                        bool flipped = facadeDesign.simpleBay.IsFlipped(BuildrBay.TextureNames.WallTexture);
                        Vector2 wallUVStart = facadeUV;
                        Vector2 wallUVEnd = facadeUV + new Vector2(realFadeWidth, floorHeight);
                        AddPlane(w0, w1, w2, w3, wallSubmesh, flipped, wallUVStart, wallUVEnd);//face

                        if (nextFacadeDesign.hasWindows && !lastRow)
                        {
                            Vector3 wl2 = w2 - lastFacadeDirection*largestDepthValue;
                            Vector3 wl3 = w3 + nextFacadeDirection*largestDepthValue;
                            Vector2 uvEnd = new Vector2(facadeWidth, 1);
                            AddPlane(w3, wl3, w2, wl2, wallSubmesh, flipped, wallUVStart, uvEnd);//top
                        }
                    }
                }
            }
            //Bottom of the mesh - it's mostly to ensure the model can render certain shadows correctly
            if (data.drawUnderside)
            {
                Vector3 foundationDrop = Vector3.down * data.foundationHeight;
                var newEndVerts = new Vector3[numberOfVolumePoints];
                var newEndUVs = new Vector2[numberOfVolumePoints];
                for (int i = 0; i < numberOfVolumePoints; i++)
                {
                    newEndVerts[i] = plan.points[volume.points[i]].vector3 + foundationDrop;
                    newEndUVs[i] = Vector2.zero;
                }
                var tris = new List<int>(data.plan.GetTrianglesBySectorBase(v));
                tris.Reverse();
                int bottomSubMesh = facadeDesign.GetTexture(BuildrFacadeDesign.textureNames.columnTexture);
                mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), bottomSubMesh);
            }
        }
        data = null;
        mesh = null;
        textures = null;
    }
예제 #7
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
        data = _data;
        mesh = _mesh;
        BuildrPlan plan = data.plan;

        int facadeIndex = 0;
        int numberOfVolumes = data.plan.numberOfVolumes;
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int numberOfVolumePoints = volume.points.Count;
            Vector3[] newEndVerts = new Vector3[numberOfVolumePoints];
            Vector2[] newEndUVs = new Vector2[numberOfVolumePoints];
            Vector3 volumeHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight);
            for (int i = 0; i < numberOfVolumePoints; i++)
            {
                newEndVerts[i] = plan.points[volume.points[i]].vector3 + volumeHeight;
                newEndUVs[i] = Vector2.zero;
            }

            List<int> tris = new List<int>(data.plan.GetTrianglesBySectorBase(s));
            mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0);
        }
        //Build ROOF

        //Build facades
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                    continue;

                int indexA = f;
                int indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector3 p0 = plan.points[volume.points[indexA]].vector3;
                Vector3 p1 = plan.points[volume.points[indexB]].vector3;

                int floorBase = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                Vector3 wallHeight = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart;
                float facadeWidth = Vector3.Distance(p0, p1);


                p0 += floorHeightStart;
                p1 += floorHeightStart;

                Vector3 w0 = p0;
                Vector3 w1 = p1;
                Vector3 w2 = w0 + wallHeight;
                Vector3 w3 = w1 + wallHeight;

                Vector2 uvMin = new Vector2(0, 0);
                Vector2 uvMax = new Vector2(facadeWidth, floorHeight);

                mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0);
                facadeIndex++;
            }
        }

        data = null;
        mesh = null;
    }
예제 #8
0
    private static void BuildSimple(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
        BuildrData data = _data;
        DynamicMeshGenericMultiMaterialMesh mesh = _mesh;
        BuildrPlan plan = data.plan;

        int facadeIndex     = 0;
        int numberOfVolumes = data.plan.numberOfVolumes;

        //Build Floor
        if (data.drawUnderside)
        {
            for (int s = 0; s < numberOfVolumes; s++)
            {
                BuildrVolume volume = plan.volumes[s];
                int          numberOfVolumePoints = volume.points.Count;
                Vector3[]    newEndVerts          = new Vector3[numberOfVolumePoints];
                Vector2[]    newEndUVs            = new Vector2[numberOfVolumePoints];
                for (int i = 0; i < numberOfVolumePoints; i++)
                {
                    newEndVerts[i] = plan.points[volume.points[i]].vector3;
                    newEndUVs[i]   = Vector2.zero;
                }

                List <int> tris = new List <int>(data.plan.GetTrianglesBySectorBase(s));
                tris.Reverse();
                mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0);
            }
        }

        //Build ROOF
        DynamicMeshGenericMultiMaterialMesh dynMeshRoof = new DynamicMeshGenericMultiMaterialMesh();

        dynMeshRoof.subMeshCount = data.textures.Count;
        BuildrRoof.Build(dynMeshRoof, data, true);
        mesh.AddData(dynMeshRoof.vertices, dynMeshRoof.uv, dynMeshRoof.triangles, 0);

        Vector3 foundationVector = Vector3.down * data.foundationHeight;

        //Build facades
        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int          numberOfVolumePoints = volume.points.Count;

            for (int l = 0; l < numberOfVolumePoints; l++)
            {
                int     indexA = l;
                int     indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0;
                Vector3 p0     = plan.points[volume.points[indexA]].vector3;
                Vector3 p1     = plan.points[volume.points[indexB]].vector3;

                int floorBase      = plan.GetFacadeFloorHeight(s, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                Vector3 wallHeight       = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart;

                p0 += floorHeightStart;
                p1 += floorHeightStart;

                Vector3 w0 = p0;
                Vector3 w1 = p1;
                Vector3 w2 = w0 + wallHeight;
                Vector3 w3 = w1 + wallHeight;

                if (floorBase == 0)
                {
                    w0 += foundationVector;
                    w1 += foundationVector;
                }

                mesh.AddPlane(w0, w1, w2, w3, Vector2.zero, Vector2.zero, 0);
                facadeIndex++;
            }
        }

        data = null;
        mesh = null;
    }
예제 #9
0
    public static void Build(DynamicMeshGenericMultiMaterialMesh _mesh, BuildrData _data)
    {
        data = _data;
        mesh = _mesh;
        BuildrPlan plan = data.plan;

        int facadeIndex     = 0;
        int numberOfVolumes = data.plan.numberOfVolumes;

        for (int s = 0; s < numberOfVolumes; s++)
        {
            BuildrVolume volume = plan.volumes[s];
            int          numberOfVolumePoints = volume.points.Count;
            Vector3[]    newEndVerts          = new Vector3[numberOfVolumePoints];
            Vector2[]    newEndUVs            = new Vector2[numberOfVolumePoints];
            Vector3      volumeHeight         = Vector3.up * (volume.numberOfFloors * data.floorHeight);
            for (int i = 0; i < numberOfVolumePoints; i++)
            {
                newEndVerts[i] = plan.points[volume.points[i]].vector3 + volumeHeight;
                newEndUVs[i]   = Vector2.zero;
            }

            List <int> tris = new List <int>(data.plan.GetTrianglesBySectorBase(s));
            mesh.AddData(newEndVerts, newEndUVs, tris.ToArray(), 0);
        }
        //Build ROOF

        //Build facades
        for (int v = 0; v < numberOfVolumes; v++)
        {
            BuildrVolume volume = plan.volumes[v];
            int          numberOfVolumePoints = volume.points.Count;

            for (int f = 0; f < numberOfVolumePoints; f++)
            {
                if (!volume.renderFacade[f])
                {
                    continue;
                }

                int     indexA = f;
                int     indexB = (f < numberOfVolumePoints - 1) ? f + 1 : 0;
                Vector3 p0     = plan.points[volume.points[indexA]].vector3;
                Vector3 p1     = plan.points[volume.points[indexB]].vector3;

                int floorBase      = plan.GetFacadeFloorHeight(v, volume.points[indexA], volume.points[indexB]);
                int numberOfFloors = volume.numberOfFloors - floorBase;
                if (numberOfFloors < 1)
                {
                    //no facade - adjacent facade is taller and covers this one
                    continue;
                }
                float floorHeight = data.floorHeight;

                Vector3 floorHeightStart = Vector3.up * (floorBase * floorHeight);
                Vector3 wallHeight       = Vector3.up * (volume.numberOfFloors * floorHeight) - floorHeightStart;
                float   facadeWidth      = Vector3.Distance(p0, p1);


                p0 += floorHeightStart;
                p1 += floorHeightStart;

                Vector3 w0 = p0;
                Vector3 w1 = p1;
                Vector3 w2 = w0 + wallHeight;
                Vector3 w3 = w1 + wallHeight;

                Vector2 uvMin = new Vector2(0, 0);
                Vector2 uvMax = new Vector2(facadeWidth, floorHeight);

                mesh.AddPlane(w0, w1, w2, w3, uvMin, uvMax, 0);
                facadeIndex++;
            }
        }

        data = null;
        mesh = null;
    }
예제 #10
0
    private static void Mansard(BuildrVolume volume, BuildrRoofDesign design)
    {
        BuildrPlan area = data.plan;
        int numberOfVolumePoints = volume.points.Count;
        int numberOfFloors = volume.numberOfFloors;
        float floorHeight = data.floorHeight;
        Vector3 volumeFloorHeight = Vector3.up * (numberOfFloors * floorHeight);

        //add top base of the flat roof
        Vector3[] topVerts = new Vector3[numberOfVolumePoints];
        Vector2[] topUVs = new Vector2[numberOfVolumePoints];
        int topTextureID = design.GetTexture(BuildrRoofDesign.textureNames.floorB);
        BuildrTexture texture = textures[topTextureID];

        for (int l = 0; l < numberOfVolumePoints; l++)
        {
            int indexA, indexB, indexA0, indexB0;
            Vector3 p0, p1, p00, p10;
            indexA = l;
            indexB = (l < numberOfVolumePoints - 1) ? l + 1 : 0;
            indexA0 = (l > 0) ? l - 1 : numberOfVolumePoints - 1;
            indexB0 = (l < numberOfVolumePoints - 2) ? l + 2 : l + 2 - numberOfVolumePoints;

            p0 = area.points[volume.points[indexA]].vector3;
            p1 = area.points[volume.points[indexB]].vector3;
            p00 = area.points[volume.points[indexA0]].vector3;
            p10 = area.points[volume.points[indexB0]].vector3;

            float facadeWidth = Vector3.Distance(p0, p1);
            Vector3 facadeDirection = (p1 - p0).normalized;
            Vector3 facadeDirectionLeft = (p0 - p00).normalized;
            Vector3 facadeDirectionRight = (p10 - p1).normalized;
            Vector3 facadeNormal = Vector3.Cross(facadeDirection, Vector3.up);
            Vector3 facadeNormalLeft = Vector3.Cross(facadeDirectionLeft, Vector3.up);
            Vector3 facadeNormalRight = Vector3.Cross(facadeDirectionRight, Vector3.up);

            float roofHeight = design.height;
            float baseDepth = design.floorDepth;
            float cornerLeftRad = Vector3.Angle(facadeDirection, -facadeDirectionLeft) * Mathf.Deg2Rad / 2;
            float cornerRightRad = Vector3.Angle(-facadeDirection, facadeDirectionRight) * Mathf.Deg2Rad / 2;
            float cornerDepthLeft = baseDepth / Mathf.Sin(cornerLeftRad);
            float cornerDepthRight = baseDepth / Mathf.Sin(cornerRightRad);
            float topDepth = design.depth;
            float cornerTopDepthLeft = topDepth / Mathf.Sin(cornerLeftRad);
            float cornerTopDepthRight = topDepth / Mathf.Sin(cornerRightRad);

            Vector3 pr = facadeDirection * facadeWidth;

            Vector3 leftDir = (facadeNormal + facadeNormalLeft).normalized;
            Vector3 rightDir = (facadeNormal + facadeNormalRight).normalized;

            p0 += volumeFloorHeight;
            p1 += volumeFloorHeight;

            Vector3 w0, w1, w2, w3, w4, w5;
            w0 = p0;
            w1 = p0 + pr;
            w2 = w0 + leftDir * cornerDepthLeft;
            w3 = w1 + rightDir * cornerDepthRight;
            w4 = w2 + leftDir * cornerTopDepthLeft + Vector3.up * roofHeight;
            w5 = w3 + rightDir * cornerTopDepthRight + Vector3.up * roofHeight;

            Vector3[] verts = new Vector3[6] { w0, w1, w2, w3, w4, w5 };
//            List<Vector2> uvs = new List<Vector2>();

            Vector2[] uvsFloor = BuildrProjectUVs.Project(new Vector3[4] { w0, w1, w2, w3 }, Vector2.zero, facadeNormal);
            if(baseDepth == 0)
                uvsFloor[3].x = facadeWidth;
            Vector2[] uvsMansard = BuildrProjectUVs.Project(new Vector3[3] { w2, w4, w5 }, uvsFloor[2], facadeNormal);

            Vector3[] vertsA = new Vector3[4] { verts[0], verts[1], verts[2], verts[3] };
            Vector2[] uvsA = new Vector2[4] { uvsFloor[0], uvsFloor[1], uvsFloor[2], uvsFloor[3] };
            int[] trisA = new int[6] { 1, 0, 2, 1, 2, 3 };
            int subMeshA = design.GetTexture(BuildrRoofDesign.textureNames.floor);
            mesh.AddData(vertsA, uvsA, trisA, subMeshA);

            Vector3[] vertsB = new Vector3[4] { verts[2], verts[3], verts[4], verts[5] };
            Vector2[] uvsB = new Vector2[4] { uvsFloor[2], uvsFloor[3], uvsMansard[1], uvsMansard[2] };
            int[] trisB = new int[6] { 0, 2, 1, 1, 2, 3 };
            int subMeshB = design.GetTexture(BuildrRoofDesign.textureNames.tiles);
            mesh.AddData(vertsB, uvsB, trisB, subMeshB);

            //modify point for the top geometry
            Vector2z point = area.points[volume.points[l]];
            topVerts[l] = point.vector3 + volumeFloorHeight + Vector3.up * roofHeight + leftDir * (cornerDepthLeft + cornerTopDepthLeft);
            topUVs[l] = new Vector2(topVerts[l].x / texture.textureUnitSize.x, topVerts[l].z / texture.textureUnitSize.y);
        }

        Vector2z[] topVertV2z = new Vector2z[topVerts.Length];
        for (int i = 0; i < topVerts.Length; i++)
            topVertV2z[i] = new Vector2z(topVerts[i]);
        int[] topTris = EarClipper.Triangulate(topVertV2z);
        AddData(topVerts, topUVs, topTris, topTextureID);//top
    }
예제 #11
0
    /// <summary>
    /// Generate the detail meshes and return the export object
    /// </summary>
    /// <param name="mesh"></param>
    /// <param name="data"></param>
    /// <returns></returns>
    public static BuildrDetailExportObject Build(DynamicMeshGenericMultiMaterialMesh mesh, BuildrData data)
    {
        BuildrDetailExportObject exportObject   = new BuildrDetailExportObject();
        List <Texture2D>         detailTextures = new List <Texture2D>();
        List <int> detailSubmeshesWithTextures  = new List <int>();
        int        numberOfDetails = data.details.Count;

        mesh.Clear();
        mesh.subMeshCount = numberOfDetails;

        for (int d = 0; d < numberOfDetails; d++)
        {
            BuildrDetail detail = data.details[d];
            if (detail.mesh == null)
            {
                continue;
            }
            int        faceIndex       = detail.face;
            Vector3    position        = Vector3.zero;
            BuildrPlan plan            = data.plan;
            int        numberOfVolumes = plan.numberOfVolumes;
            Vector2    faceUv          = detail.faceUv;
            Quaternion faceAngle       = Quaternion.identity;
            //Place the detail mesh
            if (detail.type == BuildrDetail.Types.Facade)
            {
                //find facade
                int  facadeCount = 0;
                bool facadeFound = false;
                for (int s = 0; s < numberOfVolumes; s++)
                {
                    BuildrVolume volume = plan.volumes[s];
                    int          numberOfVolumePoints = volume.points.Count;
                    for (int p = 0; p < numberOfVolumePoints; p++)
                    {
                        if (facadeCount == faceIndex)
                        {
                            int     indexA       = p;
                            int     indexB       = (p + 1) % numberOfVolumePoints;
                            Vector3 p0           = plan.points[volume.points[indexA]].vector3;
                            Vector3 p1           = plan.points[volume.points[indexB]].vector3;
                            Vector3 basePosition = Vector3.Lerp(p0, p1, faceUv.x);
                            Vector3 detailHeight = Vector3.up * (volume.numberOfFloors * data.floorHeight * faceUv.y);
                            Vector3 facadeCross  = Vector3.Cross(Vector3.up, p1 - p0).normalized;
                            Vector3 detailDepth  = facadeCross * detail.faceHeight;
                            faceAngle   = Quaternion.LookRotation(facadeCross);
                            position    = basePosition + detailHeight + detailDepth;
                            facadeFound = true;
                            break;
                        }
                        facadeCount++;
                    }
                    if (facadeFound)
                    {
                        break;
                    }
                }
            }
            else//roof detail
            {
                BuildrVolume volume = plan.volumes[Mathf.Clamp(0, numberOfVolumes - 1, faceIndex)];
                int          numberOfVolumePoints = volume.points.Count;
                Vector3      minimumRoofPoint     = plan.points[volume.points[0]].vector3;
                Vector3      maximumRoofPoint     = minimumRoofPoint;
                for (int p = 1; p < numberOfVolumePoints; p++)
                {
                    Vector3 p0 = plan.points[volume.points[p]].vector3;
                    if (p0.x < minimumRoofPoint.x)
                    {
                        minimumRoofPoint.x = p0.x;
                    }
                    if (p0.z < minimumRoofPoint.y)
                    {
                        minimumRoofPoint.y = p0.z;
                    }
                    if (p0.x > maximumRoofPoint.x)
                    {
                        maximumRoofPoint.x = p0.x;
                    }
                    if (p0.z > maximumRoofPoint.y)
                    {
                        maximumRoofPoint.y = p0.z;
                    }
                }
                position.x = Mathf.Lerp(minimumRoofPoint.x, maximumRoofPoint.x, faceUv.x);
                position.z = Mathf.Lerp(minimumRoofPoint.y, maximumRoofPoint.y, faceUv.y);
                position.y = volume.numberOfFloors * data.floorHeight + detail.faceHeight;
            }

            Quaternion userRotation = Quaternion.Euler(detail.userRotation);
            int        vertexCount  = detail.mesh.vertexCount;
            Vector3[]  verts        = new Vector3[vertexCount];
            Quaternion rotate       = faceAngle * userRotation;
            for (int i = 0; i < vertexCount; i++)
            {
                Vector3 sourceVertex = Vector3.Scale(detail.mesh.vertices[i], detail.scale);
                Vector3 outputVertex = (rotate) * sourceVertex + position;
                verts[i] = outputVertex;
            }
            mesh.AddData(verts, detail.mesh.uv, detail.mesh.triangles, d);
            detail.worldPosition = position;
            detail.worldRotation = rotate;

            if (detail.material.mainTexture != null)
            {
#if UNITY_EDITOR
                string          texturePath     = AssetDatabase.GetAssetPath(detail.material.mainTexture);
                TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(texturePath);

                if (!textureImporter.isReadable)
                {
                    Debug.LogWarning("The texture you have selected is not readable. Cannot render");
                    return(exportObject);
                }

                detailTextures.Add((Texture2D)detail.material.mainTexture);
                detailSubmeshesWithTextures.Add(d);
#endif
            }
        }

        if (detailtexture != null)
        {
            Object.DestroyImmediate(detailtexture);
        }

        List <Mesh> outputMeshes = new List <Mesh>();
        if (detailSubmeshesWithTextures.Count > 0)
        {
            Rect[] textureRects = BuildrTexturePacker2.Pack(out detailtexture, detailTextures.ToArray(), 512);
            if (detailSubmeshesWithTextures.Count > 0)
            {
                mesh.Atlas(detailSubmeshesWithTextures.ToArray(), textureRects);
            }
            mesh.CollapseSubmeshes();
            mesh.Build();
            int numberOfMeshes = mesh.meshCount;
            for (int i = 0; i < numberOfMeshes; i++)
            {
                outputMeshes.Add(mesh[i].mesh);
            }
        }

        exportObject.detailMeshes = outputMeshes.ToArray();
        exportObject.texture      = detailtexture;
        return(exportObject);

        /*if (detailMat == null)
         *      detailMat = new Material(Shader.Find("Diffuse"));
         *  detailMat.mainTexture = detailtexture;
         *  List<Mesh> outputMeshes = new List<Mesh>();
         *  for (int i = 0; i < numberOfMeshes; i++)
         *  {
         *      outputMeshes.Add(mesh[i].mesh);
         *      GameObject details = new GameObject("details " + i);
         *      details.AddComponent<MeshFilter>().mesh = mesh[i].mesh;
         *      details.AddComponent<MeshRenderer>().sharedMaterial = detailMat;
         *      detailGameobjects.Add(details);
         *  }
         * }
         * //        Debug.Log("BuildR Detail Pack Complete: " + (Time.realtimeSinceStartup - timestart) + " sec");
         * return detailGameobjects.ToArray();*/
    }