private static void ToMesh(ref BuildRMesh mesh, Vector2[] points, float height, int[] facadeIndices, IVolume volume, int submesh, Surface surface) { int vertCount = points.Length; Vector3[] verts = new Vector3[vertCount]; for (int i = 0; i < vertCount; i++) { verts[i] = new Vector3(points[i].x, height, points[i].y); } Vector2[] uvs = new Vector2[vertCount]; Vector3[] normals = new Vector3[vertCount]; Vector4[] tangents = new Vector4[vertCount]; Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); for (int v = 0; v < vertCount; v++) { if (surface != null) { uvs[v] = surface.CalculateUV(points[v]); } normals[v] = Vector3.up; tangents[v] = tangent; } // int[] topTris = EarClipper.Triangulate(points); int[] topTris = Poly2TriWrapper.Triangulate(points, true); mesh.AddData(verts, uvs, topTris, normals, tangents, submesh); }
private static Vector2 CalculateUv(Vector2 uv, Surface surface) { if (surface != null) { return(surface.CalculateUV(uv)); } return(uv); }
private static Vector2 CalculateUV(Surface surface, Vector2 uv) { if (surface == null) { return(uv); } return(surface.CalculateUV(uv)); }
public static void Generate(ref BuildRMesh mesh, Gable design, Vector3 p0, Vector3 p1, float height, float thickness, Vector2 baseUV) { int gableSectionCount = design.count; Vector2 designSize = new Vector2(); for (int g = 0; g < gableSectionCount; g++) { designSize += design[g].GetSize(); } Vector2 actualSize = new Vector2(Vector3.Distance(p0, p1), height); Vector2 designScale = new Vector2((actualSize.x / 2) / designSize.x, actualSize.y / designSize.y); Vector2 basePosition = Vector2.zero; Vector3 facadeVector = p1 - p0; Vector3 facadeDirection = facadeVector.normalized; float facadeWidth = facadeVector.magnitude; Vector3 facadeNormal = Vector3.Cross(Vector3.up, facadeDirection); Vector4 facadeTangentForward = BuildRMesh.CalculateTangent(facadeDirection); Vector4 facadeTangentLeft = BuildRMesh.CalculateTangent(facadeNormal); Vector4 facadeTangentRight = BuildRMesh.CalculateTangent(-facadeNormal); Vector4 facadeTangentBack = BuildRMesh.CalculateTangent(-facadeDirection); Surface surface = design.surface; int submesh = mesh.submeshLibrary.SubmeshAdd(surface);//surfaceMapping.IndexOf(surface); if (submesh == -1) { submesh = 0; } Vector3 back = -facadeNormal * thickness; for (int g = 0; g < gableSectionCount; g++) { float sectionWidth = design[g].size.x * designScale.x; float sectionHeight = design[g].size.y * designScale.y; Vector3 g0, g1, g2, g3; switch (design[g].type) { case GablePart.Types.Vertical: g0 = p0 + facadeDirection * basePosition.x + Vector3.up * basePosition.y; g1 = p1 - facadeDirection * basePosition.x + Vector3.up * basePosition.y; g2 = g0 + Vector3.up * sectionHeight; g3 = g1 + Vector3.up * sectionHeight; Vector2 uvMax = baseUV + basePosition + new Vector2(facadeWidth - basePosition.x * 2, sectionHeight); mesh.AddPlane(g0, g1, g2, g3, baseUV + basePosition, uvMax, facadeNormal, facadeTangentForward, submesh, surface); Vector2 uvB0 = baseUV + basePosition + new Vector2(0, 0); Vector2 uvB1 = baseUV + basePosition + new Vector2(facadeWidth - basePosition.x * 2, sectionHeight); mesh.AddPlane(g1 + back, g0 + back, g3 + back, g2 + back, uvB0, uvB1, -facadeNormal, facadeTangentBack, submesh, surface); var gb0 = g0 + back; var gb1 = g1 + back; var gb2 = g2 + back; var gb3 = g3 + back; Vector2 baseVUV = new Vector2(0, basePosition.y); mesh.AddPlane(gb0, g0, gb2, g2, baseVUV, new Vector2(thickness, basePosition.y + sectionHeight), -facadeDirection, facadeTangentLeft, submesh, surface); mesh.AddPlane(g1, gb1, g3, gb3, baseVUV, new Vector2(thickness, basePosition.y + sectionHeight), facadeDirection, facadeTangentRight, submesh, surface); basePosition.y += sectionHeight; break; case GablePart.Types.Horizonal: g0 = p0 + facadeDirection * basePosition.x + Vector3.up * basePosition.y; g1 = p1 - facadeDirection * basePosition.x + Vector3.up * basePosition.y; g2 = g0 + facadeDirection * sectionWidth; g3 = g1 - facadeDirection * sectionWidth; Vector4 tangent = BuildRMesh.CalculateTangent(facadeDirection); mesh.AddPlane(g0, g2, g0 + back, g2 + back, Vector3.zero, new Vector2(sectionWidth, thickness), Vector3.up, tangent, submesh, surface); mesh.AddPlane(g3, g1, g3 + back, g1 + back, Vector3.zero, new Vector2(sectionWidth, thickness), Vector3.up, tangent, submesh, surface); basePosition.x += sectionWidth; break; case GablePart.Types.Diagonal: Vector3 gd0 = p0 + facadeDirection * basePosition.x + Vector3.up * basePosition.y; Vector3 gd1 = p1 - facadeDirection * basePosition.x + Vector3.up * basePosition.y; Vector3 gd2 = gd0 + facadeDirection * sectionWidth + Vector3.up * sectionHeight; Vector3 gd3 = gd1 - facadeDirection * sectionWidth + Vector3.up * sectionHeight; Vector3 gdb0 = gd0 + back; Vector3 gdb1 = gd1 + back; Vector3 gdb2 = gd2 + back; Vector3 gdb3 = gd3 + back; Vector2 uv0 = baseUV + basePosition; Vector2 uv1 = baseUV + new Vector2(basePosition.x + facadeWidth - basePosition.x * 2, basePosition.y); Vector2 uv2 = baseUV + new Vector2(basePosition.x + sectionWidth, basePosition.y + sectionHeight); Vector2 uv3 = baseUV + new Vector2(basePosition.x + facadeWidth - basePosition.x * 2 - sectionWidth, basePosition.y + sectionHeight); mesh.AddPlaneComplex(gd0, gd1, gd2, gd3, uv0, uv1, uv2, uv3, facadeNormal, facadeTangentForward, submesh, surface); //face mesh.AddPlaneComplex(gdb1, gdb0, gdb3, gdb2, uv0, uv1, uv2, uv3, -facadeNormal, facadeTangentBack, submesh, surface); //face Vector3 leftNorm = Vector3.Cross(-facadeNormal, (gd2 - gd0).normalized); Vector3[] leftNorms = { leftNorm, leftNorm, leftNorm, leftNorm }; Vector4 leftTangent = facadeTangentLeft; Vector4[] leftTangents = { leftTangent, leftTangent, leftTangent, leftTangent }; Vector3[] leftFace = { gdb0, gd0, gdb2, gd2 }; float faceWidth = Vector3.Distance(gd0, gd2); Vector2 sideUV0 = Vector2.zero; Vector2 sideUV1 = surface != null?surface.CalculateUV(new Vector2(thickness, 0)) : new Vector2(1, 0); Vector2 sideUV2 = surface != null?surface.CalculateUV(new Vector2(0, faceWidth)) : new Vector2(0, 1); Vector2 sideUV3 = surface != null?surface.CalculateUV(new Vector2(thickness, faceWidth)) : new Vector2(1, 1); Vector2[] leftFaceUV = { sideUV0, sideUV1, sideUV2, sideUV3 }; mesh.AddData(leftFace, leftFaceUV, new[] { 0, 2, 1, 2, 3, 1 }, leftNorms, leftTangents, submesh); Vector3 rightNorm = Vector3.Cross(-facadeNormal, (gd1 - gd3).normalized); Vector3[] rightNorms = { rightNorm, rightNorm, rightNorm, rightNorm }; Vector4 rightTangent = facadeTangentRight; Vector4[] rightTangents = { rightTangent, rightTangent, rightTangent, rightTangent }; Vector3[] rightFace = { gd1, gdb1, gd3, gdb3 }; Vector2[] rightFaceUV = { sideUV0, sideUV1, sideUV2, sideUV3 }; //todo mesh.AddData(rightFace, rightFaceUV, new[] { 0, 2, 1, 2, 3, 1 }, rightNorms, rightTangents, submesh); basePosition.x += sectionWidth; basePosition.y += sectionHeight; break; case GablePart.Types.Concave: Arc(ref mesh, design, new Vector3(sectionWidth, sectionHeight, thickness), p0, p1, basePosition, submesh, surface, false, baseUV); basePosition.x += sectionWidth; basePosition.y += sectionHeight; break; case GablePart.Types.Convex: Arc(ref mesh, design, new Vector3(sectionWidth, sectionHeight, thickness), p0, p1, basePosition, submesh, surface, true, baseUV); basePosition.x += sectionWidth; basePosition.y += sectionHeight; break; } } }
private const float HPI = 1.570796f;//half PI private static void Arc(ref BuildRMesh mesh, Gable design, Vector3 sectorSize, Vector3 p0, Vector3 p1, Vector2 basePosition, int submesh, Surface surface, bool convex, Vector2 baseUV) { Vector3 facadeVector = p1 - p0; Vector3 facadeDirection = facadeVector.normalized; float facadeWidth = facadeVector.magnitude; Vector3 facadeNormal = Vector3.Cross(Vector3.up, facadeDirection); Vector4 facadeTangentForward = BuildRMesh.CalculateTangent(facadeDirection); Vector4 facadeTangentLeft = BuildRMesh.CalculateTangent(facadeNormal); Vector4 facadeTangentRight = BuildRMesh.CalculateTangent(-facadeNormal); Vector4 facadeTangentBack = BuildRMesh.CalculateTangent(-facadeDirection); float sectionWidth = sectorSize.x; float sectionHeight = sectorSize.y; float thickness = sectorSize.z; var segmentCount = design.segments; var vertCount = segmentCount * 8 + 4; var verts = new Vector3[vertCount]; var uvs = new Vector2[vertCount]; var normals = new Vector3[vertCount]; var tangents = new Vector4[vertCount]; int triPart = 24; //+ 12 for central section (6 front, 6 back) int triCount = (segmentCount - 1) * triPart + 12; var triangles = new int[triCount]; Vector3 back = -facadeNormal * thickness; float arcLength = HPI * Mathf.Sqrt(2 * Mathf.Pow(sectorSize.x, 2) + 2 * Mathf.Pow(sectorSize.y, 2)) / 2f; //front //left verts[0] = p0 + facadeDirection * (basePosition.x + sectionWidth) + Vector3.up * basePosition.y; Vector2 leftBaseUV = baseUV + new Vector2(basePosition.x + sectionWidth, basePosition.y); uvs[0] = surface != null?surface.CalculateUV(leftBaseUV) : new Vector2(0, 0); normals[0] = facadeNormal; tangents[0] = facadeTangentForward; //right verts[1] = p1 - facadeDirection * (basePosition.x + sectionWidth) + Vector3.up * basePosition.y; Vector2 rightBaseUV = baseUV + new Vector2(basePosition.x + facadeWidth - basePosition.x * 2 - sectionWidth, basePosition.y); uvs[1] = surface != null?surface.CalculateUV(rightBaseUV) : new Vector2(1, 0); normals[1] = facadeNormal; tangents[1] = facadeTangentForward; //back //left int endVertIndexLeft = vertCount - 2; verts[endVertIndexLeft] = verts[0] + back; uvs[endVertIndexLeft] = uvs[1]; normals[endVertIndexLeft] = -facadeNormal; tangents[endVertIndexLeft] = facadeTangentBack; //right int endVertIndexRight = vertCount - 1; verts[endVertIndexRight] = verts[1] + back; uvs[endVertIndexRight] = uvs[0]; normals[endVertIndexRight] = -facadeNormal; tangents[endVertIndexRight] = facadeTangentBack; for (int i = 0; i < segmentCount; i++) { float percent = i / (segmentCount - 1f); float arcDistance = arcLength * percent; float arcPercent = convex ? percent : (1 - percent) + 2; float x = Mathf.Sin(arcPercent * HPI); float y = Mathf.Cos(arcPercent * HPI); if (!convex) { x = (x + 1); y = (y + 1); } Vector3 arcLeft = facadeDirection * (-x * sectionWidth) + Vector3.up * y * sectionHeight; Vector3 arcRight = facadeDirection * (x * sectionWidth) + Vector3.up * y * sectionHeight; Vector3 vertA = verts[0] + arcLeft; Vector3 vertB = vertA + back; Vector3 vertC = verts[1] + arcRight; Vector3 vertD = vertC + back; //left verts[i + 2] = vertA; //front verts[i + 2 + segmentCount] = vertA; //front top verts[i + 2 + segmentCount * 2] = vertB; //back top verts[i + 2 + segmentCount * 3] = vertB; //back uvs[i + 2] = surface != null?surface.CalculateUV(leftBaseUV + new Vector2(-x *sectionWidth, y *sectionHeight)) : new Vector2(0, 0); uvs[i + 2 + segmentCount] = surface != null?surface.CalculateUV(new Vector2(thickness, arcDistance)) : new Vector2(1, 0); uvs[i + 2 + segmentCount * 2] = surface != null?surface.CalculateUV(new Vector2(0, arcDistance)) : new Vector2(0, 1); uvs[i + 2 + segmentCount * 3] = surface != null?surface.CalculateUV(rightBaseUV + new Vector2(x *sectionWidth, y *sectionHeight)) : new Vector2(1, 1); //right verts[i + 2 + segmentCount * 4] = vertC; //front verts[i + 2 + segmentCount * 5] = vertC; //front top verts[i + 2 + segmentCount * 6] = vertD; //back top verts[i + 2 + segmentCount * 7] = vertD; //back uvs[i + 2 + segmentCount * 4] = surface != null?surface.CalculateUV(rightBaseUV + new Vector2(x *sectionWidth, y *sectionHeight)) : new Vector2(0, 0); uvs[i + 2 + segmentCount * 5] = surface != null?surface.CalculateUV(new Vector2(0, arcDistance)) : new Vector2(1, 0); uvs[i + 2 + segmentCount * 6] = surface != null?surface.CalculateUV(new Vector2(thickness, arcDistance)) : new Vector2(0, 1); uvs[i + 2 + segmentCount * 7] = surface != null?surface.CalculateUV(leftBaseUV + new Vector2(-x *sectionWidth, y *sectionHeight)) : new Vector2(1, 1); if (i < segmentCount - 1) { //left //front triangles[i * triPart] = 0; triangles[i * triPart + 1] = i + 3; triangles[i * triPart + 2] = i + 2; //top triangles[i * triPart + 3] = i + segmentCount + 2; triangles[i * triPart + 4] = i + segmentCount + 3; triangles[i * triPart + 5] = i + segmentCount * 2 + 2; triangles[i * triPart + 6] = i + segmentCount + 3; triangles[i * triPart + 7] = i + segmentCount * 2 + 3; triangles[i * triPart + 8] = i + segmentCount * 2 + 2; //back triangles[i * triPart + 9] = endVertIndexLeft; triangles[i * triPart + 10] = i + 2 + segmentCount * 3; triangles[i * triPart + 11] = i + 3 + segmentCount * 3; //right //front triangles[i * triPart + 12] = 1; triangles[i * triPart + 13] = i + segmentCount * 4 + 2; triangles[i * triPart + 14] = i + segmentCount * 4 + 3; //top triangles[i * triPart + 15] = i + segmentCount * 5 + 3; triangles[i * triPart + 16] = i + segmentCount * 5 + 2; triangles[i * triPart + 17] = i + segmentCount * 6 + 2; triangles[i * triPart + 18] = i + segmentCount * 5 + 3; triangles[i * triPart + 19] = i + segmentCount * 6 + 2; triangles[i * triPart + 20] = i + segmentCount * 6 + 3; //back triangles[i * triPart + 21] = endVertIndexRight; triangles[i * triPart + 22] = i + 3 + segmentCount * 7; triangles[i * triPart + 23] = i + 2 + segmentCount * 7; } //left normals[i + 2] = facadeNormal; tangents[i + 2] = facadeTangentForward; Vector3 upNormalLeft = Vector3.Slerp(-facadeDirection, Vector3.up, percent); normals[i + 2 + segmentCount] = upNormalLeft; tangents[i + 2 + segmentCount] = facadeTangentLeft; normals[i + 2 + segmentCount * 2] = upNormalLeft; tangents[i + 2 + segmentCount * 2] = facadeTangentLeft; normals[i + 2 + segmentCount * 3] = -facadeNormal; tangents[i + 2 + segmentCount * 3] = facadeTangentBack; //right normals[i + 2 + segmentCount * 4] = facadeNormal; tangents[i + 2 + segmentCount * 4] = facadeTangentForward; Vector3 upNormalRight = Vector3.Slerp(facadeDirection, Vector3.up, percent); normals[i + 2 + segmentCount * 5] = upNormalRight; tangents[i + 2 + segmentCount * 5] = facadeTangentRight; normals[i + 2 + segmentCount * 6] = upNormalRight; tangents[i + 2 + segmentCount * 6] = facadeTangentRight; normals[i + 2 + segmentCount * 7] = -facadeNormal; tangents[i + 2 + segmentCount * 7] = facadeTangentBack; } //inter arc faces //front triangles[triCount - 12] = 1; triangles[triCount - 11] = 0; triangles[triCount - 10] = 2; triangles[triCount - 9] = 1; triangles[triCount - 8] = 2; triangles[triCount - 7] = segmentCount * 4 + 2; //back triangles[triCount - 6] = endVertIndexLeft; triangles[triCount - 5] = endVertIndexRight; triangles[triCount - 4] = 2 + segmentCount * 3; triangles[triCount - 3] = 2 + segmentCount * 3; triangles[triCount - 2] = endVertIndexRight; triangles[triCount - 1] = segmentCount * 7 + 2;//1; mesh.AddData(verts, uvs, triangles, normals, tangents, submesh); }
public static void Generate(Chimney chimney, GenerationOutput output, SubmeshLibrary submeshLibrary = null) { RGEN.seed = chimney.seed; DYNAMIC_MESH.Clear(); if (submeshLibrary != null) { DYNAMIC_MESH.submeshLibrary.AddRange(submeshLibrary.SURFACES.ToArray()); //DYNAMIC_MESH.submeshLibrary.Inject(ref submeshLibrary); } else { DYNAMIC_MESH.submeshLibrary.Add(chimney); } submeshLibrary = DYNAMIC_MESH.submeshLibrary; //CASE Vector3 caseNoiseVector = new Vector3(chimney.noise.x * RGEN.OneRange(), chimney.noise.y * RGEN.OneRange(), chimney.noise.z * RGEN.OneRange()); Vector3 cs0 = new Vector3(-chimney.caseSize.x * 0.5f, 0, -chimney.caseSize.z * 0.5f); Vector3 cs1 = new Vector3(chimney.caseSize.x * 0.5f, 0, -chimney.caseSize.z * 0.5f); Vector3 cs2 = new Vector3(-chimney.caseSize.x * 0.5f, 0, chimney.caseSize.z * 0.5f); Vector3 cs3 = new Vector3(chimney.caseSize.x * 0.5f, 0, chimney.caseSize.z * 0.5f); Vector3 cs4 = new Vector3(-chimney.caseSize.x * 0.5f, chimney.caseSize.y, -chimney.caseSize.z * 0.5f) + caseNoiseVector; Vector3 cs5 = new Vector3(chimney.caseSize.x * 0.5f, chimney.caseSize.y, -chimney.caseSize.z * 0.5f) + caseNoiseVector; Vector3 cs6 = new Vector3(-chimney.caseSize.x * 0.5f, chimney.caseSize.y, chimney.caseSize.z * 0.5f) + caseNoiseVector; Vector3 cs7 = new Vector3(chimney.caseSize.x * 0.5f, chimney.caseSize.y, chimney.caseSize.z * 0.5f) + caseNoiseVector; Vector2 csuv0 = new Vector2(0, 0); Vector2 csuv1 = new Vector2(chimney.caseSize.x, chimney.caseSize.y); Vector2 csuv2 = new Vector2(csuv1.x, 0); Vector2 csuv3 = new Vector2(csuv1.x + chimney.caseSize.z, chimney.caseSize.y); Vector2 csuv4 = new Vector2(csuv3.x, 0); Vector2 csuv5 = new Vector2(csuv3.x + chimney.caseSize.x, chimney.caseSize.y); Vector2 csuv6 = new Vector2(csuv5.x, 0); Vector2 csuv7 = new Vector2(csuv5.x + chimney.caseSize.z, chimney.caseSize.y); Vector2 csuv8 = new Vector2(0, 0); Vector2 csuv9 = new Vector2(chimney.caseSize.x, chimney.caseSize.z); Vector4 cst0 = new Vector4(0, 0, 1, 0); Vector4 cst1 = new Vector4(1, 0, 1, 0); Vector4 cst2 = new Vector4(0, 0, -1, 0); Vector4 cst3 = new Vector4(-1, 0, 0, 0); Vector4 cst4 = new Vector4(0, 0, 1, 0); int caseSubmesh = submeshLibrary.SubmeshAdd(chimney.caseSurface); //sides DYNAMIC_MESH.AddPlane(cs0, cs1, cs4, cs5, csuv0, csuv1, Vector3.back, cst0, caseSubmesh, chimney.caseSurface); DYNAMIC_MESH.AddPlane(cs1, cs3, cs5, cs7, csuv2, csuv3, Vector3.right, cst1, caseSubmesh, chimney.caseSurface); DYNAMIC_MESH.AddPlane(cs3, cs2, cs7, cs6, csuv4, csuv5, Vector3.forward, cst2, caseSubmesh, chimney.caseSurface); DYNAMIC_MESH.AddPlane(cs2, cs0, cs6, cs4, csuv6, csuv7, Vector3.left, cst3, caseSubmesh, chimney.caseSurface); //top DYNAMIC_MESH.AddPlane(cs4, cs5, cs6, cs7, csuv8, csuv9, Vector3.up, cst4, caseSubmesh, chimney.caseSurface);//todo calculate the values for this - don't be lazy //CROWN Vector3 crownBase = caseNoiseVector + Vector3.up * chimney.caseSize.y; Vector3 crownNoiseVector = new Vector3(chimney.noise.x * RGEN.OneRange(), chimney.noise.y * RGEN.OneRange(), chimney.noise.z * RGEN.OneRange()); Vector3 cr0 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, 0, -chimney.crownSize.z * 0.5f); Vector3 cr1 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, 0, -chimney.crownSize.z * 0.5f); Vector3 cr2 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, 0, chimney.crownSize.z * 0.5f); Vector3 cr3 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, 0, chimney.crownSize.z * 0.5f); Vector3 cr4 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, chimney.crownSize.y, -chimney.crownSize.z * 0.5f) + crownNoiseVector; Vector3 cr5 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, chimney.crownSize.y, -chimney.crownSize.z * 0.5f) + crownNoiseVector; Vector3 cr6 = crownBase + new Vector3(-chimney.crownSize.x * 0.5f, chimney.crownSize.y, chimney.crownSize.z * 0.5f) + crownNoiseVector; Vector3 cr7 = crownBase + new Vector3(chimney.crownSize.x * 0.5f, chimney.crownSize.y, chimney.crownSize.z * 0.5f) + crownNoiseVector; Vector2 cruv0 = new Vector2(0, 0); Vector2 cruv1 = new Vector2(chimney.crownSize.x, chimney.crownSize.y); Vector2 cruv2 = new Vector2(csuv1.x, 0); Vector2 cruv3 = new Vector2(csuv1.x + chimney.caseSize.z, chimney.crownSize.y); Vector2 cruv4 = new Vector2(csuv3.x, 0); Vector2 cruv5 = new Vector2(csuv3.x + chimney.crownSize.x, chimney.crownSize.y); Vector2 cruv6 = new Vector2(csuv5.x, chimney.crownSize.y); Vector2 cruv7 = new Vector2(csuv5.x + chimney.crownSize.z, chimney.crownSize.y); Vector2 cruv8 = new Vector2(0, 0); Vector2 cruv9 = new Vector2(chimney.crownSize.x, chimney.crownSize.z); Vector4 crt0 = new Vector4(0, 0, 1, 0); Vector4 crt1 = new Vector4(1, 0, 1, 0); Vector4 crt2 = new Vector4(0, 0, -1, 0); Vector4 crt3 = new Vector4(-1, 0, 0, 0); Vector4 crt4 = new Vector4(0, 0, 1, 0); int crownSubmesh = submeshLibrary.SubmeshAdd(chimney.crownSurface); DYNAMIC_MESH.AddPlane(cr0, cr1, cr4, cr5, cruv0, cruv1, Vector3.back, crt0, crownSubmesh, chimney.crownSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(cr1, cr3, cr5, cr7, cruv2, cruv3, Vector3.right, crt1, crownSubmesh, chimney.crownSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(cr3, cr2, cr7, cr6, cruv4, cruv5, Vector3.forward, crt2, crownSubmesh, chimney.crownSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(cr2, cr0, cr6, cr4, cruv6, cruv7, Vector3.left, crt3, crownSubmesh, chimney.crownSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(cr1, cr0, cr3, cr2, cruv8, cruv9, Vector3.down, crt4, crownSubmesh, chimney.crownSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(cr4, cr5, cr6, cr7, cruv8, cruv9, Vector3.up, crt4, crownSubmesh, chimney.crownSurface); //todo calculate the values for this - don't be lazy int xCount = 1; int zCount = 1; if (chimney.allowMultiple) { xCount = Mathf.FloorToInt((chimney.crownSize.x - chimney.flueSpacing) / (chimney.flueSize.x + chimney.flueSpacing)); if (xCount < 1) { xCount = 1; } if (chimney.allowMultipleRows) { zCount = Mathf.FloorToInt((chimney.crownSize.z - chimney.flueSpacing) / (chimney.flueSize.z + chimney.flueSpacing)); if (zCount < 1) { zCount = 1; } } } float xSpacing = (chimney.crownSize.x - chimney.flueSize.x * xCount) / (xCount + 1); float zSpacing = (chimney.crownSize.z - chimney.flueSize.z * zCount) / (zCount + 1); //FLUES for (int x = 0; x < xCount; x++) { for (int z = 0; z < zCount; z++) { Vector3 flueBase = cr4 + new Vector3(xSpacing + x * (chimney.flueSize.x + xSpacing) + chimney.flueSize.x * 0.5f, 0, zSpacing + z * (chimney.flueSize.z + zSpacing) + chimney.flueSize.z * 0.5f); float thickness = (chimney.flueSize.x + chimney.flueSize.z) * 0.05f;//10% float drop = chimney.flueSize.y * 0.9f; Vector4 topTangent = new Vector4(1, 0, 0, 0); Surface useFlueSurface = GenerationUtil.GetSurface(chimney.flueSurfaces, RGEN); int flueSubmesh = submeshLibrary.SubmeshAdd(useFlueSurface); int innerSubmesh = submeshLibrary.SubmeshAdd(chimney.innerSurface); Vector3 flueNoiseVector = new Vector3(chimney.noise.x * RGEN.OneRange(), chimney.noise.y * RGEN.OneRange(), chimney.noise.z * RGEN.OneRange()); if (chimney.square) { Vector3 f0 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, 0, -chimney.flueSize.z * 0.5f); Vector3 f1 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, 0, -chimney.flueSize.z * 0.5f); Vector3 f2 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, 0, chimney.flueSize.z * 0.5f); Vector3 f3 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, 0, chimney.flueSize.z * 0.5f); Vector3 f4 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, chimney.flueSize.y, -chimney.flueSize.z * 0.5f) + flueNoiseVector; Vector3 f5 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, chimney.flueSize.y, -chimney.flueSize.z * 0.5f) + flueNoiseVector; Vector3 f6 = flueBase + new Vector3(-chimney.flueSize.x * 0.5f, chimney.flueSize.y, chimney.flueSize.z * 0.5f) + flueNoiseVector; Vector3 f7 = flueBase + new Vector3(chimney.flueSize.x * 0.5f, chimney.flueSize.y, chimney.flueSize.z * 0.5f) + flueNoiseVector; Vector3 f4i = f4 + new Vector3(thickness, 0, thickness) + flueNoiseVector; Vector3 f5i = f5 + new Vector3(-thickness, 0, thickness) + flueNoiseVector; Vector3 f6i = f6 + new Vector3(thickness, 0, -thickness) + flueNoiseVector; Vector3 f7i = f7 + new Vector3(-thickness, 0, -thickness) + flueNoiseVector; Vector3 f4id = f4i + new Vector3(0, -drop, 0); Vector3 f5id = f5i + new Vector3(0, -drop, 0); Vector3 f6id = f6i + new Vector3(0, -drop, 0); Vector3 f7id = f7i + new Vector3(0, -drop, 0); // Vector2 fuv0 = new Vector2(0, 0); // Vector2 fuv1 = new Vector2(chimney.flueSize.x, 0); // Vector2 fuv2 = new Vector2(fuv1.x + chimney.flueSize.z, 0); // Vector2 fuv3 = new Vector2(fuv2.x + chimney.flueSize.x, 0); // // Vector2 fuv4 = new Vector2(0, chimney.flueSize.y); // Vector2 fuv5 = new Vector2(chimney.flueSize.x, chimney.flueSize.y); // Vector2 fuv6 = new Vector2(fuv1.x + chimney.flueSize.z, chimney.flueSize.y); // Vector2 fuv7 = new Vector2(fuv2.x + chimney.flueSize.x, chimney.flueSize.y); //Flue Sides DYNAMIC_MESH.AddPlane(f0, f1, f4, f5, flueSubmesh); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(f1, f3, f5, f7, flueSubmesh); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(f3, f2, f7, f6, flueSubmesh); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(f2, f0, f6, f4, flueSubmesh); //todo calculate the values for this - don't be lazy //Flue Top DYNAMIC_MESH.AddPlaneComplex(f4, f5, f4i, f5i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlaneComplex(f5, f7, f5i, f7i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlaneComplex(f7, f6, f7i, f6i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlaneComplex(f6, f4, f6i, f4i, Vector3.up, topTangent, flueSubmesh, useFlueSurface); //todo calculate the values for this - don't be lazy //Flue Drop DYNAMIC_MESH.AddPlane(f5id, f4id, f5i, f4i, innerSubmesh); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(f7id, f5id, f7i, f5i, innerSubmesh); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(f6id, f7id, f6i, f7i, innerSubmesh); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(f4id, f6id, f4i, f6i, innerSubmesh); //todo calculate the values for this - don't be lazy DYNAMIC_MESH.AddPlane(f4id, f5id, f6id, f7id, innerSubmesh); //todo calculate the values for this - don't be lazy } else { int vertCount = (chimney.segments + 1) * 2;//add an additonal so we can wrap the UVs well RawMeshData flueOuter = new RawMeshData(vertCount, chimney.segments * 6); RawMeshData flueTop = new RawMeshData(vertCount, chimney.segments * 6); //add additional point for the middle, bottom of the inside of the flue RawMeshData flueInner = new RawMeshData(vertCount + 1, chimney.segments * 9); //the additonal point at the bottom of the flue - added to the end of the mesh data flueInner.vertices[vertCount] = flueBase; flueInner.normals[vertCount] = Vector3.up; flueInner.tangents[vertCount] = new Vector4(1, 0, 0, 0); int indexIm = flueInner.vertCount - 1; float circumference = Mathf.PI * (chimney.flueSize.x + chimney.flueSize.z); for (int s = 0; s < chimney.segments + 1; s++) { float percent = s / (float)(chimney.segments); percent = (percent + (chimney.angleOffset / 360)) % 1f; int indexV0 = s * 2; int indexV1 = s * 2 + 1; int indexV2 = s * 2 + 2; int indexV3 = s * 2 + 3; if (s == chimney.segments - 1) { indexV2 = 0; indexV3 = 1; } float xa = Mathf.Sin(percent * Mathf.PI * 2) * chimney.flueSize.x * 0.5f; float za = Mathf.Cos(percent * Mathf.PI * 2) * chimney.flueSize.z * 0.5f; // float innerHalf = thickness / (chimney.flueSize.x + chimney.flueSize.z) / 2; float xai = Mathf.Sin(percent * Mathf.PI * 2) * chimney.flueSize.x * 0.4f; float zai = Mathf.Cos(percent * Mathf.PI * 2) * chimney.flueSize.z * 0.4f; Vector3 v0 = flueBase + new Vector3(xa, 0, za); Vector3 v1 = flueBase + new Vector3(xa, chimney.flueSize.y, za) + flueNoiseVector; Vector3 v2 = flueBase + new Vector3(xai, chimney.flueSize.y, zai) + flueNoiseVector; Vector3 v3 = flueBase + new Vector3(xai, chimney.flueSize.y * 0.1f, zai); Vector2 uv0 = new Vector2(-circumference * percent, 0); Vector2 uv1 = new Vector2(-circumference * percent, chimney.flueSize.y); Vector2 uv2 = new Vector2(-circumference * percent, chimney.flueSize.y + 0.1f); Vector2 uv3 = new Vector2(-circumference * percent, 0); int rdnFlueSurfaceIndex = RGEN.Index(chimney.flueSurfaces.Count); Surface flueSurface = rdnFlueSurfaceIndex != -1 ? chimney.flueSurfaces[rdnFlueSurfaceIndex] : null; if (flueSurface != null) { uv0 = flueSurface.CalculateUV(uv0); uv1 = flueSurface.CalculateUV(uv1); uv2 = flueSurface.CalculateUV(uv2); uv3 = flueSurface.CalculateUV(uv3); } flueOuter.vertices[indexV0] = v0; flueOuter.vertices[indexV1] = v1; flueOuter.uvs[indexV0] = uv0; flueOuter.uvs[indexV1] = uv1; flueTop.vertices[indexV0] = v1; flueTop.vertices[indexV1] = v2; flueTop.uvs[indexV0] = uv1; flueTop.uvs[indexV1] = uv2; flueInner.vertices[indexV0] = v2; flueInner.vertices[indexV1] = v3; flueInner.uvs[indexV0] = uv2; flueInner.uvs[indexV1] = uv3; Vector3 outerNormal = new Vector3(Mathf.Sin(percent * Mathf.PI * 2), 0, Mathf.Cos(percent * Mathf.PI * 2)); flueOuter.normals[indexV0] = outerNormal; flueOuter.normals[indexV1] = outerNormal; flueTop.normals[indexV0] = Vector3.up; flueTop.normals[indexV1] = Vector3.up; flueInner.normals[indexV0] = -outerNormal; flueInner.normals[indexV1] = -outerNormal; if (s < chimney.segments) { int tidx0 = s * 6; flueOuter.triangles[tidx0 + 0] = indexV0; flueOuter.triangles[tidx0 + 2] = indexV1; flueOuter.triangles[tidx0 + 1] = indexV2; flueOuter.triangles[tidx0 + 3] = indexV1; flueOuter.triangles[tidx0 + 4] = indexV2; flueOuter.triangles[tidx0 + 5] = indexV3; flueTop.triangles[tidx0 + 0] = indexV0; flueTop.triangles[tidx0 + 2] = indexV1; flueTop.triangles[tidx0 + 1] = indexV2; flueTop.triangles[tidx0 + 3] = indexV1; flueTop.triangles[tidx0 + 4] = indexV2; flueTop.triangles[tidx0 + 5] = indexV3; int tidx0i = s * 9; flueInner.triangles[tidx0i + 0] = indexV0; flueInner.triangles[tidx0i + 2] = indexV1; flueInner.triangles[tidx0i + 1] = indexV2; flueInner.triangles[tidx0i + 3] = indexV1; flueInner.triangles[tidx0i + 4] = indexV2; flueInner.triangles[tidx0i + 5] = indexV3; flueInner.triangles[tidx0i + 6] = indexV1; flueInner.triangles[tidx0i + 7] = indexV3; flueInner.triangles[tidx0i + 8] = indexIm; } } DYNAMIC_MESH.AddData(flueOuter, flueSubmesh); DYNAMIC_MESH.AddData(flueTop, flueSubmesh); DYNAMIC_MESH.AddData(flueInner, innerSubmesh); } } } if (output.raw != null) { output.raw.Copy(DYNAMIC_MESH); } if (output.mesh != null) { output.mesh.Clear(false); DYNAMIC_MESH.Build(output.mesh); } }
public static void Generate(IBuilding building, IVolume volume, IFloorplan floorplan, int volumeFloor, VerticalOpening[] openings, BuildRMesh mesh, BuildRCollider collider) { SubmeshLibrary submeshLibrary = mesh.submeshLibrary; bool generateColliders = building.colliderType != BuildingColliderTypes.None; bool generateMeshColliders = building.colliderType != BuildingColliderTypes.Primitive && generateColliders; BuildRCollider sendCollider = (generateColliders) ? collider : null; collider.thickness = volume.wallThickness; if (!generateMeshColliders) { collider = null; } float wallThickness = volume.wallThickness; float wallUp = volume.floorHeight - wallThickness; Vector3 wallUpV = Vector3.up * wallUp; Vector3 floorBaseV = Vector3.up * volume.baseHeight; int roomCount = floorplan.RoomCount; int actualFloor = building.VolumeBaseFloor(volume) + volumeFloor; int openingCount = openings.Length; bool[] openingBelow = new bool[openingCount]; bool[] openingAbove = new bool[openingCount]; FlatBounds[] openingBounds = new FlatBounds[openingCount]; Vector2[][] openingShapes = new Vector2[openingCount][]; bool[] openingUsedInThisFloor = new bool[openingCount]; for (int o = 0; o < openingCount; o++) { VerticalOpening opening = openings[o]; if (!openings[o].FloorIsIncluded(actualFloor)) { continue; } openingBelow[o] = opening.FloorIsIncluded(actualFloor - 1); openingAbove[o] = opening.FloorIsIncluded(actualFloor + 1); openingShapes[o] = opening.PointsRotated(); openingBounds[o] = new FlatBounds(openingShapes[o]); submeshLibrary.Add(opening.surfaceA); submeshLibrary.Add(opening.surfaceB); submeshLibrary.Add(opening.surfaceC); submeshLibrary.Add(opening.surfaceD); } Dictionary <int, List <Vector2Int> > externalWallAnchors = volume.facadeWallAnchors; Room[] rooms = floorplan.AllRooms(); for (int r = 0; r < roomCount; r++) { Room room = rooms[r]; int pointCount = room.numberOfPoints; Surface floorSurface = null; Surface wallSurface = null; Surface ceilingSurface = null; if (room.style != null) { RoomStyle style = room.style; floorSurface = style.floorSurface; wallSurface = style.wallSurface; ceilingSurface = style.ceilingSurface; } int floorSubmesh = submeshLibrary.SubmeshAdd(floorSurface); int wallSubmesh = submeshLibrary.SubmeshAdd(wallSurface); int ceilingSubmesh = submeshLibrary.SubmeshAdd(ceilingSurface); FloorplanUtil.RoomWall[] walls = FloorplanUtil.CalculatePoints(room, volume); Vector2[] roomArchorPoints = FloorplanUtil.RoomArchorPoints(walls); Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); Vector2[] offsetRoomAnchorPoints = QuickPolyOffset.Execute(roomArchorPoints, wallThickness); FlatBounds roomBounds = new FlatBounds(offsetRoomAnchorPoints); List <Vector2[]> floorCuts = new List <Vector2[]>(); List <Vector2[]> ceilingCuts = new List <Vector2[]>(); List <VerticalOpening> roomOpenings = new List <VerticalOpening>(); for (int o = 0; o < openingCount; o++) { if (openings[o].FloorIsIncluded(actualFloor)) { if (roomBounds.Overlaps(openingBounds[o])) { if (CheckShapeWithinRoom(offsetRoomAnchorPoints, openingShapes[o])) { if (openingBelow[o]) { floorCuts.Add(openingShapes[o]); } if (openingAbove[o]) { ceilingCuts.Add(openingShapes[o]); } if (openingAbove[o] || openingBelow[o]) { roomOpenings.Add(openings[o]); openingUsedInThisFloor[o] = true; } } } } } int offsetPointBase = 0; for (int p = 0; p < pointCount; p++)//generate room walls { FloorplanUtil.RoomWall wall = walls[p]; int wallPointCount = wall.offsetPoints.Length; List <RoomPortal> wallPortals = floorplan.GetWallPortals(room, p); int wallPortalCount = wallPortals.Count; if (!wall.isExternal) { int indexA = offsetPointBase; int indexB = (offsetPointBase + 1) % roomArchorPoints.Length; Vector2 origBaseA = roomArchorPoints[indexA]; Vector2 origBaseB = roomArchorPoints[indexB]; Vector2 baseA = offsetRoomAnchorPoints[indexA]; Vector2 baseB = offsetRoomAnchorPoints[indexB]; Vector3 v0 = new Vector3(origBaseA.x, 0, origBaseA.y) + floorBaseV; Vector3 v1 = new Vector3(origBaseB.x, 0, origBaseB.y) + floorBaseV; Vector3 vOffset0 = new Vector3(baseA.x, 0, baseA.y) + floorBaseV; Vector3 vOffset1 = new Vector3(baseB.x, 0, baseB.y) + floorBaseV; if (wallPortalCount == 0) //just draw the wall - no portals to cut { Vector3 v2 = vOffset1 + wallUpV; Vector3 v3 = vOffset0 + wallUpV; Vector2 minUV = Vector2.zero; Vector2 maxUV = new Vector2(Vector2.Distance(baseA, baseB), wallUp); if (wallSurface != null) { maxUV = wallSurface.CalculateUV(maxUV); } Vector3 wallDir = (vOffset0 - vOffset1).normalized; Vector3 wallNormal = Vector3.Cross(Vector3.up, wallDir); Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir); mesh.AddPlane(vOffset1, vOffset0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface); if (generateColliders) { collider.AddPlane(vOffset1, vOffset0, v2, v3); } } else { List <float> useLaterals = new List <float>(); List <bool> hasPortals = new List <bool>(); for (int wp = 0; wp < wallPortalCount; wp++) { RoomPortal portal = wallPortals[wp]; bool hasPortal = room.HasPortal(portal); hasPortals.Add(hasPortal); if (hasPortal) { useLaterals.Add(portal.lateralPosition); } else { useLaterals.Add(1 - portal.lateralPosition);//portal from other wall - wall orientation is flipped } } Vector3 wallVector = vOffset1 - vOffset0; Vector3 wallDirection = wallVector.normalized; Vector3 wallStart = vOffset0; Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDirection); Vector3 wallNormal = Vector3.Cross(Vector3.up, wallDirection); Vector4 wallNormalTangent = BuildRMesh.CalculateTangent(wallNormal); Vector4 wallNormalTangentReverse = BuildRMesh.CalculateTangent(-wallNormal); while (wallPortalCount > 0) { int portalIndex = 0; RoomPortal usePortal = wallPortals[0]; float lowestLat = useLaterals[0]; for (int wp = 1; wp < wallPortalCount; wp++) { if (useLaterals[wp] < lowestLat) { portalIndex = wp; usePortal = wallPortals[wp]; lowestLat = useLaterals[wp]; } } wallPortals.RemoveAt(portalIndex); useLaterals.RemoveAt(portalIndex); wallPortalCount--; Vector3 vl0 = v0 + (-wallNormal + wallDirection) * wallThickness; Vector3 vl1 = v1 + (-wallNormal - wallDirection) * wallThickness; Vector3 portalCenter = Vector3.Lerp(vl0, vl1, lowestLat); Vector3 portalHalfvector = wallDirection * (usePortal.width * 0.5f); Vector3 portalBase = Vector3.up * (volume.floorHeight - usePortal.height) * usePortal.verticalPosition; Vector3 portalUp = portalBase + Vector3.up * usePortal.height; Vector3 portalStart = portalCenter - portalHalfvector; Vector3 portalEnd = portalCenter + portalHalfvector; Vector2 initalWallUVMin = new Vector2(Vector3.Dot(portalStart, wallDirection), 0); Vector2 initalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp); mesh.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV, initalWallUVMin, initalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//initial wall if (generateColliders) { collider.AddPlane(portalStart, wallStart, portalStart + wallUpV, wallStart + wallUpV); } if (usePortal.verticalPosition > 0) { Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), 0); Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), portalBase.y); mesh.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//bottom if (generateColliders) { collider.AddPlane(portalEnd, portalStart, portalEnd + portalBase, portalStart + portalBase); } } if (usePortal.verticalPosition < 1) { Vector2 portalBaseUVMin = new Vector2(Vector3.Dot(portalEnd, wallDirection), portalUp.y); Vector2 portalBaseUVMax = new Vector2(Vector3.Dot(portalStart, wallDirection), wallUp); mesh.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV, portalBaseUVMin, portalBaseUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//top if (generateColliders) { collider.AddPlane(portalEnd + portalUp, portalStart + portalUp, portalEnd + wallUpV, portalStart + wallUpV); } } if (hasPortals[portalIndex])//only do this once - from the room it's attached to { //portal interior frame Vector3 portalDepth = wallNormal * wallThickness * 2; //sides mesh.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp, wallDirection, wallNormalTangentReverse, wallSubmesh); mesh.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp, -wallDirection, wallNormalTangent, wallSubmesh); if (generateMeshColliders) { collider.AddPlane(portalStart + portalDepth + portalBase, portalStart + portalBase, portalStart + portalDepth + portalUp, portalStart + portalUp); collider.AddPlane(portalEnd + portalBase, portalEnd + portalDepth + portalBase, portalEnd + portalUp, portalEnd + portalDepth + portalUp); } //floor Vector2 minFloorUv = new Vector2((portalEnd + portalBase).z, (portalEnd + portalBase).x); Vector2 maxFloorUv = minFloorUv + new Vector2(wallThickness, usePortal.width); mesh.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase, minFloorUv, maxFloorUv, Vector3.up, wallTangent, floorSubmesh, floorSurface); if (generateMeshColliders) { collider.AddPlane(portalStart + portalBase, portalStart + portalDepth + portalBase, portalEnd + portalBase, portalEnd + portalDepth + portalBase); } //ceiling mesh.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp, Vector3.down, wallTangent, wallSubmesh); if (generateMeshColliders) { collider.AddPlane(portalEnd + portalUp, portalEnd + portalDepth + portalUp, portalStart + portalUp, portalStart + portalDepth + portalUp); } } wallStart = portalEnd;//move the start for the next calculation } Vector2 finalWallUVMin = new Vector2(Vector3.Dot(vOffset1, wallDirection), 0); Vector2 finalWallUVMax = new Vector2(Vector3.Dot(wallStart, wallDirection), wallUp); mesh.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV, finalWallUVMin, finalWallUVMax, wallNormal, wallTangent, wallSubmesh, wallSurface);//final wall section if (generateColliders) { collider.AddPlane(vOffset1, wallStart, vOffset1 + wallUpV, wallStart + wallUpV); } } offsetPointBase += 1; } else//external anchored wall { int facadeIndex = wall.facadeIndex; Facade facadeDesign = volume.GetFacade(facadeIndex); int currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count - 1; int currentWallSectionIndex = wall.offsetPointWallSection[0]; int wallOffsetPoints = wall.offsetPoints.Length; for (int w = 0; w < wallOffsetPoints - 1; w++) { int roomPointIndex = offsetPointBase + w; Vector2 baseA = offsetRoomAnchorPoints[roomPointIndex]; int offsetIndexB = (roomPointIndex + 1) % offsetRoomAnchorPoints.Length; Vector2 baseB = offsetRoomAnchorPoints[offsetIndexB]; Vector3 v0 = new Vector3(baseA.x, 0, baseA.y) + floorBaseV; Vector3 v1 = new Vector3(baseB.x, 0, baseB.y) + floorBaseV; int wallSectionIndex = wall.offsetPointWallSection[w]; bool canGenerateWallSection = facadeDesign != null; Vector3 wallVector = v0 - v1; Vector3 wallDir = wallVector.normalized; float wallLength = wallVector.magnitude; if (!canGenerateWallSection) { if (wallSurface != null) { submeshLibrary.Add(wallSurface); } Vector3 v2 = v1 + wallUpV; Vector3 v3 = v0 + wallUpV; Vector2 minUV = Vector2.zero; Vector2 maxUV = new Vector2(Vector2.Distance(baseA, baseB), wallUp); Vector3 wallNormal = Vector3.Cross(Vector3.up, wallDir); Vector4 wallTangent = BuildRMesh.CalculateTangent(wallDir); mesh.AddPlane(v1, v0, v2, v3, minUV, maxUV, wallNormal, wallTangent, wallSubmesh, wallSurface); if (generateMeshColliders) { collider.AddPlane(v1, v0, v2, v3); } } else { WallSection section = facadeDesign.GetWallSection(wallSectionIndex, volumeFloor, currentFacadeWallSectionLength, volume.floors); if (section.model != null) { continue;//cannot account for custom meshes assume custom mesh does include interior mesh or if does - will be generated with the exterior } GenerationOutput generatedSection = GenerationOutput.CreateRawOutput(); Vector2 wallSectionSize = new Vector2(wallLength, wallUp + wallThickness); bool cullOpening = building.cullDoors && section.isDoor; SubmeshLibrary sectionLib = new SubmeshLibrary(); if (wallSurface != null) { sectionLib.Add(wallSurface);//add interior wall surface submeshLibrary.Add(wallSurface); } sectionLib.Add(section.openingSurface);//add windows - the only surface we'll use in the interior room submeshLibrary.Add(section.openingSurface); float offset = 0; if (w == 0) { offset = wallThickness; } if (w == wallOffsetPoints - 2) { offset = -wallThickness; } WallSectionGenerator.Generate(section, generatedSection, wallSectionSize, true, wallThickness, cullOpening, null, sectionLib, offset); int[] mapping = submeshLibrary.MapSubmeshes(generatedSection.raw.materials); Vector3 curveNormal = Vector3.Cross(wallDir, Vector3.up); Quaternion meshRot = Quaternion.LookRotation(curveNormal, Vector3.up); Vector3 meshPos = new Vector3(v1.x, volume.baseHeight, v1.z) + wallDir * wallSectionSize.x + Vector3.up * wallSectionSize.y; meshPos += meshRot * -new Vector3(wallSectionSize.x, wallSectionSize.y, 0) * 0.5f; mesh.AddData(generatedSection.raw, mapping, meshPos, meshRot, Vector3.one); } currentWallSectionIndex++; if (currentWallSectionIndex >= currentFacadeWallSectionLength) { //reached the end of the facade - move to the next one and continue currentFacadeWallSectionLength = externalWallAnchors[facadeIndex].Count; currentWallSectionIndex = 0; } } offsetPointBase += wallPointCount - 1; } } //FLOOR Vector2[] mainShape = offsetRoomAnchorPoints; Vector2[][] floorCutPoints = floorCuts.ToArray(); int floorVertCount = mainShape.Length; for (int flc = 0; flc < floorCutPoints.Length; flc++) { floorVertCount += floorCutPoints[flc].Length; } Vector2[] allFloorPoints = new Vector2[floorVertCount]; int mainShapeLength = mainShape.Length; for (int ms = 0; ms < mainShapeLength; ms++) { allFloorPoints[ms] = mainShape[ms]; } int cutPointIterator = mainShapeLength; for (int flc = 0; flc < floorCutPoints.Length; flc++) { for (int flcp = 0; flcp < floorCutPoints[flc].Length; flcp++) { allFloorPoints[cutPointIterator] = floorCutPoints[flc][flcp]; cutPointIterator++; } } Vector3[] floorPoints = new Vector3[floorVertCount]; Vector2[] floorUvs = new Vector2[floorVertCount]; Vector3[] floorNorms = new Vector3[floorVertCount]; Vector4[] floorTangents = new Vector4[floorVertCount]; for (int rp = 0; rp < floorVertCount; rp++) { floorPoints[rp] = new Vector3(allFloorPoints[rp].x, 0, allFloorPoints[rp].y) + floorBaseV; Vector2 uv = allFloorPoints[rp]; if (floorSurface != null) { uv = floorSurface.CalculateUV(uv); } floorUvs[rp] = uv; floorNorms[rp] = Vector3.up; floorTangents[rp] = tangent; } int[] tris = Poly2TriWrapper.Triangulate(mainShape, true, floorCutPoints); mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, floorSubmesh); if (generateColliders) { collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0); } //CEILING! Vector2[][] ceilingCutPoints = ceilingCuts.ToArray(); int ceilingVertCount = mainShape.Length; for (int flc = 0; flc < ceilingCutPoints.Length; flc++) { ceilingVertCount += ceilingCutPoints[flc].Length; } Vector2[] allCeilingPoints = new Vector2[ceilingVertCount]; for (int ms = 0; ms < mainShapeLength; ms++) { allCeilingPoints[ms] = mainShape[ms]; } cutPointIterator = mainShapeLength; for (int flc = 0; flc < ceilingCutPoints.Length; flc++) { for (int flcp = 0; flcp < ceilingCutPoints[flc].Length; flcp++) { allCeilingPoints[cutPointIterator] = ceilingCutPoints[flc][flcp]; cutPointIterator++; } } Vector3[] ceilingPoints = new Vector3[ceilingVertCount]; Vector2[] ceilingUvs = new Vector2[ceilingVertCount]; Vector3[] ceilingNorms = new Vector3[ceilingVertCount]; Vector4[] ceilingTangents = new Vector4[ceilingVertCount]; for (int rp = 0; rp < ceilingVertCount; rp++) { ceilingPoints[rp] = new Vector3(allCeilingPoints[rp].x, wallUp, allCeilingPoints[rp].y) + floorBaseV; Vector2 uv = allCeilingPoints[rp]; if (floorSurface != null) { uv = ceilingSurface.CalculateUV(uv); } ceilingUvs[rp] = uv; ceilingNorms[rp] = Vector3.down; ceilingTangents[rp] = tangent; } tris = Poly2TriWrapper.Triangulate(mainShape, false, ceilingCutPoints); mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, ceilingSubmesh); if (generateColliders) { collider.mesh.AddData(ceilingPoints, ceilingUvs, tris, ceilingNorms, ceilingTangents, 0); } for (int ob = 0; ob < openingCount; ob++) { VerticalOpening opening = openings[ob]; int openingIndex = Array.IndexOf(openings, opening); Vector3 basePosition = openingBounds[openingIndex].center; basePosition.z = basePosition.y; basePosition.y = volume.baseHeight; if (roomOpenings.Contains(opening))//opening used in this floorplan { int externalWallSubmesh = wallSubmesh != -1 ? wallSubmesh : -1; switch (opening.usage) { case VerticalOpening.Usages.Space: if (ceilingCutPoints.Length <= ob) { continue; } Vector3 ceilingCutUpV = Vector3.up * wallThickness; Vector2[] ceilingCut = ceilingCutPoints[ob]; int custSize = ceilingCut.Length; for (int cp = 0; cp < custSize; cp++) { int indexA = (cp + 1) % custSize; int indexB = cp; Vector3 cp0 = new Vector3(ceilingCut[indexA].x, wallUp, ceilingCut[indexA].y) + floorBaseV; Vector3 cp1 = new Vector3(ceilingCut[indexB].x, wallUp, ceilingCut[indexB].y) + floorBaseV; Vector3 cp2 = cp0 + ceilingCutUpV; Vector3 cp3 = cp1 + ceilingCutUpV; mesh.AddPlane(cp0, cp1, cp2, cp3, ceilingSubmesh); if (generateColliders) { collider.AddPlane(cp0, cp1, cp2, cp3); } } break; case VerticalOpening.Usages.Stairwell: StaircaseGenerator.Generate(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider); if (volumeFloor == volume.floors - 1 && opening.baseFloor + opening.floors > building.VolumeBaseFloor(volume) + volume.floors - 1 && volume.abovePlanCount == 0) { StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, externalWallSubmesh, sendCollider); } break; case VerticalOpening.Usages.Elevator: ElevatorShaftGenerator.Generate(ref mesh, opening, actualFloor, basePosition, volume.floorHeight, externalWallSubmesh, sendCollider); break; } } } } for (int ob = 0; ob < openingCount; ob++) { Vector2[] openingShape = openingShapes[ob]; if (openingShape == null) { continue; //opening not used by this floorplan } if (openingUsedInThisFloor[ob]) { continue; //opening already generated } //seal this opening from the void VerticalOpening opening = openings[ob]; int openingIndex = Array.IndexOf(openings, opening); Vector3 basePosition = openingBounds[openingIndex].center; basePosition.z = basePosition.y; basePosition.y = 0; int cutSize = openingShape.Length; Vector3 sealingWallUpV = Vector3.up * volume.floorHeight; int sealWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB); Vector2[] offsetOpeningShape = QuickPolyOffset.Execute(openingShape, wallThickness); for (int cp = 0; cp < cutSize; cp++) { int indexA = (cp + 1) % cutSize; int indexB = cp; Vector2 p0 = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexA] : offsetOpeningShape[indexA]; Vector2 p1 = opening.usage == VerticalOpening.Usages.Space ? openingShape[indexB] : offsetOpeningShape[indexB]; Vector3 cp0 = new Vector3(p0.x, 0, p0.y) + floorBaseV; Vector3 cp1 = new Vector3(p1.x, 0, p1.y) + floorBaseV; Vector3 cp2 = cp0 + sealingWallUpV; Vector3 cp3 = cp1 + sealingWallUpV; mesh.AddPlane(cp0, cp1, cp2, cp3, sealWallSubmesh); if (generateColliders) { collider.AddPlane(cp0, cp1, cp2, cp3); } } switch (opening.usage) { case VerticalOpening.Usages.Space: //nothing to implement break; case VerticalOpening.Usages.Stairwell: //need stairs to connect used floors StaircaseGenerator.GenerateStairs(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider); if (volumeFloor == volume.floors - 1) { StaircaseGenerator.GenerateRoofAccess(mesh, opening, basePosition, volume.floorHeight, actualFloor, -1, sendCollider); } break; case VerticalOpening.Usages.Elevator: //nothing to implement break; } } }
public static void BMesh(BuildRMesh mesh, float height, Surface surface, int submesh, Vector2[] shape, Rect clampUV, bool flipTri = false, Vector2[][] holes = null, BuildRCollider collider = null) { int shapeSize = shape.Length; bool[] useHole = new bool[0]; if (holes != null) { int holeCount = holes.Length; // Debug.Log("BMesh "+holeCount); useHole = new bool[holeCount]; for (int flc = 0; flc < holeCount; flc++) { useHole[flc] = true; int holeSize = holes[flc].Length; // for(int h = 0; h < holeSize; h++) // { // Vector2 holePoint = holes[flc][h]; // holeIntersections[h] = PointInShape(holePoint, shape); //// Debug.Log("intersection length " + intersections.Length); // useHole[flc] = holeIntersections[h].Length == 0; // } // for(int flcp = 0; flcp < holeSize; flcp++) // { // if(!PointInPolygon(holes[flc][flcp], shape)) // { // useHole[flc] = false; // break; // } // } if (useHole[flc]) { shapeSize += holeSize; } } } Vector2[] allFloorPoints = new Vector2[shapeSize]; int mainShapeLength = shape.Length; for (int ms = 0; ms < mainShapeLength; ms++) { allFloorPoints[ms] = shape[ms]; } int cutPointIterator = mainShapeLength; if (holes != null) { for (int flc = 0; flc < holes.Length; flc++) { if (!useHole[flc]) { continue; } for (int flcp = 0; flcp < holes[flc].Length; flcp++) { allFloorPoints[cutPointIterator] = holes[flc][flcp]; cutPointIterator++; } } } FlatBounds bounds = new FlatBounds(); if (clampUV.width > 0) { for (int fvc = 0; fvc < mainShapeLength; fvc++) { bounds.Encapsulate(shape[fvc]); } } Vector3[] floorPoints = new Vector3[shapeSize]; Vector2[] floorUvs = new Vector2[shapeSize]; Vector3[] floorNorms = new Vector3[shapeSize]; Vector4[] floorTangents = new Vector4[shapeSize]; Vector3 normal = flipTri ? Vector3.up : Vector3.down; Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); for (int rp = 0; rp < shapeSize; rp++) { floorPoints[rp] = new Vector3(allFloorPoints[rp].x, height, allFloorPoints[rp].y); if (clampUV.width > 0) { Vector2 clampedUV = new Vector2(); clampedUV.x = ((floorPoints[rp].x - bounds.xMin) / bounds.width) * clampUV.width + clampUV.x; clampedUV.y = ((floorPoints[rp].z - bounds.yMin) / bounds.height) * clampUV.height + clampUV.y; floorUvs[rp] = clampedUV; } else { if (surface != null) { floorUvs[rp] = surface.CalculateUV(allFloorPoints[rp]); } else { floorUvs[rp] = allFloorPoints[rp]; } } floorNorms[rp] = normal; floorTangents[rp] = tangent; } int[] tris = Triangulate(shape, flipTri, holes); // Debug.Log(volumeFloor + " " + actualFloor + " " + floorPoints.Length + " " + tris.Length+" "+r); int useFloorSubmesh = submesh != -1 ? submesh : 0; mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, useFloorSubmesh); if (collider != null) { collider.mesh.AddData(floorPoints, floorUvs, tris, floorNorms, floorTangents, 0); } }
private static void ToMesh(ref BuildRMesh mesh, ref Shape shape, float roofBaseHeight, float meshHeight, int[] facadeIndices, IVolume volume, int submesh, Surface surface, bool generateDormers = false) { //TODO fix this error properly if (shape == null) { Debug.Log("ToMesh: Error to fix"); return; } List <Edge> edges = new List <Edge>(shape.edges); List <Edge> baseEdges = new List <Edge>(shape.baseEdges); float shapeHeight = shape.HeighestPoint(); float heightScale = meshHeight / shapeHeight; bool isFloor = meshHeight < 0.00001f; Dictionary <Node, int> shapeConnectionCount = new Dictionary <Node, int>(); Dictionary <Node, List <Node> > shapeConnections = new Dictionary <Node, List <Node> >(); int edgeCount = edges.Count; for (int e = 0; e < edgeCount; e++) { Edge edge = edges[e]; if (edge.length < Mathf.Epsilon) { continue; } if (!shapeConnectionCount.ContainsKey(edge.nodeA)) { shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeA, new List <Node> { edge.nodeB }); } else { shapeConnectionCount[edge.nodeA]++; if (!shapeConnections[edge.nodeA].Contains(edge.nodeB)) { shapeConnections[edge.nodeA].Add(edge.nodeB); } } if (!shapeConnectionCount.ContainsKey(edge.nodeB)) { shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeB, new List <Node> { edge.nodeA }); } else { shapeConnectionCount[edge.nodeB]++; if (!shapeConnections[edge.nodeB].Contains(edge.nodeA)) { shapeConnections[edge.nodeB].Add(edge.nodeA); } } } int baseEdgeCount = baseEdges.Count; List <Vector3[]> roofFaces = new List <Vector3[]>(); for (int b = 0; b < baseEdgeCount; b++) { int facadeIndex = facadeIndices[b]; bool isGabled = volume[facadeIndex].isGabled; if (!isGabled) { int facadeIndexLeft = (facadeIndex - 1 + volume.numberOfFacades) % volume.numberOfFacades; int facadeIndexRight = (facadeIndex + 1) % volume.numberOfFacades; bool isGabledLeft = volume[facadeIndexLeft].isGabled; bool isGabledRight = volume[facadeIndexRight].isGabled; Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Node currentNode = nodeA; Node lastNode = nodeB; int itMax = 50; List <Node> edgeShape = new List <Node>() { nodeA }; while (currentNode != nodeB) { List <Node> nodeConnections = shapeConnections[currentNode]; int nodeConnectionCount = nodeConnections.Count; float minAngle = Mathf.Infinity; Node nextNode = null; Vector2 currentDirection = (currentNode.position - lastNode.position).normalized; for (int n = 0; n < nodeConnectionCount; n++) { Node connectingNode = nodeConnections[n]; if (connectingNode == lastNode) { continue; //end this circus! } Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized; float nodeAngle = SignAngleDirection(currentDirection, nextDirection); if (nodeAngle < minAngle) { minAngle = nodeAngle; nextNode = connectingNode; } } if (nextNode != null) { edgeShape.Add(nextNode); lastNode = currentNode; currentNode = nextNode; } itMax--; if (itMax < 0) { break; } } int edgeShapeCount = edgeShape.Count; if (edgeShapeCount == 4 && generateDormers) { Vector3[] edgeShapeV3 = new Vector3[4]; edgeShapeV3[0] = new Vector3(edgeShape[0].position.x, roofBaseHeight, edgeShape[0].position.y); edgeShapeV3[1] = new Vector3(edgeShape[3].position.x, roofBaseHeight, edgeShape[3].position.y); edgeShapeV3[2] = new Vector3(edgeShape[1].position.x, roofBaseHeight + meshHeight, edgeShape[1].position.y); edgeShapeV3[3] = new Vector3(edgeShape[2].position.x, roofBaseHeight + meshHeight, edgeShape[2].position.y); roofFaces.Add(edgeShapeV3); } if ((isGabledLeft || isGabledRight) && edgeShapeCount == 4)//modify shape if gables are detected { Vector3 p0 = edgeShape[0].position; Vector3 p1 = edgeShape[3].position; Vector3 p2 = edgeShape[1].position; Vector3 vector = p1 - p0; Vector3 dir = vector.normalized; Vector3 cross = Vector3.Cross(Vector3.back, dir); if (isGabledLeft) { float gableThickness = volume[facadeIndexLeft].gableThickness; bool simpleGable = volume[facadeIndexLeft].simpleGable; Gable gableStyle = volume[facadeIndexLeft].gableStyle; if (!simpleGable && gableStyle == null || !isFloor) { gableThickness = 0; } Vector3 newPointA = Vector3.Project(p2 - p1, cross) + dir * gableThickness; edgeShape[1].position = edgeShape[0].position + new Vector2(newPointA.x, newPointA.y); } if (isGabledRight) { float gableThickness = volume[facadeIndexRight].gableThickness; bool simpleGable = volume[facadeIndexRight].simpleGable; Gable gableStyle = volume[facadeIndexRight].gableStyle; if (!simpleGable && gableStyle == null || !isFloor) { gableThickness = 0; } Vector3 newPointB = Vector3.Project(p2 - p1, cross) - dir * gableThickness; edgeShape[2].position = edgeShape[3].position + new Vector2(newPointB.x, newPointB.y); } } Vector3[] verts = new Vector3[edgeShapeCount]; Vector2[] uvs = new Vector2[edgeShapeCount]; Vector3 baseShapeDirection = ToV3(nodeB.position - nodeA.position).normalized; float uvAngle = SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90; Vector2[] faceShape = new Vector2[edgeShapeCount]; Vector3[] normals = new Vector3[edgeShapeCount]; Vector4[] tangents = new Vector4[edgeShapeCount]; Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection); for (int i = 0; i < edgeShapeCount; i++) { Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y); verts[i] = newVert; Vector2 baseUV = (i == 0) ? Vector2.zero : new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z); Vector2 newUV = Rotate(baseUV, uvAngle); float faceHeight = edgeShape[i].height * heightScale; newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight)); if (surface != null) { newUV = surface.CalculateUV(newUV); } uvs[i] = newUV; faceShape[i] = edgeShape[i].position;//used for triangulation // normals[i] = normal; tangents[i] = tangent; } // int[] tris = EarClipper.Triangulate(faceShape, 0, -1); int[] tris = Poly2TriWrapper.Triangulate(faceShape, true); int triCount = tris.Length; if (triCount < 3) { continue; } Vector3 normal = BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]); for (int i = 0; i < edgeShapeCount; i++) { normals[i] = normal;//normCal[i].normalized; } mesh.AddData(verts, uvs, tris, normals, tangents, submesh); if (isGabled) { for (int t = 0; t < triCount; t += 3) { if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0) { int beB = edgeShapeCount - 1; if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB) { Vector3 b0 = verts[0]; Vector3 b1 = verts[beB]; int topIndex = 0; for (int tx = 0; tx < 3; tx++) { if (tris[t + tx] != 0 && tris[t + tx] != beB) { topIndex = tris[t + tx]; } } Vector3 b2 = verts[topIndex]; Vector3 baseV = b1 - b0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir); // float length = baseV.magnitude; Vector3 center = Vector3.Lerp(b0, b1, 0.5f); Vector3 up = Vector3.Project(b2 - b0, Vector3.up); Vector3 b3 = center + up; mesh.AddTri(b0, b2, b3, face, submesh); //left mesh.AddTri(b1, b3, b2, -face, submesh); //right mesh.AddTri(b0, b3, b1, dir, submesh); //face //clear triangle tris[t] = 0; tris[t + 1] = 0; tris[t + 2] = 0; } } } } } else if (isFloor) { Roof roof = volume.roof; Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Vector3 p0 = new Vector3(nodeA.position.x, heightScale + roofBaseHeight, nodeA.position.y); Vector3 p1 = new Vector3(nodeB.position.x, heightScale + roofBaseHeight, nodeB.position.y); Vector3 baseV = p1 - p0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir).normalized; Vector3 parapetEdgeModifier = dir * (roof.overhang - (roof.parapetFrontDepth + roof.parapetBackDepth)) * 1.05f; p0 += parapetEdgeModifier; p1 += -parapetEdgeModifier; // p0 += face * (roof.parapetFrontDepth + roof.parapetBackDepth + roof.overhang); VolumePoint volumePoint = volume[facadeIndices[b]]; bool simpleGable = volumePoint.simpleGable; Gable gableStyle = volume[facadeIndices[b]].gableStyle; if (!simpleGable && gableStyle == null) { simpleGable = true; } float thickness = volume[facadeIndices[b]].gableThickness; float additionalHeight = volume[facadeIndices[b]].gableHeight; float height = roof.height + additionalHeight; if (simpleGable) //generate a simple gable { int wallSubmesh = mesh.submeshLibrary.SubmeshAdd(roof.wallSurface); //surfaceMapping.IndexOf(roof.wallSurface); if (wallSubmesh == -1) { wallSubmesh = submesh; } Vector3 g0 = p0; Vector3 g1 = p0 + Vector3.up * additionalHeight; Vector3 g2 = g1 + dir * roof.floorDepth * 0.5f; Vector3 g3 = g2 + dir * roof.depth * 0.5f + Vector3.up * roof.height; Vector3 g7 = p1; Vector3 g6 = p1 + Vector3.up * additionalHeight; Vector3 g5 = g6 - dir * roof.floorDepth * 0.5f; Vector3 g4 = g5 - dir * roof.depth * 0.5f + Vector3.up * roof.height; Vector3 gF = -face * thickness; mesh.AddPlane(g0, g7, g1, g6, wallSubmesh); //bottom front mesh.AddPlane(g7 + gF, g0 + gF, g6 + gF, g1 + gF, wallSubmesh); //bottom back mesh.AddPlane(g1, g6, g1 + gF, g6 + gF, wallSubmesh); //bottom top mesh.AddPlane(g0, g1, g0 + gF, g1 + gF, wallSubmesh); //bottom sides mesh.AddPlane(g6, g7, g6 + gF, g7 + gF, wallSubmesh); mesh.AddPlane(g2, g5, g3, g4, wallSubmesh); //top front mesh.AddPlane(g5 + gF, g2 + gF, g4 + gF, g3 + gF, wallSubmesh); //top back mesh.AddPlane(g2 + gF, g2, g3 + gF, g3, wallSubmesh); //top sides mesh.AddPlane(g5, g5 + gF, g4, g4 + gF, wallSubmesh); //top sides mesh.AddPlane(g3 + gF, g3, g4 + gF, g4, wallSubmesh); //top top } else { Vector2 baseUV = new Vector2(0, volume.planHeight); GableGenerator.Generate(ref mesh, gableStyle, p0, p1, height, thickness, baseUV); } } } if (generateDormers) { DormerGenerator.Generate(ref mesh, volume, roofFaces); } }