public void GenerateFromDynamicMesh(BuildRMesh mesh) { if (_mesh == null) { _mesh = new Mesh(); } if (_meshCollider == null) { #if UNITY_EDITOR _meshCollider = UnityEditor.Undo.AddComponent <MeshCollider>(gameObject); #else _meshCollider = gameObject.AddComponent <MeshCollider>(); #endif } // Debug.Log("GenerateFromDynamicMesh "+ _mesh.vertexCount+" "+_mesh.triangles.Length); mesh.Build(_mesh); _meshCollider.sharedMesh = _mesh; if (mesh.hasOverflowed) { if (_sibling == null) { _sibling = Create(transform.parent, name); } _sibling.GenerateFromDynamicMesh(mesh.overflow); } else { if (_sibling != null) { _sibling.DestroyVisual(); } _sibling = null; } }
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 void OnEnable() { _roomStyle = (RoomStyle)target; bMesh = new BuildRMesh("preview mesh"); float width = 3; float height = 1.5f; Vector3 v0 = new Vector3(-width, -height, -width); Vector3 v1 = new Vector3(width, -height, -width); Vector3 v2 = new Vector3(-width, -height, width); Vector3 v3 = new Vector3(width, -height, width); Vector3 v4 = new Vector3(-width, height, -width); Vector3 v5 = new Vector3(width, height, -width); Vector3 v6 = new Vector3(-width, height, width); Vector3 v7 = new Vector3(width, height, width); bMesh.AddPlane(v0, v1, v2, v3, 0); bMesh.AddPlane(v1, v0, v5, v4, 1); bMesh.AddPlane(v3, v1, v7, v5, 1); bMesh.AddPlane(v0, v2, v4, v6, 1); bMesh.AddPlane(v2, v3, v6, v7, 1); bMesh.AddPlane(v6, v7, v4, v5, 2); mesh = new Mesh(); bMesh.submeshLibrary.enabled = false; bMesh.Build(mesh); }
public static void ConvertSkeletonMeshToBuildRMesh(OffsetPolyCore skeleton, ref BuildRMesh mesh, float baseHeight, float height, int submesh) { // //hipped shape // SkeletonTri[] tris = skeleton.data.mesh.GetTriangles(); // foreach (SkeletonTri tri in tris) // { // Vector3 p0 = new Vector3(tri[0].position.x, tri[0].height * height + baseHeight, tri[0].position.y); // Vector3 p1 = new Vector3(tri[1].position.x, tri[1].height * height + baseHeight, tri[1].position.y); // Vector3 p2 = new Vector3(tri[2].position.x, tri[2].height * height + baseHeight, tri[2].position.y); // Vector3[] verts = { p0, p1, p2 }; // Vector3[] norms = { tri.normal, tri.normal, tri.normal }; // Vector4[] tangents = { tri.tangent, tri.tangent, tri.tangent }; // mesh.AddData(verts, tri.uvs, new[] { 0, 2, 1 }, norms, tangents, submesh); // } // // //top shape // Vector2[] topShape = skeleton.data.mesh.topShape().ToArray(); // int shapeSize = topShape.Length; // int[] topTris = EarClipper.Triangulate(topShape); // Vector3[] topVerts = new Vector3[shapeSize]; // Vector2[] topUVs = new Vector2[shapeSize]; // Vector3[] topNormals = new Vector3[shapeSize]; // Vector4[] topTangents = new Vector4[shapeSize]; // Vector4 tangent = DynamicMesh.CalculateTangent(Vector3.right); // for (int t = 0; t < shapeSize; t++) // { // topVerts[t] = new Vector3(topShape[t].x, height, topShape[t].y); // topUVs[t] = topShape[t]; // topNormals[t] = Vector3.up; // topTangents[t] = tangent; // } // mesh.AddData(topVerts, topUVs, topTris, topNormals, topTangents, submesh); }
public static RawMeshData CopyBuildRMesh(BuildRMesh data) { RawMeshData output = new RawMeshData(data.vertices.Count, data.triangles.Count); output.Copy(data); return(output); }
public void GenerateFromDynamicMesh(BuildRMesh mesh) { if (_mesh == null) { _mesh = new Mesh(); } if (_meshCollider == null) { _meshCollider = gameObject.AddComponent <MeshCollider>(); } mesh.Build(_mesh); _meshCollider.sharedMesh = _mesh; if (mesh.hasOverflowed) { if (_sibling == null) { _sibling = Create(transform.parent, name); } _sibling.GenerateFromDynamicMesh(mesh.overflow); } else { if (_sibling != null) { _sibling.Deactivate(); } _sibling = null; } }
/// <summary> /// Project the specified Base UVs to find the appropriate 2D shape from 3D space - mainly used for angled roofs /// </summary> public static Vector2[] Project(Vector3 p0, Vector3 p1, Vector3 p2, Vector2 baseUV) { Vector2[] uvs = new Vector2[3]; Vector3 normal = BuildRMesh.CalculateNormal(p0, p1, p2); Quaternion normalToFaceUp = Quaternion.FromToRotation(normal, Vector3.up); Vector3 pC = (p0 + p1 + p2) / 3f; p0 = normalToFaceUp * (p0 - pC); p1 = normalToFaceUp * (p1 - pC); p2 = normalToFaceUp * (p2 - pC); uvs[0] = new Vector2(p0.x, p0.z); uvs[1] = new Vector2(p1.x, p1.z); uvs[2] = new Vector2(p2.x, p2.z); float minX = Mathf.Min(uvs[0].x, uvs[1].x, uvs[2].x); float minY = Mathf.Min(uvs[0].y, uvs[1].y, uvs[2].y); if (minX < 0) { uvs[0].x += -minX; uvs[1].x += -minX; uvs[2].x += -minX; } if (minY < 0) { uvs[0].y += -minY; uvs[1].y += -minY; uvs[2].y += -minY; } return(uvs); }
public void Init() { HUtils.log(); if (_mesh == null) { _mesh = new Mesh(); } if (_filter == null) { _filter = gameObject.AddComponent <MeshFilter>(); } if (_renderer == null) { _renderer = gameObject.AddComponent <MeshRenderer>(); } if (_dynamicMesh == null) { _dynamicMesh = new BuildRMesh(DYNAMIC_MESH_NAME); } if (_colliderMesh == null) { _colliderMesh = new BuildRCollider(DYNAMIC_COLLIDER_NAME); } }
public static void Generate(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int floor, int wallSubmesh = -1, BuildRCollider collider = null) { if (collider != null) { collider.thickness = VerticalOpening.WALL_THICKNESS; } GenerateWall(mesh, opening, basePosition, height, wallSubmesh, collider); GenerateStairs(mesh, opening, basePosition, height, floor, wallSubmesh, collider); }
private static void Flat(IBuilding building, IVolume volume, BuildRMesh mesh, BuildRCollider collider, Vector2[] points, float roofBaseHeight, Roof design, int submesh, Surface surface, Rect clampUV) { BuildRVolumeUtil.VolumeShape[] roofPoints = BuildRVolumeUtil.GetTopShape(building, volume, points); int roofShapeCount = roofPoints.Length; for (int r = 0; r < roofShapeCount; r++) { Poly2TriWrapper.BMesh(mesh, roofBaseHeight, surface, submesh, roofPoints[r].outer, clampUV, true, roofPoints[r].holes, collider); } }
public void GenerateFromDynamicMesh(BuildRMesh overflow = null) { HUtils.log(); if (_dynamicMesh.vertexCount == 0) { return; } if (_mesh == null) { _mesh = new Mesh(); } if (_filter == null) { _filter = gameObject.AddComponent <MeshFilter>(); } if (_renderer == null) { _renderer = gameObject.AddComponent <MeshRenderer>(); } if (overflow != null) { _dynamicMesh = overflow; } _dynamicMesh.Build(_mesh); _filter.sharedMesh = _mesh; _renderer.sharedMaterials = _dynamicMesh.materials.ToArray(); if (_dynamicMesh.hasOverflowed) { if (_sibling == null) { _sibling = GetPoolItem(); } _sibling.GenerateFromDynamicMesh(_dynamicMesh.overflow); } else { if (_sibling != null) { _sibling.Deactivate(); VisualPartRuntimePool.Instance.Push(_sibling); } _sibling = null; } if (_colliderPart == null) { _colliderPart = ColliderPartRuntime.GetPoolItem(); _colliderPart.GenerateFromColliderMesh(_colliderMesh); } }
public void Copy(BuildRMesh data) { vertices = data.vertices.ToArray(); uvs = data.uvs.ToArray(); triangles = data.triangles.ToArray(); normals = data.normals.ToArray(); tangents = data.tangents.ToArray(); subTriangles = new Dictionary <int, List <int> >(data.subTriangles); vertCount = data.vertexCount; submeshCount = subTriangles.Count; materials = new List <Material>(data.submeshLibrary.MATERIALS); }
private void OnDisable() { if (bMesh != null) { bMesh.Clear(); } bMesh = null; if (mesh != null) { mesh.Clear(); } mesh = null; }
private static void Pitched(BuildRMesh mesh, Vector3[] points, Roof design, int submesh) { int numberOfVolumePoints = points.Length; Vector2[] volumePoints = new Vector2[numberOfVolumePoints]; for (int i = 0; i < numberOfVolumePoints; i++) { volumePoints[i] = new Vector2(points[i].x, points[i].z); } OffsetSkeleton offsetPoly = new OffsetSkeleton(volumePoints); offsetPoly.Execute(); }
public static void OverhangUnderside(ref BuildRMesh mesh, Vector2[] facadePoints, Vector2[] outerPoints, float roofBaseHeight, Roof design) { Vector2[][] facadeHole = new Vector2[1][]; facadeHole[0] = outerPoints; int[] topTris = Poly2TriWrapper.Triangulate(outerPoints, false, facadeHole); // Array.Reverse(topTris); int facadePointCount = facadePoints.Length; int outerPointCount = outerPoints.Length; int usePoints = facadePointCount + outerPointCount; Vector2[] points = new Vector2[usePoints]; for (int f = 0; f < facadePointCount; f++) { points[f] = facadePoints[f]; } for (int o = 0; o < outerPointCount; o++) { points[o + facadePointCount] = outerPoints[o]; } int submesh = mesh.submeshLibrary.SubmeshAdd(design.floorSurface); int vertCount = points.Length; Vector3[] verts = new Vector3[vertCount]; for (int i = 0; i < vertCount; i++) { verts[i] = new Vector3(points[i].x, roofBaseHeight, points[i].y); } Vector2[] uvs = new Vector2[vertCount]; Vector3[] normals = new Vector3[vertCount]; Vector4[] tangents = new Vector4[vertCount]; Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); Surface surface = design.floorSurface; for (int v = 0; v < vertCount; v++) { if (surface != null) { uvs[v] = surface.CalculateUV(points[v]); } normals[v] = Vector3.down; tangents[v] = tangent; } mesh.AddData(verts, uvs, topTris, normals, tangents, submesh); }
public static void MansardRoof(ref BuildRMesh mesh, Vector2[] points, bool[] gabled, float roofBaseHeight, Roof design, List <Surface> surfaceMapping) { float floorWidth = design.floorDepth; float roofDepth = design.depth; float roofHeight = design.height; //mansard floor if (floorWidth > 0) { OffsetSkeleton offsetFloorPoly = new OffsetSkeleton(points, null, floorWidth); offsetFloorPoly.direction = 1; offsetFloorPoly.Execute(); Shape floorShape = offsetFloorPoly.shape; int floorSubmesh = surfaceMapping.IndexOf(design.floorSurface); ToMesh(ref mesh, floorShape, gabled, roofBaseHeight, 0, floorSubmesh, design.floorSurface); points = new Vector2[floorShape.terminatedNodeCount]; for (int i = 0; i < floorShape.terminatedNodeCount; i++) { points[i] = floorShape.TerminatedNode(i).position; } } //mansard roof OffsetSkeleton offsetRoofPoly = new OffsetSkeleton(points, null, roofDepth); offsetRoofPoly.direction = 1; offsetRoofPoly.Execute(); Shape roofShape = offsetRoofPoly.shape; int roofSubmesh = surfaceMapping.IndexOf(design.mainSurface); ToMesh(ref mesh, roofShape, gabled, roofBaseHeight, roofHeight, roofSubmesh, design.mainSurface); points = new Vector2[roofShape.terminatedNodeCount]; for (int i = 0; i < roofShape.terminatedNodeCount; i++) { points[i] = roofShape.TerminatedNode(i).position; } //mansard top int topSubmesh = surfaceMapping.IndexOf(design.floorSurface); ToMesh(ref mesh, points, roofBaseHeight + roofHeight, topSubmesh, design.floorSurface); }
public static void Gambrel(ref BuildRMesh mesh, Vector2[] points, bool[] gabled, float roofBaseHeight, Roof design, List <Surface> surfaceMapping) { float roofDepth = design.depth; float roofHeightB = design.heightB; float roofHeight = design.height - roofHeightB; int roofSubmesh = surfaceMapping.IndexOf(design.mainSurface); for (int p = 0; p < points.Length; p++) { Vector3 p0 = Utils.ToV3(points[p]); Vector3 p1 = Utils.ToV3(points[(p + 1) % points.Length]); Debug.DrawLine(p0, p1); } if (roofDepth > 0) { //slope one OffsetSkeleton offsetRoofPoly = new OffsetSkeleton(points, null, roofDepth); offsetRoofPoly.direction = 1; offsetRoofPoly.Execute(); Shape roofShape = offsetRoofPoly.shape; ToMesh(ref mesh, roofShape, gabled, roofBaseHeight, roofHeightB, roofSubmesh, design.mainSurface); points = new Vector2[roofShape.terminatedNodeCount]; for (int i = 0; i < roofShape.terminatedNodeCount; i++) { points[i] = roofShape.TerminatedNode(i).position; } } else { roofHeight = design.height; roofHeightB = 0; } //slope two OffsetSkeleton offsetRoofPolyB = new OffsetSkeleton(points); offsetRoofPolyB.direction = 1; offsetRoofPolyB.Execute(); Shape roofShapeB = offsetRoofPolyB.shape; ToMesh(ref mesh, roofShapeB, gabled, roofBaseHeight + roofHeightB, roofHeight, roofSubmesh, design.mainSurface); }
private void UpdatePreviewMesh() { string meshName = string.Format("{0}_Preview_Mesh", name); BuildRMesh pBMesh = new BuildRMesh(meshName); if (_previewMesh == null) { _previewMesh = new Mesh(); } _previewMesh.name = meshName; if (_settings == null) { _settings = BuildRSettings.GetSettings(); } Vector3 left = new Vector3(-_settings.previewGableWidth * 0.5f, -_settings.previewGableHeight * 0.5f, 0); Vector3 right = new Vector3(_settings.previewGableWidth * 0.5f, -_settings.previewGableHeight * 0.5f, 0); GableGenerator.Generate(ref pBMesh, this, left, right, _settings.previewGableHeight, _settings.previewGableThickness, new Vector2()); pBMesh.Build(_previewMesh); }
private void UpdatePreview() { FacadeGenerator.FacadeData fData = new FacadeGenerator.FacadeData(); Vector2 sectionSize = new Vector2(2, 3); fData.baseA = new Vector3(0, 0, 0); fData.baseB = new Vector3(sectionSize.x * SIZE.x, 0, 0); fData.controlA = Vector3.zero; fData.controlB = Vector3.zero; List <Vector2Int> anchors = new List <Vector2Int>(); fData.anchors = anchors; fData.isStraight = true; fData.curveStyle = VolumePoint.CurveStyles.Distance; fData.floorCount = SIZE.y; fData.facadeDesign = _facade; fData.startFloor = 0; fData.actualStartFloor = 0; fData.foundationDepth = 0; fData.wallThickness = 0.25f; fData.minimumWallUnitLength = sectionSize.x; fData.floorHeight = sectionSize.y; fData.meshType = BuildingMeshTypes.Full; fData.colliderType = BuildingColliderTypes.None; fData.cullDoors = false; fData.prefabs = null; BuildRMesh dMesh = new BuildRMesh("facade preview"); FacadeGenerator.GenerateFacade(fData, dMesh); _mesh = new Mesh(); dMesh.Build(_mesh); if (_materialList == null) { _materialList = new List <Material>(); } _materialList.Clear(); _materialList.AddRange(dMesh.materials); }
private static void ToMesh(ref BuildRMesh mesh, Vector2[] points, float height, int submesh, Surface surface) { int vertCount = points.Length; Vector3[] verts = new Vector3[vertCount]; for (int i = 0; i < vertCount; i++) { verts[i] = new Vector3(points[i].x, height, points[i].y); } Vector2[] uvs = new Vector2[vertCount]; Vector3[] normals = new Vector3[vertCount]; Vector4[] tangents = new Vector4[vertCount]; Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); for (int v = 0; v < vertCount; v++) { if (surface != null) { uvs[v] = surface.CalculateUV(points[v]); } normals[v] = Vector3.up; tangents[v] = tangent; } // int[] topTris = EarClipper.Triangulate(points); int[] topTris = Poly2TriWrapper.Triangulate(points); for (int t = 0; t < topTris.Length; t += 3) { int ia = topTris[t]; int ib = topTris[t + 1]; int ic = topTris[t + 2]; Debug.DrawLine(verts[topTris[ia]], verts[topTris[ib]]); Debug.DrawLine(verts[topTris[ib]], verts[topTris[ic]]); Debug.DrawLine(verts[topTris[ic]], verts[topTris[ia]]); } mesh.AddData(verts, uvs, topTris, normals, tangents, submesh); }
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 GenerateFacade(FacadeData data, BuildRMesh dmesh, BuildRCollider collider = null) { // Debug.Log("******************* "+data.facadeDesign.ToString()); Vector3 facadeVector = data.baseB - data.baseA; if (facadeVector.magnitude < Mathf.Epsilon) { return; } Vector3 facadeDirection = facadeVector.normalized; Vector3 facadeNormal = Vector3.Cross(facadeDirection, Vector3.up); Vector4 facadeTangent = BuildRMesh.CalculateTangent(facadeDirection); RandomGen rGen = new RandomGen(); rGen.GenerateNewSeed(); float wallThickness = data.wallThickness; float foundation = data.foundationDepth; BuildingMeshTypes meshType = data.meshType; BuildingColliderTypes colliderType = data.colliderType; int wallSections = 0; Vector2 wallSectionSize; float facadeLength = 0; if (data.isStraight) { facadeLength = facadeVector.magnitude; wallSections = Mathf.FloorToInt(facadeLength / data.minimumWallUnitLength); if (wallSections < 1) { wallSections = 1; } wallSectionSize = new Vector2(facadeLength / wallSections, data.floorHeight); } else { wallSections = data.anchors.Count - 1; if (wallSections < 1) { wallSections = 1; } float sectionWidth = Vector2.Distance(data.anchors[0].vector2, data.anchors[1].vector2); wallSectionSize = new Vector2(sectionWidth, data.floorHeight); } Dictionary <WallSection, RawMeshData> generatedSections = new Dictionary <WallSection, RawMeshData>(); Dictionary <WallSection, RawMeshData> generatedSectionMeshColliders = new Dictionary <WallSection, RawMeshData>(); Dictionary <WallSection, BuildRCollider.BBox[]> generatedSectionPrimitiveColliders = new Dictionary <WallSection, BuildRCollider.BBox[]>(); int startFloor = data.startFloor; // Debug.Log("st fl "+startFloor); // Debug.Log("fl ct "+ data.floorCount); for (int fl = startFloor; fl < data.floorCount; fl++) { // Debug.Log(fl); if (data.facadeDesign.randomisationMode == Facade.RandomisationModes.RandomRows) { generatedSections.Clear(); //recalculate each row } // Debug.Log(wallSections); for (int s = 0; s < wallSections; s++) { // Debug.Log(s); WallSection section = data.facadeDesign.GetWallSection(s, fl + data.actualStartFloor, wallSections, data.floorCount); // Debug.Log(section); dmesh.submeshLibrary.Add(section); //add the wallsection to the main submesh library RawMeshData generatedSection = null; RawMeshData generatedSectionCollider = null; BuildRCollider.BBox[] bboxes = new BuildRCollider.BBox[0]; if (section == null) { GenerationOutput output = GenerationOutput.CreateRawOutput(); GenerationOutput outputCollider = null; if (colliderType == BuildingColliderTypes.Complex) { outputCollider = GenerationOutput.CreateRawOutput(); } if (colliderType == BuildingColliderTypes.Primitive) { BuildRCollider.BBox[] bbox = WallSectionGenerator.Generate(section, wallSectionSize, wallThickness); generatedSectionPrimitiveColliders.Add(section, bbox); } WallSectionGenerator.Generate(section, output, wallSectionSize, false, wallThickness, true, outputCollider, dmesh.submeshLibrary); generatedSection = output.raw; if (outputCollider != null) { generatedSectionCollider = outputCollider.raw; } } else { if (generatedSections.ContainsKey(section)) { generatedSection = generatedSections[section]; if (generatedSectionMeshColliders.ContainsKey(section)) { generatedSectionCollider = generatedSectionMeshColliders[section]; } } else { GenerationOutput output = GenerationOutput.CreateRawOutput(); GenerationOutput outputCollider = null; bool cullOpening = data.cullDoors && section.isDoor; if (colliderType == BuildingColliderTypes.Complex) { outputCollider = GenerationOutput.CreateRawOutput(); } if (colliderType == BuildingColliderTypes.Primitive) { BuildRCollider.BBox[] bbox = WallSectionGenerator.Generate(section, wallSectionSize, wallThickness, cullOpening); generatedSectionPrimitiveColliders.Add(section, bbox); } WallSectionGenerator.Generate(section, output, wallSectionSize, false, wallThickness, cullOpening, outputCollider, dmesh.submeshLibrary); generatedSections.Add(section, output.raw); if (generatedSectionCollider != null) { generatedSectionMeshColliders.Add(section, outputCollider.raw); } generatedSection = output.raw; if (generatedSectionCollider != null) { generatedSectionCollider = outputCollider.raw; } } if (generatedSectionPrimitiveColliders.ContainsKey(section)) { bboxes = generatedSectionPrimitiveColliders[section]; } } // Debug.Log("data strt" + data.isStraight); if (data.isStraight) { Quaternion meshRot = Quaternion.LookRotation(facadeNormal, Vector3.up); Vector3 baseMeshPos = data.baseA + facadeDirection * wallSectionSize.x + Vector3.up * wallSectionSize.y; Vector3 wallSectionVector = new Vector3(wallSectionSize.x * s, wallSectionSize.y * fl, 0); baseMeshPos += meshRot * wallSectionVector; Vector3 meshPos = baseMeshPos + meshRot * -wallSectionSize * 0.5f; Vector2 uvOffset = new Vector2(wallSectionSize.x * s, wallSectionSize.y * fl); Vector2 uvOffsetScaled = uvOffset; if (section != null && section.wallSurface != null) { uvOffsetScaled = CalculateUv(uvOffsetScaled, section.wallSurface); } //TODO account for the mesh mode of the wall section - custom meshes if (meshType == BuildingMeshTypes.Full) { dmesh.AddData(generatedSection, meshPos, meshRot, Vector3.one, uvOffsetScaled); } if (collider != null && generatedSectionCollider != null) { collider.mesh.AddData(generatedSectionCollider, meshPos, meshRot, Vector3.one); } if (collider != null && bboxes.Length > 0) { collider.AddBBox(bboxes, meshPos, meshRot); } // Debug.Log("foundation"); if (fl == 0 && foundation > Mathf.Epsilon) { Vector3 fp3 = baseMeshPos + Vector3.down * wallSectionSize.y; Vector3 fp2 = fp3 - facadeDirection * wallSectionSize.x; Vector3 fp0 = fp2 + Vector3.down * foundation; Vector3 fp1 = fp3 + Vector3.down * foundation; if (meshType == BuildingMeshTypes.Full) { Surface foundationSurface = data.foundationSurface != null ? data.foundationSurface : section.wallSurface; int foundationSubmesh = dmesh.submeshLibrary.SubmeshAdd(foundationSurface); //facadeSurfaces.IndexOf(section.wallSurface)); dmesh.AddPlane(fp0, fp1, fp2, fp3, new Vector2(uvOffset.x, -foundation), new Vector2(uvOffset.x + wallSectionSize.x, 0), -facadeNormal, facadeTangent, foundationSubmesh, foundationSurface); } if (collider != null && generatedSectionCollider != null) { collider.mesh.AddPlane(fp0, fp1, fp2, fp3, 0); } } } else { //todo switch - support wall section based curves for now Vector3 cp0 = data.anchors[s].vector3XZ; cp0.y = data.baseA.y; Vector3 cp1 = data.anchors[s + 1].vector3XZ; cp1.y = data.baseA.y; Vector3 curveVector = cp1 - cp0; Vector3 curveDirection = curveVector.normalized; Vector3 curveNormal = Vector3.Cross(curveDirection, Vector3.up); float actualWidth = curveVector.magnitude; Quaternion meshRot = Quaternion.LookRotation(curveNormal, Vector3.up); Vector3 meshPos = cp1 + Vector3.up * wallSectionSize.y; Vector3 wallSectionVector = new Vector3(0, wallSectionSize.y * fl, 0); meshPos += meshRot * wallSectionVector; meshPos += meshRot * -new Vector3(actualWidth, wallSectionSize.y, 0) * 0.5f; Vector3 meshScale = new Vector3(actualWidth / wallSectionSize.x, 1, 1); //Thanks Anthony Cuellar - issue #12 Vector2 uvOffset = new Vector2(wallSectionVector.x, wallSectionVector.y + (section.hasOpening ? 0 : wallSectionSize.y / 2f)); Vector2 uvOffsetScaled = CalculateUv(uvOffset, section.wallSurface); //TODO account for the mesh mode of the wall section - custom meshes if (meshType == BuildingMeshTypes.Full) { dmesh.AddData(generatedSection, meshPos, meshRot, meshScale, uvOffsetScaled); } if (collider != null && generatedSectionCollider != null) { collider.mesh.AddData(generatedSectionCollider, meshPos, meshRot, meshScale); } if (collider != null && bboxes.Length > 0) { collider.AddBBox(bboxes, meshPos, meshRot); } // Debug.Log("foundation"); if (fl == 0 && foundation > Mathf.Epsilon) { Vector3 fp3 = cp1; Vector3 fp2 = fp3 - curveDirection * actualWidth; Vector3 fp0 = fp2 + Vector3.down * foundation; Vector3 fp1 = fp3 + Vector3.down * foundation; if (meshType == BuildingMeshTypes.Full) { Surface foundationSurface = data.foundationSurface != null ? data.foundationSurface : section.wallSurface; int foundationSubmesh = dmesh.submeshLibrary.SubmeshAdd(foundationSurface); //facadeSurfaces.IndexOf(section.wallSurface); dmesh.AddPlane(fp0, fp1, fp2, fp3, new Vector2(uvOffset.x, -foundation), new Vector2(uvOffset.x + actualWidth, 0), -curveNormal, facadeTangent, foundationSubmesh, foundationSurface); } if (collider != null && generatedSectionCollider != null) { collider.mesh.AddPlane(fp0, fp1, fp2, fp3, 0); } } } } //string course is completely ignored for a collision // Debug.Log("string"); if (fl > 0 && data.facadeDesign.stringCourse && meshType == BuildingMeshTypes.Full) //no string course on ground floor { float baseStringCoursePosition = wallSectionSize.y * fl + wallSectionSize.y * data.facadeDesign.stringCoursePosition; Vector3 scBaseUp = baseStringCoursePosition * Vector3.up; Vector3 scTopUp = (data.facadeDesign.stringCourseHeight + baseStringCoursePosition) * Vector3.up; if (data.isStraight) { Vector3 scNm = data.facadeDesign.stringCourseDepth * facadeNormal; Vector3 p0 = data.baseA; Vector3 p1 = data.baseB; Vector3 p0o = data.baseA - scNm; Vector3 p1o = data.baseB - scNm; int submesh = dmesh.submeshLibrary.SubmeshAdd(data.facadeDesign.stringCourseSurface); //data.facadeDesign.stringCourseSurface != null ? facadeSurfaces.IndexOf(data.facadeDesign.stringCourseSurface) : 0; Vector2 uvMax = new Vector2(facadeLength, data.facadeDesign.stringCourseHeight); dmesh.AddPlane(p0o + scBaseUp, p1o + scBaseUp, p0o + scTopUp, p1o + scTopUp, Vector3.zero, uvMax, -facadeNormal, facadeTangent, submesh, data.facadeDesign.stringCourseSurface); //front dmesh.AddPlane(p0 + scBaseUp, p0o + scBaseUp, p0 + scTopUp, p0o + scTopUp, facadeNormal, facadeTangent, submesh); //left dmesh.AddPlane(p1o + scBaseUp, p1 + scBaseUp, p1o + scTopUp, p1 + scTopUp, facadeNormal, facadeTangent, submesh); //right float facadeAngle = BuildrUtils.CalculateFacadeAngle(facadeDirection); dmesh.AddPlaneComplexUp(p0 + scBaseUp, p1 + scBaseUp, p0o + scBaseUp, p1o + scBaseUp, facadeAngle, Vector3.down, facadeTangent, submesh, data.facadeDesign.stringCourseSurface); //bottom dmesh.AddPlaneComplexUp(p1 + scTopUp, p0 + scTopUp, p1o + scTopUp, p0o + scTopUp, facadeAngle, Vector3.up, facadeTangent, submesh, data.facadeDesign.stringCourseSurface); //top } else { int baseCurvePointCount = data.anchors.Count; //baseCurvepoints.Count; Vector3[] interSectionNmls = new Vector3[baseCurvePointCount]; for (int i = 0; i < baseCurvePointCount - 1; i++) { Vector3 p0 = data.anchors[i].vector3XZ; //baseCurvepoints[i]; Vector3 p1 = data.anchors[i + 1].vector3XZ; //baseCurvepoints[i + 1]; Vector3 p2 = data.anchors[Mathf.Max(i - 1, 0)].vector3XZ; //baseCurvepoints[Mathf.Max(i - 1, 0)]; interSectionNmls[i] = Vector3.Cross((p1 - p0 + p0 - p2).normalized, Vector3.up); } for (int i = 0; i < baseCurvePointCount - 1; i++) { Vector3 p0 = data.anchors[i].vector3XZ; //baseCurvepoints[i]; Vector3 p1 = data.anchors[i + 1].vector3XZ; //baseCurvepoints[i + 1]; Vector3 sectionVector = p1 - p0; Vector3 sectionDir = sectionVector.normalized; Vector3 sectionNml = Vector3.Cross(sectionDir, Vector3.up); Vector4 sectionTgnt = BuildRMesh.CalculateTangent(sectionDir); Vector3 scNmA = data.facadeDesign.stringCourseDepth * interSectionNmls[i + 0]; Vector3 scNmB = data.facadeDesign.stringCourseDepth * interSectionNmls[i + 1]; Vector3 p0o = p0 - scNmA; Vector3 p1o = p1 - scNmB; int submesh = dmesh.submeshLibrary.SubmeshAdd(data.facadeDesign.stringCourseSurface); //data.facadeDesign.stringCourseSurface != null ? facadeSurfaces.IndexOf(data.facadeDesign.stringCourseSurface) : 0; dmesh.AddPlane(p0o + scBaseUp, p1o + scBaseUp, p0o + scTopUp, p1o + scTopUp, sectionNml, sectionTgnt, submesh); dmesh.AddPlane(p0 + scBaseUp, p0o + scBaseUp, p0 + scTopUp, p0o + scTopUp, sectionNml, sectionTgnt, submesh); dmesh.AddPlane(p1o + scBaseUp, p1 + scBaseUp, p1o + scTopUp, p1 + scTopUp, sectionNml, sectionTgnt, submesh); float facadeAngle = BuildrUtils.CalculateFacadeAngle(sectionDir); dmesh.AddPlaneComplexUp(p0 + scBaseUp, p1 + scBaseUp, p0o + scBaseUp, p1o + scBaseUp, facadeAngle, Vector3.down, sectionTgnt, submesh, data.facadeDesign.stringCourseSurface); //bottom dmesh.AddPlaneComplexUp(p1 + scTopUp, p0 + scTopUp, p1o + scTopUp, p0o + scTopUp, facadeAngle, Vector3.up, sectionTgnt, submesh, data.facadeDesign.stringCourseSurface); //top } } } } }
public static void Generate(IBuilding building) { int numberOfVolumes = building.numberOfVolumes; // Debug.Log("n vol "+numberOfVolumes); for (int v = 0; v < numberOfVolumes; v++) { IVolume volume = building[v]; volume.CheckVolume(); if (!volume.isLegal) { GenerateMesh.ClearVisuals(volume); continue; } int numberOfPoints = volume.numberOfPoints; float totalPlanHeight = volume.planHeight; Vector3 planUp = totalPlanHeight * Vector3.up; VerticalOpening[] volumeOpenings = BuildrUtils.GetOpeningsQuick(building, volume); float foundation = building.IsBaseVolume(volume) ? building.foundationDepth : 0;//set suspended volumes foundation to 0 IVisualPart visual = volume.visualPart; BuildRMesh dMesh = visual.dynamicMesh; BuildRCollider cMesh = visual.colliderMesh; BuildingMeshTypes meshType = building.meshType; BuildingColliderTypes colliderType = building.colliderType; dMesh.Clear(); cMesh.Clear(); cMesh.TogglePrimitives(colliderType == BuildingColliderTypes.Primitive); cMesh.thickness = volume.wallThickness; if (colliderType == BuildingColliderTypes.None) { cMesh = null; } Transform[] prefabs = volume.prefabs.GetComponentsInChildren <Transform>(); int prefabCount = prefabs.Length; for (int p = 0; p < prefabCount; p++) { if (prefabs[p] == volume.prefabs) { continue; } if (prefabs[p] == null) { continue; //gone already man } #if UNITY_EDITOR Object.DestroyImmediate(prefabs[p].gameObject); #else Object.Destroy(prefabs[p].gameObject); #endif } Dictionary <int, List <Vector2Int> > anchorPoints = volume.facadeWallAnchors; Texture2D facadeTexture = null; #region Exteriors // Debug.Log("ext"); if (building.generateExteriors) { for (int p = 0; p < numberOfPoints; p++) { if (!volume[p].render) { continue; } Vector3 p0 = volume.BuildingPoint(p); Vector3 p1 = volume.BuildingPoint((p + 1) % numberOfPoints); Vector3 p0u = p0 + planUp; Vector3 p1u = p1 + planUp; Vector3 cw0 = volume.BuildingControlPointA(p); Vector3 cw1 = volume.BuildingControlPointB(p); Facade facade = volume.GetFacade(p); bool isStraight = volume.IsWallStraight(p); Vector3 facadeVector = p1 - p0; Vector3 facadeDirection = facadeVector.normalized; float facadeLength = facadeVector.magnitude; if (facadeLength < Mathf.Epsilon) { continue; } // Debug.Log("flength "+facadeLength); if (facade == null || colliderType == BuildingColliderTypes.Simple) { // Debug.Log("simple"); if (isStraight) { Vector3 normal = Vector3.Cross(Vector3.up, facadeDirection); Vector4 tangent = BuildRMesh.CalculateTangent(facadeDirection); if (facade == null) { dMesh.AddPlane(p0, p1, p0u, p1u, normal, tangent, 0); } if (colliderType != BuildingColliderTypes.None) { cMesh.AddPlane(p0, p1, p0u, p1u); } if (foundation > Mathf.Epsilon) { Vector3 fp2 = p0; Vector3 fp3 = p1; Vector3 fp0 = fp2 + Vector3.down * foundation; Vector3 fp1 = fp3 + Vector3.down * foundation; if (facade == null) { Surface foundationSurface = building.foundationSurface != null ? building.foundationSurface : null; int foundationSubmesh = dMesh.submeshLibrary.SubmeshAdd(foundationSurface); Vector2 uxmax = new Vector2(Vector3.Distance(p0, p1), foundation); dMesh.AddPlane(fp0, fp1, fp2, fp3, Vector2.zero, uxmax, normal, tangent, foundationSubmesh, foundationSurface); } if (colliderType != BuildingColliderTypes.None) { cMesh.mesh.AddPlane(fp0, fp1, fp2, fp3, 0); } } } else { List <Vector2Int> facadeAnchorPoints = anchorPoints[p]; int anchorCount = facadeAnchorPoints.Count; for (int i = 0; i < anchorCount - 1; i++) { Vector3 c0 = facadeAnchorPoints[i].vector3XZ; c0.y = p0.y; Vector3 c1 = facadeAnchorPoints[i + 1].vector3XZ; c1.y = p0.y; Vector3 c2 = c0 + planUp; Vector3 c3 = c1 + planUp; Vector3 sectionDirection = (c1 - c0).normalized; Vector3 normal = Vector3.Cross(Vector3.up, sectionDirection); Vector4 tangent = BuildRMesh.CalculateTangent(sectionDirection); if (facade == null) { dMesh.AddPlane(c0, c1, c2, c3, normal, tangent, 0); } if (colliderType != BuildingColliderTypes.None) { cMesh.AddPlane(c0, c1, c2, c3); } if (foundation > Mathf.Epsilon) { Vector3 fp2 = c0; Vector3 fp3 = c1; Vector3 fp0 = fp2 + Vector3.down * foundation; Vector3 fp1 = fp3 + Vector3.down * foundation; if (facade == null) { Surface foundationSurface = building.foundationSurface != null ? building.foundationSurface : null; int foundationSubmesh = dMesh.submeshLibrary.SubmeshAdd(foundationSurface); Vector2 uxmax = new Vector2(Vector3.Distance(c0, c1), foundation); dMesh.AddPlane(fp0, fp1, fp2, fp3, Vector2.zero, uxmax, normal, tangent, foundationSubmesh, foundationSurface); } if (colliderType != BuildingColliderTypes.None) { cMesh.AddPlane(fp0, fp1, fp2, fp3); } } } } // Debug.Log("Generate facade " + p + " " + dMesh.vertexCount ); } // Debug.Log("fac "+p); if (facade != null && (meshType == BuildingMeshTypes.Full || colliderType == BuildingColliderTypes.Primitive || colliderType == BuildingColliderTypes.Complex)) { //generate the facade // Debug.Log("full"); FacadeGenerator.FacadeData fData = new FacadeGenerator.FacadeData(); // fData.building = building; // fData.volume = volume; fData.baseA = p0; fData.baseB = p1; fData.controlA = cw0; fData.controlB = cw1; fData.anchors = anchorPoints[p]; fData.isStraight = isStraight; fData.curveStyle = volume[p].curveStyle; fData.floorCount = volume.floors; fData.facadeDesign = facade; // fData.submeshList = usedFloorplanSurfaces; fData.startFloor = BuildRFacadeUtil.MinimumFloor(building, volume, p); fData.actualStartFloor = building.VolumeBaseFloor(volume); fData.foundationDepth = foundation; fData.foundationSurface = building.foundationSurface; fData.wallThickness = volume.wallThickness; fData.minimumWallUnitLength = volume.minimumWallUnitLength; fData.floorHeight = volume.floorHeight; fData.floors = volume.floors; fData.meshType = building.meshType; fData.colliderType = building.colliderType; fData.cullDoors = building.cullDoors; fData.prefabs = volume.prefabs; // Debug.Log("mesh"); FacadeGenerator.GenerateFacade(fData, dMesh, cMesh); // Debug.Log("pref"); FacadeGenerator.GeneratePrefabs(fData); // Debug.Log("Generate facade "+p+" "+dMesh.vertexCount); } } } #endregion #region Interiors // Debug.Log("int"); bool generateInteriors = building.generateInteriors && meshType == BuildingMeshTypes.Full; if (generateInteriors) { int floors = volume.floors; IFloorplan[] floorplans = volume.InteriorFloorplans(); for (int fl = 0; fl < floors; fl++) { IFloorplan floorplan = floorplans[fl]; IVisualPart floorVisual = floorplan.visualPart; BuildRMesh flMesh = floorVisual.dynamicMesh; BuildRCollider flCollider = floorVisual.colliderMesh; flMesh.Clear(); flCollider.Clear(); flCollider.TogglePrimitives(colliderType == BuildingColliderTypes.Primitive); FloorplanGenerator.Generate(building, volume, floorplans[fl], fl, volumeOpenings, flMesh, flCollider); floorVisual.GenerateFromDynamicMesh(); floorplan.transform.localPosition = Vector3.up * (fl * volume.floorHeight); floorVisual.transform.localPosition = Vector3.zero;// floorVisual.transform.localRotation = Quaternion.identity; } } else { IFloorplan[] floorplans = volume.InteriorFloorplans(); int floors = floorplans.Length; for (int fl = 0; fl < floors; fl++) { floorplans[fl].visualPart.Clear(); } } #endregion #region Volume Underside Generation // Debug.Log("und"); BuildRVolumeUtil.VolumeShape[] underShapes = BuildRVolumeUtil.GetBottomShape(building, volume); int underShapeCount = underShapes.Length; float volumeBaseHeight = volume.baseHeight - building.foundationDepth; for (int u = 0; u < underShapeCount; u++) { if (underShapes[u].outer == null) { continue; //no underside shape } int undersideSubmesh = dMesh.submeshLibrary.SubmeshAdd(volume.undersideSurafce); Poly2TriWrapper.BMesh(dMesh, volumeBaseHeight, null, undersideSubmesh, underShapes[u].outer, new Rect(0, 0, 0, 0), false, underShapes[u].holes); } #endregion // Debug.Log("roof"); if (building.generateExteriors) { RoofGenerator.Generate(building, volume, dMesh, cMesh); visual.GenerateFromDynamicMesh(); } else { visual.Clear(); } // Debug.Log("mat"); switch (meshType) { case BuildingMeshTypes.None: visual.materials = null; break; case BuildingMeshTypes.Box: visual.materials = new[] { new Material(Shader.Find("Standard")) }; break; case BuildingMeshTypes.Simple: facadeTexture.filterMode = FilterMode.Bilinear; facadeTexture.Apply(true, false); Material simpleMaterial = new Material(Shader.Find("Standard")); simpleMaterial.mainTexture = facadeTexture; visual.materials = new[] { simpleMaterial }; break; case BuildingMeshTypes.Full: visual.materials = dMesh.materials.ToArray(); break; } } }
public static bool Generate(BuildRMesh mesh, BuildRCollider collider, Vector2[] points, int[] facadeIndices, float roofBaseHeight, IVolume volume, Rect clampUV) { Roof design = volume.roof; OffsetSkeleton offsetPoly = new OffsetSkeleton(points); offsetPoly.direction = 1; offsetPoly.Execute(); Shape shape = offsetPoly.shape; int submesh = mesh.submeshLibrary.SubmeshAdd(design.mainSurface); // surfaceMapping.IndexOf(design.mainSurface); int wallSubmesh = mesh.submeshLibrary.SubmeshAdd(design.wallSurface); //surfaceMapping.IndexOf(design.wallSurface); if (shape == null) { return(false); } List <Edge> edges = new List <Edge>(shape.edges); List <Edge> baseEdges = new List <Edge>(shape.baseEdges); float shapeHeight = shape.HeighestPoint(); float designHeight = design.height; float heightScale = designHeight / shapeHeight; Vector2 clampUVScale = Vector2.one; if (clampUV.width > 0) { FlatBounds bounds = new FlatBounds(); for (int fvc = 0; fvc < points.Length; fvc++) { bounds.Encapsulate(points[fvc]); } clampUVScale.x = bounds.width / clampUV.width; clampUVScale.y = bounds.height / clampUV.height; } Dictionary <Node, int> shapeConnectionCount = new Dictionary <Node, int>(); Dictionary <Node, List <Node> > shapeConnections = new Dictionary <Node, List <Node> >(); int edgeCount = edges.Count; for (int e = 0; e < edgeCount; e++) { Edge edge = edges[e]; if (edge.length < Mathf.Epsilon) { continue; } if (!shapeConnectionCount.ContainsKey(edge.nodeA)) { shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeA, new List <Node> { edge.nodeB }); } else { shapeConnectionCount[edge.nodeA]++; if (!shapeConnections[edge.nodeA].Contains(edge.nodeB)) { shapeConnections[edge.nodeA].Add(edge.nodeB); } } if (!shapeConnectionCount.ContainsKey(edge.nodeB)) { shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeB, new List <Node> { edge.nodeA }); } else { shapeConnectionCount[edge.nodeB]++; if (!shapeConnections[edge.nodeB].Contains(edge.nodeA)) { shapeConnections[edge.nodeB].Add(edge.nodeA); } } } int baseEdgeCount = baseEdges.Count; for (int b = 0; b < baseEdgeCount; b++) { Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Node currentNode = nodeA; Node lastNode = nodeB; int itMax = 50; List <Node> edgeShape = new List <Node>() { nodeA }; while (currentNode != nodeB) { List <Node> nodeConnections = shapeConnections[currentNode]; int nodeConnectionCount = nodeConnections.Count; float minAngle = Mathf.Infinity; Node nextNode = null; Vector2 currentDirection = (currentNode.position - lastNode.position).normalized; for (int n = 0; n < nodeConnectionCount; n++) { Node connectingNode = nodeConnections[n]; if (connectingNode == lastNode) { continue; } Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized; float nodeAngle = JMath.SignAngleDirection(currentDirection, nextDirection); if (nodeAngle < minAngle) { minAngle = nodeAngle; nextNode = connectingNode; } } if (nextNode != null) { edgeShape.Add(nextNode); lastNode = currentNode; currentNode = nextNode; } itMax--; if (itMax < 0) { break; } } int edgeShapeCount = edgeShape.Count; if (edgeShapeCount < 3) { continue; } // Debug.Log("Generate edgeShapeCount "+ edgeShapeCount); Vector3[] verts = new Vector3[edgeShapeCount]; Vector2[] uvs = new Vector2[edgeShapeCount]; Vector3 baseShapeDirection = ShapeOffset.Utils.ToV3(nodeB.position - nodeA.position).normalized; float uvAngle = JMath.SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90; Vector2[] faceShape = new Vector2[edgeShapeCount]; Vector3[] normals = new Vector3[edgeShapeCount]; Vector4[] tangents = new Vector4[edgeShapeCount]; // Vector3 normal = Vector3.up;//BuildRMesh.CalculateNormal(); TODO Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection); for (int i = 0; i < edgeShapeCount; i++)//what on earth did I write here? { Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y); verts[i] = newVert; Vector2 baseUV = new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z); Vector2 newUV = Vector2.zero; if (i != 0) { newUV = JMath.Rotate(baseUV, uvAngle); } if (clampUV.width > Mathf.Epsilon) { newUV.x = Mathf.Clamp(clampUV.x + newUV.x / clampUVScale.x, clampUV.xMin, clampUV.xMax); newUV.y = Mathf.Clamp(clampUV.y + newUV.y / clampUVScale.y, clampUV.yMin, clampUV.yMax); } else { if (i != 0) { float faceHeight = edgeShape[i].height * heightScale; newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight));//hypotenuse of roof to give length of roof face if (design.mainSurface != null) { newUV = design.mainSurface.CalculateUV(newUV); } } } uvs[i] = newUV; faceShape[i] = edgeShape[i].position;//used for triangulation // normals[i] = normal; tangents[i] = tangent; } // int[] tris = EarClipper.Triangulate(faceShape, 0, -1); int[] tris = Poly2TriWrapper.Triangulate(faceShape, true); int triCount = tris.Length; Vector3 normal = (verts.Length > 2 && triCount > 2) ? BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]) : Vector3.up; for (int i = 0; i < edgeShapeCount; i++) { normals[i] = normal; } mesh.AddData(verts, uvs, tris, normals, tangents, submesh); //gable bool isGabled = volume[facadeIndices[b]].isGabled; if (isGabled) { for (int t = 0; t < triCount; t += 3) { if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0) { int beB = edgeShapeCount - 1; if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB) { Vector3 b0 = verts[0]; Vector3 b1 = verts[beB]; Vector3 g0 = b0; Vector3 g1 = b1; int topIndex = 0; for (int tx = 0; tx < 3; tx++) { if (tris[t + tx] != 0 && tris[t + tx] != beB) { topIndex = tris[t + tx]; } } Vector3 b2 = verts[topIndex]; Vector3 baseV = b1 - b0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir).normalized; Vector3 up = Vector3.Project(b2 - b0, Vector3.up); //clear triangle tris[t] = 0; tris[t + 1] = 0; tris[t + 2] = 0; bool simpleGable = volume[facadeIndices[b]].simpleGable; Gable gableStyle = volume[facadeIndices[b]].gableStyle; float thickness = volume[facadeIndices[b]].gableThickness; float additionalHeight = volume[facadeIndices[b]].gableHeight; float height = up.magnitude + additionalHeight; if (simpleGable || gableStyle != null) { Vector3 pitchVectorA = (b2 - b0).normalized; Vector3 pitchVectorB = (b2 - b1).normalized; float angle = Vector3.Angle(-face, pitchVectorA); float scale = Mathf.Cos(angle / 57.2957795f); b0 += pitchVectorA * (thickness * (1 / scale)); b1 += pitchVectorB * (thickness * (1 / scale)); } Vector3 center = Vector3.Lerp(b0, b1, 0.5f); up = Vector3.Project(b2 - b0, Vector3.up); //recalculate after b change(?) Vector3 b3 = center + up; if (simpleGable) //generate a simple gable { //generate simple gable based on roof Vector3 gCenter = Vector3.Lerp(g0, g1, 0.5f); Vector3 gBaseUp = Vector3.up * additionalHeight; Vector3 gUp = up.normalized * height; Vector3 gBack = -face * thickness; //todo further calculations //face mesh.AddPlane(g0, g1, g0 + gBaseUp, g1 + gBaseUp, wallSubmesh); mesh.AddTri(g1 + gBaseUp, g0 + gBaseUp, gCenter + gUp, dir, wallSubmesh); //backface mesh.AddPlane(g1 + gBack, g0 + gBack, g1 + gBaseUp + gBack, g0 + gBaseUp + gBack, wallSubmesh); mesh.AddTri(g0 + gBack + gBaseUp, g1 + gBack + gBaseUp, b3 + gBaseUp, -dir, wallSubmesh); //left mesh.AddPlane(g0 + gBack, g0, g0 + gBaseUp + gBack, g0 + gBaseUp, wallSubmesh); mesh.AddPlane(g0 + gBaseUp + gBack, g0 + gBaseUp, b3 + gBaseUp, gCenter + gUp, wallSubmesh); //right mesh.AddPlane(g1, g1 + gBack, g1 + gBaseUp, g1 + gBaseUp + gBack, wallSubmesh); mesh.AddPlane(g1 + gBaseUp, g1 + gBaseUp + gBack, gCenter + gUp, b3 + gBaseUp, wallSubmesh); } else if (volume[facadeIndices[b]].gableStyle != null) { Vector2 baseUV = new Vector2(0, volume.planHeight); GableGenerator.Generate(ref mesh, gableStyle, g0, g1, height, thickness, baseUV); } else { mesh.AddTri(b0, b3, b1, dir, submesh);//face - no separate gable } mesh.AddTri(b0, b2, b3, face, submesh); //left mesh.AddTri(b1, b3, b2, -face, submesh); //right } } } } } return(true); }
public static void GenerateStairs(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int floor, int wallSubmesh = -1, BuildRCollider collider = null) { bool stepped = true; //todo float minimumWidth = 0.9f; //UK standard float stepHeight = 0.22f; float wallThickness = VerticalOpening.WALL_THICKNESS; bool generateColldier = collider != null; float minimumRunLength = 0.25f; float maximumRiserHeight = 0.2f; int internalWallSubmesh = mesh.submeshLibrary.SubmeshAdd(opening.surfaceB); int internalFloorSubmesh = mesh.submeshLibrary.SubmeshAdd(opening.surfaceD); bool isBottomFloor = opening.baseFloor == floor; bool isTopFloor = opening.baseFloor + opening.floors == floor; // Debug.Log((opening.baseFloor + opening.floors - 1) +" "+ floor); //base positions Quaternion rotation = Quaternion.Euler(0, opening.rotation, 0); Vector2Int openingSize = opening.size; Vector3 b0 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b1 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b2 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); Vector3 b3 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); //inner points Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness; Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness; Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness; Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness; Vector2 internalSize = new Vector2(openingSize.vx - wallThickness * 2, openingSize.vy - wallThickness * 2); float stairWidthFromX = internalSize.x * 0.5f; float stairWidthFromY = internalSize.y - Mathf.Ceil(height / maximumRiserHeight) * minimumRunLength; float useLandingWidth = (stairWidthFromX + stairWidthFromY) * 0.5f; useLandingWidth = Mathf.Clamp(useLandingWidth, minimumWidth, opening.stairWidth); //Mathf.Max(stairWidth, internalSize.x * 0.5f)); float useStairWidth = Mathf.Clamp(opening.stairWidth, minimumWidth, stairWidthFromX); float stairRun = internalSize.y - (useLandingWidth * 2); Vector3 escalationFlatDir = (b2i - b0i).normalized; Vector3 escalationRight = (b1i - b0i).normalized; Vector3 escalationVector = new Vector3(stairRun * escalationFlatDir.x, height * 0.5f, stairRun * escalationFlatDir.z); Vector3 escalationDirection = escalationVector.normalized; float escalationHypotenuse = escalationVector.magnitude; int numberOfSteps = Mathf.CeilToInt((height) / stepHeight); Vector3 escalationVectorB = new Vector3(stairRun * -escalationFlatDir.x, height * 0.5f, stairRun * -escalationFlatDir.z); Vector3 escalationDirectionB = escalationVectorB.normalized; Vector3 landingDrop = Vector3.down * wallThickness; Vector4 rightTangent = BuildRMesh.CalculateTangent(escalationRight); //lower landing if (!isBottomFloor) { Vector3 l0 = b0i; Vector3 l1 = b1i; Vector3 l2 = b0i + escalationFlatDir * useLandingWidth; Vector3 l3 = b1i + escalationFlatDir * useLandingWidth; Vector2 maxUVTop = new Vector2(internalSize.x, useLandingWidth); Vector2 maxUVSide = new Vector2(internalSize.x, stepHeight); //top mesh.AddPlane(l0, l1, l2, l3, Vector3.zero, maxUVTop, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //bottom mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, Vector3.zero, maxUVTop, Vector3.down, rightTangent, internalWallSubmesh, opening.surfaceB); //front mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, escalationFlatDir, maxUVSide, Vector3.up, rightTangent, internalWallSubmesh, opening.surfaceB); if (generateColldier) { collider.mesh.AddPlane(l0, l1, l2, l3, 0); collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0); collider.mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, 0); } } if (!isTopFloor) { //mid landing if (true) //half landed { Vector3 up = Vector3.up * height * 0.5f; Vector3 l0 = b2i - escalationFlatDir * useLandingWidth + up; Vector3 l1 = b3i - escalationFlatDir * useLandingWidth + up; Vector3 l2 = b2i + up; Vector3 l3 = b3i + up; Vector2 maxUVTop = new Vector2(internalSize.x, useLandingWidth); Vector2 maxUVSide = new Vector2(internalSize.x, useLandingWidth); //top mesh.AddPlane(l0, l1, l2, l3, Vector3.zero, maxUVTop, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //bottom mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, Vector3.zero, maxUVTop, Vector3.down, rightTangent, internalWallSubmesh, opening.surfaceB); //front mesh.AddPlane(l1, l0, l1 + landingDrop, l0 + landingDrop, Vector3.zero, maxUVSide, -escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB); if (generateColldier) { collider.mesh.AddPlane(l0, l1, l2, l3, 0); collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0); collider.mesh.AddPlane(l1, l0, l1 + landingDrop, l0 + landingDrop, 0); } } Vector3 flightABaseOutside = b0i + escalationFlatDir * useLandingWidth; Vector3 flightABaseInside = flightABaseOutside + escalationRight * useStairWidth; Vector3 flightATopOutside = flightABaseOutside + escalationDirection * escalationHypotenuse; Vector3 flightATopInside = flightABaseInside + escalationDirection * escalationHypotenuse; float dropThickness = wallThickness; //Mathf.Sin(Mathf.Atan2(height, stairRun)) * wallThickness; Vector3 flightABaseOutsideDrop = flightABaseOutside + Vector3.down * dropThickness; Vector3 flightABaseInsideDrop = flightABaseInside + Vector3.down * dropThickness; Vector3 flightATopOutsideDrop = flightATopOutside + Vector3.down * dropThickness; Vector3 flightATopInsideDrop = flightATopInside + Vector3.down * dropThickness; Vector3 flightBBaseOutside = b3i - escalationFlatDir * useLandingWidth + Vector3.up * height * 0.5f; Vector3 flightBBaseInside = flightBBaseOutside - escalationRight * useStairWidth; Vector3 flightBTopOutside = flightBBaseOutside + escalationDirectionB * escalationHypotenuse; Vector3 flightBTopInside = flightBBaseInside + escalationDirectionB * escalationHypotenuse; Vector3 flightBBaseOutsideDrop = flightBBaseOutside + Vector3.down * dropThickness; Vector3 flightBBaseInsideDrop = flightBBaseInside + Vector3.down * dropThickness; Vector3 flightBTopOutsideDrop = flightBTopOutside + Vector3.down * dropThickness; Vector3 flightBTopInsideDrop = flightBTopInside + Vector3.down * dropThickness; if (generateColldier) { collider.mesh.AddPlane(flightABaseOutside, flightABaseInside, flightATopOutside, flightATopInside, 0); collider.mesh.AddPlane(flightABaseInsideDrop, flightATopInsideDrop, flightABaseInside, flightATopInside, 0); collider.mesh.AddPlane(flightABaseInsideDrop, flightABaseOutsideDrop, flightATopInsideDrop, flightATopOutsideDrop, 0); collider.mesh.AddPlane(flightBBaseOutside, flightBBaseInside, flightBTopOutside, flightBTopInside, 0); collider.mesh.AddPlane(flightBBaseInsideDrop, flightBTopInsideDrop, flightBBaseInside, flightBTopInside, 0); collider.mesh.AddPlane(flightBBaseInsideDrop, flightBBaseOutsideDrop, flightBTopInsideDrop, flightBTopOutsideDrop, 0); } if (stepped) //todo, flat generation { float stepDepth = stairRun / (numberOfSteps); float skipStep = (stepDepth / (numberOfSteps - 1)); stepDepth += skipStep; float stepRiser = height / numberOfSteps / 2; Vector2 stepUvTopMin = new Vector2(0, 0); Vector2 stepUvTopMax = new Vector2(useStairWidth, stepDepth); Vector2 stepUvSideMin = new Vector2(0, 0); Vector2 stepUvSideMax = new Vector2(useStairWidth, stepRiser); //flight one float lerpIncrement = 1.0f / (numberOfSteps - 1); Vector3 flightATopOutsideStep = flightATopOutside + Vector3.down * stepHeight * 0.5f; Vector3 flightATopInsideStep = flightATopInside + Vector3.down * stepHeight * 0.5f; for (int s = 0; s < numberOfSteps - 1; s++) { float lerpValueAA = lerpIncrement * s; Vector3 s0 = Vector3.Lerp(flightABaseOutside, flightATopOutsideStep, lerpValueAA); Vector3 s1 = Vector3.Lerp(flightABaseInside, flightATopInsideStep, lerpValueAA); Vector3 s2 = s0 + Vector3.up * stepRiser; Vector3 s3 = s1 + Vector3.up * stepRiser; Vector3 s4 = s2 + escalationFlatDir.normalized * stepDepth; Vector3 s5 = s3 + escalationFlatDir.normalized * stepDepth; //front mesh.AddPlane(s0, s1, s2, s3, stepUvSideMin, stepUvSideMax, -escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB); //top mesh.AddPlane(s2, s3, s4, s5, stepUvTopMin, stepUvTopMax, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //sides float lerpValueB = lerpIncrement * s; Vector3 normal = escalationRight; Vector3[] normals = { normal, normal, normal, normal }; Vector4 tangent = BuildRMesh.CalculateTangent(escalationFlatDir); Vector4[] tangents = { tangent, tangent, tangent, tangent }; Vector3 s8 = Vector3.Lerp(flightABaseInsideDrop, flightATopInsideDrop, lerpValueB); Vector3 s9 = Vector3.Lerp(flightABaseInsideDrop, flightATopInsideDrop, lerpValueB + lerpIncrement); Vector2 uv5, uv3, uv8, uv9; if (opening.surfaceB != null) { uv5 = opening.surfaceB.CalculateUV(new Vector2(s5.z, s5.y)); uv3 = opening.surfaceB.CalculateUV(new Vector2(s3.z, s3.y)); uv8 = opening.surfaceB.CalculateUV(new Vector2(s8.z, s8.y)); uv9 = opening.surfaceB.CalculateUV(new Vector2(s9.z, s9.y)); } else { uv5 = new Vector2(); uv3 = new Vector2(); uv8 = new Vector2(); uv9 = new Vector2(); } mesh.AddData(new[] { s3, s5, s8, s9 }, new[] { uv3, uv5, uv8, uv9 }, new[] { 0, 1, 2, 2, 1, 3 }, normals, tangents, internalWallSubmesh); if (opening.surfaceB.tiled) { stepUvSideMin.x += 0.11f; stepUvSideMin.y += 0.37f; stepUvSideMax.x += 0.11f; stepUvSideMax.y += 0.37f; } if (opening.surfaceD.tiled) { stepUvTopMin.x += 0.23f; stepUvTopMin.y += 0.13f; stepUvTopMax.x += 0.23f; stepUvTopMax.y += 0.13f; } } mesh.AddPlane(flightABaseInsideDrop, flightABaseOutsideDrop, flightATopInsideDrop, flightATopOutsideDrop, internalWallSubmesh); //underside //flight two Vector3 flightBTopOutsideStep = flightBTopOutside + Vector3.down * stepHeight * 0.5f; Vector3 flightBTopInsideStep = flightBTopInside + Vector3.down * stepHeight * 0.5f; for (int s = 0; s < numberOfSteps - 1; s++) { float lerpValue = lerpIncrement * s; Vector3 s0 = Vector3.Lerp(flightBBaseOutside, flightBTopOutsideStep, lerpValue); Vector3 s1 = Vector3.Lerp(flightBBaseInside, flightBTopInsideStep, lerpValue); Vector3 s2 = s0 + Vector3.up * stepRiser; Vector3 s3 = s1 + Vector3.up * stepRiser; Vector3 s4 = s2 - escalationFlatDir.normalized * stepDepth; Vector3 s5 = s3 - escalationFlatDir.normalized * stepDepth; //front mesh.AddPlane(s0, s1, s2, s3, stepUvSideMin, stepUvSideMax, escalationFlatDir, rightTangent, internalWallSubmesh, opening.surfaceB); //top mesh.AddPlane(s2, s3, s4, s5, stepUvTopMin, stepUvTopMax, Vector3.up, rightTangent, internalFloorSubmesh, opening.surfaceD); //sides float lerpValueB = lerpIncrement * s; Vector3 normal = escalationRight; Vector3[] normals = { normal, normal, normal, normal }; Vector4 tangent = BuildRMesh.CalculateTangent(escalationFlatDir); Vector4[] tangents = { tangent, tangent, tangent, tangent }; Vector3 s8 = Vector3.Lerp(flightBBaseInsideDrop, flightBTopInsideDrop, lerpValueB); Vector3 s9 = Vector3.Lerp(flightBBaseInsideDrop, flightBTopInsideDrop, lerpValueB + lerpIncrement); Vector2 uv5, uv3, uv8, uv9; if (opening.surfaceB != null) { uv5 = opening.surfaceB.CalculateUV(new Vector2(s5.z, s5.y)); uv3 = opening.surfaceB.CalculateUV(new Vector2(s3.z, s3.y)); uv8 = opening.surfaceB.CalculateUV(new Vector2(s8.z, s8.y)); uv9 = opening.surfaceB.CalculateUV(new Vector2(s9.z, s9.y)); } else { uv5 = new Vector2(); uv3 = new Vector2(); uv8 = new Vector2(); uv9 = new Vector2(); } mesh.AddData(new[] { s3, s5, s8, s9 }, new[] { uv3, uv5, uv8, uv9 }, new[] { 0, 1, 2, 2, 1, 3 }, normals, tangents, internalWallSubmesh); } mesh.AddPlane(flightBBaseInsideDrop, flightBBaseOutsideDrop, flightBTopInsideDrop, flightBTopOutsideDrop, internalWallSubmesh); //underside } } }
public static void GenerateRoofAccess(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int floor, int wallSubmesh = -1, BuildRCollider collider = null) { // bool stepped = true;//todo float minimumWidth = 0.9f; //UK standard // float maximumWidth = 2.0f; // float stepHeight = 0.22f; float wallThickness = VerticalOpening.WALL_THICKNESS; float stairWidth = 0.70f; //todo / calculate float doorWidth = 1.3f; float doorHeight = 2.04f; bool generateColldier = collider != null; float minimumRunLength = 0.25f; float maximumRiserHeight = 0.2f; SubmeshLibrary submeshLibrary = mesh.submeshLibrary; int externalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceA); int internalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB); int doorFrameSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceC); int internalFloorSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceD); //base positions Quaternion rotation = Quaternion.Euler(0, opening.rotation, 0); Vector2Int openingSize = opening.size; Vector3 b0 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, height, -opening.size.vy * 0.5f); Vector3 b1 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, height, -opening.size.vy * 0.5f); Vector3 b2 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, height, opening.size.vy * 0.5f); Vector3 b3 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, height, opening.size.vy * 0.5f); //inner points Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness; Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness; Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness; Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness; Vector2 internalSize = new Vector2(openingSize.vx - wallThickness * 2, openingSize.vy - wallThickness * 2); float stairWidthFromX = internalSize.x * 0.5f; float stairWidthFromY = internalSize.y - Mathf.Ceil(height / maximumRiserHeight) * minimumRunLength; float useLandingWidth = (stairWidthFromX + stairWidthFromY) * 0.5f; useLandingWidth = Mathf.Clamp(useLandingWidth, minimumWidth, opening.stairWidth); Vector3 escalationFlatDir = (b2i - b0i).normalized; Vector3 landingDrop = Vector3.down * wallThickness; //landing Vector3 l0 = b0i; Vector3 l1 = b1i; Vector3 l2 = b0i + escalationFlatDir * useLandingWidth; Vector3 l3 = b1i + escalationFlatDir * useLandingWidth; //top mesh.AddPlane(l0, l1, l2, l3, internalFloorSubmesh); //bottom mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, internalWallSubmesh); //front mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, internalWallSubmesh); if (generateColldier) { collider.mesh.AddPlane(l0, l1, l2, l3, 0); collider.mesh.AddPlane(l1 + landingDrop, l0 + landingDrop, l3 + landingDrop, l2 + landingDrop, 0); collider.mesh.AddPlane(l2, l3, l2 + landingDrop, l3 + landingDrop, 0); } //internal walls Vector3 wallUp = Vector3.up * height; wallUp.y += -wallThickness * 0.5f; Vector3 wallUpI = Vector3.up * (height - wallThickness); mesh.AddPlane(b0i, b2i, b0i + wallUpI, b2i + wallUpI, internalWallSubmesh); mesh.AddPlane(b2i, b3i, b2i + wallUpI, b3i + wallUpI, internalWallSubmesh); mesh.AddPlane(b3i, b1i, b3i + wallUpI, b1i + wallUpI, internalWallSubmesh); mesh.AddPlane(b1i + wallUpI, b0i + wallUpI, b3i + wallUpI, b2i + wallUpI, internalWallSubmesh); //external walls mesh.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp, externalWallSubmesh); mesh.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp, externalWallSubmesh); mesh.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp, externalWallSubmesh); mesh.AddPlane(b0 + wallUp, b1 + wallUp, b2 + wallUp, b3 + wallUp, internalWallSubmesh); if (generateColldier) { collider.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp); collider.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp); collider.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp); collider.mesh.AddPlane(b1i + wallUpI, b0i + wallUpI, b3i + wallUpI, b2i + wallUpI, 0); collider.mesh.AddPlane(b0 + wallUp, b1 + wallUp, b2 + wallUp, b3 + wallUp, 0); if (!collider.usingPrimitives) { collider.mesh.AddPlane(b0i, b2i, b0i + wallUpI, b2i + wallUpI, 0); collider.mesh.AddPlane(b2i, b3i, b2i + wallUpI, b3i + wallUpI, 0); collider.mesh.AddPlane(b3i, b1i, b3i + wallUpI, b1i + wallUpI, 0); } } //door wall //internal float internalWallLength = openingSize.vx - (wallThickness * 2f); float lerpA = Mathf.Max(stairWidth - doorWidth, 0.05f) / internalWallLength; float lerpB = (Mathf.Max(stairWidth - doorWidth, 0.05f) + doorWidth) / internalWallLength; Vector3 bd0i = Vector3.Lerp(b0i, b1i, lerpA); Vector3 bd1i = Vector3.Lerp(b0i, b1i, lerpB); Vector3 doorUp = Vector3.up * doorHeight; //Right side mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, internalWallSubmesh); //left side mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, internalWallSubmesh); //top mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUpI, b0i + wallUpI, internalWallSubmesh); //external Vector3 doorOut = -escalationFlatDir * wallThickness; //left mesh.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp, externalWallSubmesh); //right mesh.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp, externalWallSubmesh); //top mesh.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp, externalWallSubmesh); //frame //floor mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, externalWallSubmesh); //left mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, doorFrameSubmesh); //right mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); //top mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); if (generateColldier) { collider.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp); collider.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp); collider.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp); if (!collider.usingPrimitives) { collider.mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, 0); collider.mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, 0); collider.mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUpI, b0i + wallUpI, 0); collider.mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, 0); collider.mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, 0); collider.mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, 0); collider.mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, 0); } } }
public static void GenerateWall(BuildRMesh mesh, VerticalOpening opening, Vector3 basePosition, float height, int wallSubmesh = -1, BuildRCollider collider = null) { float stairWidth = 0.70f; //todo / calculate float wallThickness = VerticalOpening.WALL_THICKNESS; float doorWidth = 1.3f; float doorHeight = 2.04f; bool generateColldier = collider != null; // bool generateMeshCollider = generateColldier && !collider.usingPrimitives; SubmeshLibrary submeshLibrary = mesh.submeshLibrary; int externalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceA); int internalWallSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceB); int doorFrameSubmesh = submeshLibrary.SubmeshAdd(opening.surfaceC); //base positions Quaternion rotation = Quaternion.Euler(0, opening.rotation, 0); Vector2Int openingSize = opening.size; Vector3 b0 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b1 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, -opening.size.vy * 0.5f); Vector3 b2 = basePosition + rotation * new Vector3(-opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); Vector3 b3 = basePosition + rotation * new Vector3(opening.size.vx * 0.5f, 0, opening.size.vy * 0.5f); //inner points Vector3 b0i = b0 + rotation * new Vector3(1, 0, 1) * wallThickness; Vector3 b1i = b1 + rotation * new Vector3(-1, 0, 1) * wallThickness; Vector3 b2i = b2 + rotation * new Vector3(1, 0, -1) * wallThickness; Vector3 b3i = b3 + rotation * new Vector3(-1, 0, -1) * wallThickness; Vector3 escalationFlatDir = (b2i - b0i).normalized; Vector3 wallUp = Vector3.up * height; //external walls Vector2 uv20_min = new Vector2(0, 0); Vector2 uv20_max = new Vector2(opening.size.vy, height); Vector3 normal02 = rotation * Vector3.left; Vector4 tangent02 = BuildRMesh.CalculateTangent((b0 - b2).normalized); mesh.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp, uv20_min, uv20_max, normal02, tangent02, externalWallSubmesh, opening.surfaceA); Vector2 uv32_min = new Vector2(0, 0); Vector2 uv32_max = new Vector2(opening.size.vx, height); Vector3 normal32 = rotation * Vector3.forward; Vector4 tangent32 = BuildRMesh.CalculateTangent((b2 - b3).normalized); mesh.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp, uv32_min, uv32_max, normal32, tangent32, externalWallSubmesh, opening.surfaceA); Vector2 uv13_min = new Vector2(0, 0); Vector2 uv13_max = new Vector2(opening.size.vy, height); Vector3 normal13 = rotation * Vector3.right; Vector4 tangent13 = BuildRMesh.CalculateTangent((b3 - b1).normalized); mesh.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp, uv13_min, uv13_max, normal13, tangent13, externalWallSubmesh, opening.surfaceA); //internal walls Vector2 uv20i_min = new Vector2(wallThickness, 0); Vector2 uv20i_max = new Vector2(opening.size.vy - wallThickness, height); Vector3 normal02i = rotation * Vector3.right; Vector4 tangent02i = BuildRMesh.CalculateTangent((b2 - b0).normalized); mesh.AddPlane(b0i, b2i, b0i + wallUp, b2i + wallUp, uv20i_min, uv20i_max, normal02i, tangent02i, internalWallSubmesh, opening.surfaceB); Vector2 uv32i_min = new Vector2(0, 0); Vector2 uv32i_max = new Vector2(opening.size.vx - wallThickness, height); Vector3 normal32i = rotation * Vector3.back; Vector4 tangent32i = BuildRMesh.CalculateTangent((b3 - b2).normalized); mesh.AddPlane(b2i, b3i, b2i + wallUp, b3i + wallUp, uv32i_min, uv32i_max, normal32i, tangent32i, internalWallSubmesh, opening.surfaceB); Vector2 uv13i_min = new Vector2(0, 0); Vector2 uv13i_max = new Vector2(opening.size.vy - wallThickness, height); Vector3 normal13i = rotation * Vector3.left; Vector4 tangent13i = BuildRMesh.CalculateTangent((b1 - b3).normalized); mesh.AddPlane(b3i, b1i, b3i + wallUp, b1i + wallUp, uv13i_min, uv13i_max, normal13i, tangent13i, internalWallSubmesh, opening.surfaceB); if (generateColldier) { collider.AddPlane(b2, b0, b2 + wallUp, b0 + wallUp); collider.AddPlane(b3, b2, b3 + wallUp, b2 + wallUp); collider.AddPlane(b1, b3, b1 + wallUp, b3 + wallUp); if (!collider.usingPrimitives) { collider.mesh.AddPlane(b0i, b2i, b0i + wallUp, b2i + wallUp, 0); collider.mesh.AddPlane(b2i, b3i, b2i + wallUp, b3i + wallUp, 0); collider.mesh.AddPlane(b3i, b1i, b3i + wallUp, b1i + wallUp, 0); } } //door wall float internalWallLength = openingSize.vx - (wallThickness * 2f); float lerpA = Mathf.Max(stairWidth - doorWidth, 0.05f) / internalWallLength; float lerpB = (Mathf.Max(stairWidth - doorWidth, 0.05f) + doorWidth) / internalWallLength; Vector2 uvd_b0 = new Vector2(0, 0); Vector2 uvd_b1 = new Vector2(opening.size.vx * lerpA, 0); Vector2 uvd_b2 = new Vector2(opening.size.vx * lerpB, 0); Vector2 uvd_b3 = new Vector2(opening.size.vx, 0); Vector2 uvd_m0 = new Vector2(uvd_b0.x, doorHeight); Vector2 uvd_m1 = new Vector2(uvd_b1.x, doorHeight); Vector2 uvd_m3 = new Vector2(uvd_b3.x, doorHeight); Vector2 uvd_t0 = new Vector2(0, height); Vector2 uvd_t3 = new Vector2(opening.size.vx, height); //internal Vector3 bd0i = Vector3.Lerp(b0i, b1i, lerpA); Vector3 bd1i = Vector3.Lerp(b0i, b1i, lerpB); Vector3 normal01i = rotation * Vector3.forward; Vector4 tangent01i = BuildRMesh.CalculateTangent((b0 - b1).normalized); Vector3 doorUp = Vector3.up * doorHeight; //Right side mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, uvd_b0, uvd_m1, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB); //left side mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, uvd_b2, uvd_m3, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB); //top mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUp, b0i + wallUp, uvd_m3, uvd_t0, normal01i, tangent01i, internalWallSubmesh, opening.surfaceB); //external Vector3 doorOut = -escalationFlatDir * wallThickness; Vector3 normal01 = rotation * Vector3.back; Vector4 tangent01 = BuildRMesh.CalculateTangent((b1 - b0).normalized); //left mesh.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp, uvd_b0, uvd_m1, normal01, tangent01, externalWallSubmesh, opening.surfaceA); //right mesh.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp, uvd_b2, uvd_m3, normal01, tangent01, externalWallSubmesh, opening.surfaceA); //top mesh.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp, uvd_m0, uvd_t3, normal01, tangent01, externalWallSubmesh, opening.surfaceA); //frame //floor mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, externalWallSubmesh); //left mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, doorFrameSubmesh); //right mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); //top mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, doorFrameSubmesh); if (generateColldier) { collider.AddPlane(b0, bd0i + doorOut, b0 + doorUp, bd0i + doorOut + doorUp); collider.AddPlane(bd1i + doorOut, b1, bd1i + doorOut + doorUp, b1 + doorUp); collider.AddPlane(b0 + doorUp, b1 + doorUp, b0 + wallUp, b1 + wallUp); if (!collider.usingPrimitives) { collider.mesh.AddPlane(bd0i, b0i, bd0i + doorUp, b0i + doorUp, 0); collider.mesh.AddPlane(b1i, bd1i, b1i + doorUp, bd1i + doorUp, 0); collider.mesh.AddPlane(b1i + doorUp, b0i + doorUp, b1i + wallUp, b0i + wallUp, 0); collider.mesh.AddPlane(bd1i, bd0i, bd1i + doorOut, bd0i + doorOut, 0); collider.mesh.AddPlane(bd0i + doorOut, bd0i, bd0i + doorOut + doorUp, bd0i + doorUp, 0); collider.mesh.AddPlane(bd1i, bd1i + doorOut, bd1i + doorUp, bd1i + doorOut + doorUp, 0); collider.mesh.AddPlane(bd0i + doorUp, bd1i + doorUp, bd0i + doorOut + doorUp, bd1i + doorOut + doorUp, 0); } } }
public BuildRCollider(string newName) { _name = newName; _mesh = new BuildRMesh(newName); _boxList = new List <BBox>(); }
public static void Portal(ref BuildRMesh dynamicMesh, Portal portal, Vector2 size, Vector3 offset, bool interior = true, SubmeshLibrary submeshLibrary = null) { if (submeshLibrary == null) { submeshLibrary = new SubmeshLibrary(); submeshLibrary.Add(portal); } Division root = portal.root; List <Panel> processNodes = new List <Panel>(); Dictionary <Panel, Panel[]> dataDic = new Dictionary <Panel, Panel[]>(); List <Panel> data = new List <Panel>(); Panel rootPanel = new Panel(root, new Rect(0, 0, size.x, size.y), 0); processNodes.Add(rootPanel); float totalDepth = 0; while (processNodes.Count > 0) { Panel current = processNodes[0]; Division division = current.division; List <Division> children = division.GetChildren; int childCount = children.Count; data.Add(current);//dump processed node into data. dataDic.Add(current, new Panel[childCount]); if (current.recess > totalDepth) { totalDepth = current.recess; } float childRatio = 0; for (int c = 0; c < childCount; c++) { childRatio += children[c].size; } for (int c = 0; c < childCount; c++) { Division child = children[c]; Rect newPanelrect = current.rect; float ratio = children[c].size / childRatio; if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal) { newPanelrect.width = Mathf.Max(newPanelrect.width - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio; newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2, 0); if (c > 0) { Panel lastPanel = processNodes[processNodes.Count - 1]; newPanelrect.x = lastPanel.rect.xMax + division.frame; } else { newPanelrect.x = current.rect.xMin + division.frame; } newPanelrect.y = current.rect.yMin + division.frame; } else { newPanelrect.width = Mathf.Max(newPanelrect.width - division.frame * 2, 0); newPanelrect.height = Mathf.Max(newPanelrect.height - division.frame * 2 - division.frame * (childCount - 1), 0) * ratio; if (c > 0) { Panel lastPanel = processNodes[processNodes.Count - 1]; newPanelrect.y = lastPanel.rect.y + lastPanel.rect.height + division.frame; } else { newPanelrect.y = current.rect.yMin + division.frame; } newPanelrect.x = current.rect.xMin + division.frame; } Panel childPanel = new Panel(child, newPanelrect, current.recess + division.recess); dataDic[current][c] = childPanel; processNodes.Add(childPanel); } processNodes.RemoveAt(0); } int dataCount = data.Count; Vector3 norm = Vector3.back; Vector4 tangent = BuildRMesh.CalculateTangent(Vector3.right); Vector4 tangentForward = BuildRMesh.CalculateTangent(Vector3.forward); Vector4 tangentBack = BuildRMesh.CalculateTangent(Vector3.back); Vector4 tangentInvert = BuildRMesh.CalculateTangent(Vector3.left); Vector3 useOffset = size * 0.5f; useOffset += offset; useOffset.y = -useOffset.y;//inverse - UX resaons for (int i = 0; i < dataCount; i++) { Panel panel = data[i]; Division division = panel.division; Rect panelRect = panel.rect; if (panelRect.width == 0 || panelRect.height == 0) { continue; } Vector3 v0 = new Vector3(panelRect.xMin, -panelRect.yMin, panel.recess) - useOffset; Vector3 v1 = new Vector3(panelRect.xMax, -panelRect.yMin, panel.recess) - useOffset; Vector3 v2 = new Vector3(panelRect.xMin, -panelRect.yMax, panel.recess) - useOffset; Vector3 v3 = new Vector3(panelRect.xMax, -panelRect.yMax, panel.recess) - useOffset; Surface usedSurface = GetSurface(portal, division); int useSubmesh = submeshLibrary.SubmeshAdd(usedSurface); // int useSubmesh = usedSurface != null ? Array.IndexOf(usedSurfaces, usedSurface) : 0; Vector2 uv0 = CalculateUV(usedSurface, v0); Vector2 uv1 = CalculateUV(usedSurface, v1); Vector2 uv2 = CalculateUV(usedSurface, v2); Vector2 uv3 = CalculateUV(usedSurface, v3); if (!division.hasChildren)//simple panel { Vector3[] verts = { v0, v1, v2, v3 }; Vector2[] uvs = { uv0, uv1, uv2, uv3 }; int[] tris = { 0, 1, 2, 1, 3, 2 }; Vector3[] norms = { norm, norm, norm, norm }; Vector4[] tangents = { tangent, tangent, tangent, tangent }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); verts = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset }; uvs = new[] { uv1, uv0, uv3, uv2 }; tris = new[] { 0, 2, 1, 1, 2, 3 }; norms = new[] { -norm, -norm, -norm, -norm }; tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); } } else//build a frame { Vector3 v0f = v0 + new Vector3(division.frame, -division.frame, 0); Vector3 v1f = v1 + new Vector3(-division.frame, -division.frame, 0); Vector3 v2f = v2 + new Vector3(division.frame, division.frame, 0); Vector3 v3f = v3 + new Vector3(-division.frame, division.frame, 0); Vector3 recessV = Vector3.forward * (division.recess); Vector3 v0r = v0f + recessV; Vector3 v1r = v1f + recessV; Vector3 v2r = v2f + recessV; Vector3 v3r = v3f + recessV; Vector2 uv0f = CalculateUV(usedSurface, v0f); Vector2 uv1f = CalculateUV(usedSurface, v1f); Vector2 uv2f = CalculateUV(usedSurface, v2f); Vector2 uv3f = CalculateUV(usedSurface, v3f); // Vector2 uv0r = CalculateUV(usedSurface, v0r); // Vector2 uv1r = CalculateUV(usedSurface, v1r); // Vector2 uv2r = CalculateUV(usedSurface, v2r); // Vector2 uv3r = CalculateUV(usedSurface, v3r); Vector3[] verts = { v0, v1, v2, v3, v0f, v1f, v2f, v3f }; Vector2[] uvs = { uv0, uv1, uv2, uv3, uv0f, uv1f, uv2f, uv3f }; Vector3[] norms = { norm, norm, norm, norm, norm, norm, norm, norm }; Vector4[] tangents = { tangent, tangent, tangent, tangent, tangent, tangent, tangent, tangent }; int[] tris = { 0, 4, 2, 4, 6, 2, //left 0, 1, 4, 1, 5, 4, //top 5, 1, 3, 5, 3, 7, //right 2, 6, 3, 3, 6, 7, //bottom }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); Vector2 uvUp = CalculateUV(usedSurface, new Vector2(0, division.recess)); Vector2 uvRight = CalculateUV(usedSurface, new Vector2(division.recess, 0)); dynamicMesh.AddPlaneComplex(v1f, v0f, v1r, v0r, uv1f, uv0f, uv1f + uvUp, uv0f + uvUp, Vector3.down, tangent, useSubmesh, usedSurface); //top dynamicMesh.AddPlaneComplex(v2f, v3f, v2r, v3r, uv2f, uv3f, uv2f + uvUp, uv3f + uvUp, Vector3.up, tangent, useSubmesh, usedSurface); //bottom dynamicMesh.AddPlaneComplex(v0f, v2f, v0r, v2r, uv0f, uv2f, uv0f + uvRight, uv2f + uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //left dynamicMesh.AddPlaneComplex(v3f, v1f, v3r, v1r, uv3f, uv1f, uv3f + uvRight, uv1f + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface); //right if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2); verts = new[] { v0 + interiorOffset, v1 + interiorOffset, v2 + interiorOffset, v3 + interiorOffset, v0f + interiorOffset, v1f + interiorOffset, v2f + interiorOffset, v3f + interiorOffset }; uvs = new [] { uv1, uv0, uv3, uv2, uv1f, uv0f, uv3f, uv2f }; Array.Reverse(tris); norms = new[] { -norm, -norm, -norm, -norm, -norm, -norm, -norm, -norm }; tangents = new[] { tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert, tangentInvert }; dynamicMesh.AddData(verts, uvs, tris, norms, tangents, useSubmesh); dynamicMesh.AddPlaneComplex(v0f + interiorOffset, v1f + interiorOffset, v0r + interiorOffsetr, v1r + interiorOffsetr, uv0f, uv1f, uv0f + uvUp, uv1f + uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface); //top dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v2f + interiorOffset, v3r + interiorOffsetr, v2r + interiorOffsetr, uv3f, uv2f, uv3f + uvUp, uv2f + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface); //bottom dynamicMesh.AddPlaneComplex(v2f + interiorOffset, v0f + interiorOffset, v2r + interiorOffsetr, v0r + interiorOffsetr, uv2f, uv0f, uv2f + uvRight, uv0f + uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface); //left dynamicMesh.AddPlaneComplex(v3f + interiorOffset, v3f + interiorOffset, v3r + interiorOffsetr, v3r + interiorOffsetr, uv1f, uv3f, uv1f + uvRight, uv3f + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface); //right } List <Division> children = division.GetChildren; int childCount = children.Count; if (childCount > 1 && division.frame > 0) { for (int c = 0; c < childCount - 1; c++) { Panel childPanel = dataDic[panel][c]; if (division.divisionType == BuildR2.Portal.DivisionTypes.Horizontal) { Vector3 v0d = v0 + new Vector3(childPanel.rect.xMax - panelRect.xMin, -division.frame, 0); Vector3 v1d = v0d + new Vector3(division.frame, 0, 0); Vector3 v2d = v0d + new Vector3(0, -panelRect.height + division.frame * 2, 0); Vector3 v3d = v1d + new Vector3(0, -panelRect.height + division.frame * 2, 0); Vector2 uv0d = CalculateUV(usedSurface, v0d); Vector2 uv1d = CalculateUV(usedSurface, v1d); Vector2 uv2d = CalculateUV(usedSurface, v2d); Vector2 uv3d = CalculateUV(usedSurface, v3d); dynamicMesh.AddPlaneComplex(v1d, v0d, v3d, v2d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v2d, v0d, v2d + recessV, v0d + recessV, uv2d, uv0d, uv2d + uvRight, uv0d + uvRight, Vector3.left, tangentBack, useSubmesh, usedSurface); //divider left dynamicMesh.AddPlaneComplex(v1d, v3d, v1d + recessV, v3d + recessV, uv1d, uv3d, uv1d - uvRight, uv3d - uvRight, Vector3.right, tangentBack, useSubmesh, usedSurface); //divider right if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2); dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v1d + interiorOffset, v2d + interiorOffset, v3d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v0d + interiorOffset, v2d + interiorOffset, v0d + recessV + interiorOffsetr, v2d + recessV + interiorOffsetr, uv0d, uv2d, uv0d + uvRight, uv2d + uvRight, Vector3.left, tangentForward, useSubmesh, usedSurface); //divider left dynamicMesh.AddPlaneComplex(v3d + interiorOffset, v1d + interiorOffset, v3d + recessV + interiorOffsetr, v1d + recessV + interiorOffsetr, uv3d, uv1d, uv3d - uvRight, uv1d - uvRight, Vector3.right, tangentForward, useSubmesh, usedSurface); //divider right } } else { Vector3 v0d = v0 + new Vector3(division.frame, -childPanel.rect.yMax + panelRect.yMin, 0); Vector3 v1d = v0d + new Vector3(0, -division.frame, 0); Vector3 v2d = v0d + new Vector3(panelRect.width - division.frame * 2, 0, 0); Vector3 v3d = v1d + new Vector3(panelRect.width - division.frame * 2, 0, 0); Vector2 uv0d = CalculateUV(usedSurface, v0d); Vector2 uv1d = CalculateUV(usedSurface, v1d); Vector2 uv2d = CalculateUV(usedSurface, v2d); Vector2 uv3d = CalculateUV(usedSurface, v3d); dynamicMesh.AddPlaneComplex(v0d, v1d, v2d, v3d, uv0d, uv1d, uv2d, uv3d, norm, tangent, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v0d, v2d, v0d + recessV, v2d + recessV, uv0d, uv2d, uv0d + uvUp, uv2d + uvUp, Vector3.up, tangent, useSubmesh, usedSurface); //divider top dynamicMesh.AddPlaneComplex(v3d, v1d, v3d + recessV, v1d + recessV, uv3d, uv1d, uv3d - uvUp, uv1d - uvUp, Vector3.down, tangent, useSubmesh, usedSurface); //divider bottom if (interior) { Vector3 interiorOffset = new Vector3(0, 0, (totalDepth - panel.recess) * 2); Vector3 interiorOffsetr = new Vector3(0, 0, (totalDepth - panel.recess - division.recess) * 2); dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v0d + interiorOffset, v3d + interiorOffset, v2d + interiorOffset, uv1d, uv0d, uv3d, uv2d, -norm, tangentInvert, useSubmesh, usedSurface); //divider face dynamicMesh.AddPlaneComplex(v2d + interiorOffset, v0d + interiorOffset, v2d + recessV + interiorOffsetr, v0d + recessV + interiorOffsetr, uv2d, uv0d, uv2d + uvUp, uv0d + uvUp, Vector3.up, tangentInvert, useSubmesh, usedSurface); //divider top dynamicMesh.AddPlaneComplex(v1d + interiorOffset, v3d + interiorOffset, v1d + recessV + interiorOffsetr, v3d + recessV + interiorOffsetr, uv1d, uv3d, uv1d - uvUp, uv3d - uvUp, Vector3.down, tangentInvert, useSubmesh, usedSurface); //divider bottom } } } } } } }