private static Gable MenuCreateNewGableB() { Gable output = CreateGable(); UnityEditor.Selection.activeObject = output; return(output); }
public static Gable CreateGable() { Gable output = CreateInstance <Gable>(); #if UNITY_EDITOR UnityEditor.AssetDatabase.CreateAsset(output, AssetCreator.GeneratePath("newGable.asset", "Gables")); UnityEditor.AssetDatabase.SaveAssets(); UnityEditor.AssetDatabase.Refresh(); #endif return(output); }
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 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); }
private void OnEnable() { _gable = (Gable)target; _plane = Primitives.Plane(10); // _blueprintMaterial = AssetDatabase.LoadAssetAtPath<Material>("Assets/BuildR2/Materials/Blueprint.mat");//TODO make independent of BuildR location }
static void ItemOnGui(string guid, Rect rect) { if (settings == null) { settings = BuildRSettings.GetSettings(); } if (!settings.iconPreviews) { return; } bool defaultFound = settings.defaultIcon != null; Rect squareRect = new Rect(rect.x, rect.y, rect.height, rect.height); float defaultHeight = Mathf.Min(56, rect.height); float defaultWidth = Mathf.Min(44, rect.width, defaultHeight * 0.7857f); float defaultX = rect.x; float defaultY = rect.y; if (rect.height > 56) { defaultX = rect.x + (rect.width - 44) * 0.5f; defaultY = rect.y + (rect.height - 70) * 0.5f; } Rect defaultRect = new Rect(defaultX, defaultY, defaultWidth, defaultHeight); // IconUtil.GUIDIconData iconData = settings.GetCustomIconData(guid); // if(iconData == null) // { // iconData = IconUtil.GenerateGUIDIconData(guid); // settings.AddCustomIconData(guid, iconData); // } string assetPath = AssetDatabase.GUIDToAssetPath(guid); WallSection wallSection = AssetDatabase.LoadAssetAtPath(assetPath, typeof(WallSection)) as WallSection; if (wallSection != null) { Texture2D wallSectionPreview = wallSection.previewTexture; if (wallSectionPreview != null) { GUI.DrawTexture(squareRect, wallSectionPreview); } else if (defaultFound) { GUI.DrawTexture(defaultRect, settings.defaultIcon); } } Facade facade = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Facade)) as Facade; if (facade != null) { Texture2D facadePreview = facade.previewTexture; if (facadePreview != null) { GUI.DrawTexture(squareRect, facadePreview); } else if (defaultFound) { GUI.DrawTexture(defaultRect, settings.defaultIcon); } } Surface surface = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Surface)) as Surface; if (surface != null && surface.previewTexture != null) { if (surface.previewTexture != null) { GUI.DrawTexture(squareRect, surface.previewTexture); } else if (defaultFound) { GUI.DrawTexture(defaultRect, settings.defaultIcon); } } Gable gable = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Gable)) as Gable; if (defaultFound && gable != null) { GUI.DrawTexture(defaultRect, settings.defaultIcon); } RoomStyle roomStyle = AssetDatabase.LoadAssetAtPath(assetPath, typeof(RoomStyle)) as RoomStyle; if (defaultFound && roomStyle != null) { GUI.DrawTexture(defaultRect, settings.defaultIcon); } Portal portal = AssetDatabase.LoadAssetAtPath(assetPath, typeof(Portal)) as Portal; if (defaultFound && portal != null) { GUI.DrawTexture(defaultRect, settings.defaultIcon); } BuildRSettings settingsIcon = AssetDatabase.LoadAssetAtPath(assetPath, typeof(BuildRSettings)) as BuildRSettings; if (defaultFound && settingsIcon != null) { GUI.DrawTexture(defaultRect, settings.defaultIcon); } }
private static void ToMesh(ref BuildRMesh mesh, ref Shape shape, float roofBaseHeight, float meshHeight, int[] facadeIndices, IVolume volume, int submesh, Surface surface, bool generateDormers = false) { //TODO fix this error properly if (shape == null) { Debug.Log("ToMesh: Error to fix"); return; } List <Edge> edges = new List <Edge>(shape.edges); List <Edge> baseEdges = new List <Edge>(shape.baseEdges); float shapeHeight = shape.HeighestPoint(); float heightScale = meshHeight / shapeHeight; bool isFloor = meshHeight < 0.00001f; Dictionary <Node, int> shapeConnectionCount = new Dictionary <Node, int>(); Dictionary <Node, List <Node> > shapeConnections = new Dictionary <Node, List <Node> >(); int edgeCount = edges.Count; for (int e = 0; e < edgeCount; e++) { Edge edge = edges[e]; if (edge.length < Mathf.Epsilon) { continue; } if (!shapeConnectionCount.ContainsKey(edge.nodeA)) { shapeConnectionCount.Add(edge.nodeA, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeA, new List <Node> { edge.nodeB }); } else { shapeConnectionCount[edge.nodeA]++; if (!shapeConnections[edge.nodeA].Contains(edge.nodeB)) { shapeConnections[edge.nodeA].Add(edge.nodeB); } } if (!shapeConnectionCount.ContainsKey(edge.nodeB)) { shapeConnectionCount.Add(edge.nodeB, 0);//start at zero - we need two edges to make a shape... shapeConnections.Add(edge.nodeB, new List <Node> { edge.nodeA }); } else { shapeConnectionCount[edge.nodeB]++; if (!shapeConnections[edge.nodeB].Contains(edge.nodeA)) { shapeConnections[edge.nodeB].Add(edge.nodeA); } } } int baseEdgeCount = baseEdges.Count; List <Vector3[]> roofFaces = new List <Vector3[]>(); for (int b = 0; b < baseEdgeCount; b++) { int facadeIndex = facadeIndices[b]; bool isGabled = volume[facadeIndex].isGabled; if (!isGabled) { int facadeIndexLeft = (facadeIndex - 1 + volume.numberOfFacades) % volume.numberOfFacades; int facadeIndexRight = (facadeIndex + 1) % volume.numberOfFacades; bool isGabledLeft = volume[facadeIndexLeft].isGabled; bool isGabledRight = volume[facadeIndexRight].isGabled; Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Node currentNode = nodeA; Node lastNode = nodeB; int itMax = 50; List <Node> edgeShape = new List <Node>() { nodeA }; while (currentNode != nodeB) { List <Node> nodeConnections = shapeConnections[currentNode]; int nodeConnectionCount = nodeConnections.Count; float minAngle = Mathf.Infinity; Node nextNode = null; Vector2 currentDirection = (currentNode.position - lastNode.position).normalized; for (int n = 0; n < nodeConnectionCount; n++) { Node connectingNode = nodeConnections[n]; if (connectingNode == lastNode) { continue; //end this circus! } Vector2 nextDirection = (connectingNode.position - currentNode.position).normalized; float nodeAngle = SignAngleDirection(currentDirection, nextDirection); if (nodeAngle < minAngle) { minAngle = nodeAngle; nextNode = connectingNode; } } if (nextNode != null) { edgeShape.Add(nextNode); lastNode = currentNode; currentNode = nextNode; } itMax--; if (itMax < 0) { break; } } int edgeShapeCount = edgeShape.Count; if (edgeShapeCount == 4 && generateDormers) { Vector3[] edgeShapeV3 = new Vector3[4]; edgeShapeV3[0] = new Vector3(edgeShape[0].position.x, roofBaseHeight, edgeShape[0].position.y); edgeShapeV3[1] = new Vector3(edgeShape[3].position.x, roofBaseHeight, edgeShape[3].position.y); edgeShapeV3[2] = new Vector3(edgeShape[1].position.x, roofBaseHeight + meshHeight, edgeShape[1].position.y); edgeShapeV3[3] = new Vector3(edgeShape[2].position.x, roofBaseHeight + meshHeight, edgeShape[2].position.y); roofFaces.Add(edgeShapeV3); } if ((isGabledLeft || isGabledRight) && edgeShapeCount == 4)//modify shape if gables are detected { Vector3 p0 = edgeShape[0].position; Vector3 p1 = edgeShape[3].position; Vector3 p2 = edgeShape[1].position; Vector3 vector = p1 - p0; Vector3 dir = vector.normalized; Vector3 cross = Vector3.Cross(Vector3.back, dir); if (isGabledLeft) { float gableThickness = volume[facadeIndexLeft].gableThickness; bool simpleGable = volume[facadeIndexLeft].simpleGable; Gable gableStyle = volume[facadeIndexLeft].gableStyle; if (!simpleGable && gableStyle == null || !isFloor) { gableThickness = 0; } Vector3 newPointA = Vector3.Project(p2 - p1, cross) + dir * gableThickness; edgeShape[1].position = edgeShape[0].position + new Vector2(newPointA.x, newPointA.y); } if (isGabledRight) { float gableThickness = volume[facadeIndexRight].gableThickness; bool simpleGable = volume[facadeIndexRight].simpleGable; Gable gableStyle = volume[facadeIndexRight].gableStyle; if (!simpleGable && gableStyle == null || !isFloor) { gableThickness = 0; } Vector3 newPointB = Vector3.Project(p2 - p1, cross) - dir * gableThickness; edgeShape[2].position = edgeShape[3].position + new Vector2(newPointB.x, newPointB.y); } } Vector3[] verts = new Vector3[edgeShapeCount]; Vector2[] uvs = new Vector2[edgeShapeCount]; Vector3 baseShapeDirection = ToV3(nodeB.position - nodeA.position).normalized; float uvAngle = SignAngle(new Vector2(baseShapeDirection.x, baseShapeDirection.z).normalized) - 90; Vector2[] faceShape = new Vector2[edgeShapeCount]; Vector3[] normals = new Vector3[edgeShapeCount]; Vector4[] tangents = new Vector4[edgeShapeCount]; Vector4 tangent = BuildRMesh.CalculateTangent(baseShapeDirection); for (int i = 0; i < edgeShapeCount; i++) { Vector3 newVert = new Vector3(edgeShape[i].position.x, edgeShape[i].height * heightScale + roofBaseHeight, edgeShape[i].position.y); verts[i] = newVert; Vector2 baseUV = (i == 0) ? Vector2.zero : new Vector2(newVert.x - verts[0].x, newVert.z - verts[0].z); Vector2 newUV = Rotate(baseUV, uvAngle); float faceHeight = edgeShape[i].height * heightScale; newUV.y = Mathf.Sqrt((newUV.y * newUV.y) + (faceHeight * faceHeight)); if (surface != null) { newUV = surface.CalculateUV(newUV); } uvs[i] = newUV; faceShape[i] = edgeShape[i].position;//used for triangulation // normals[i] = normal; tangents[i] = tangent; } // int[] tris = EarClipper.Triangulate(faceShape, 0, -1); int[] tris = Poly2TriWrapper.Triangulate(faceShape, true); int triCount = tris.Length; if (triCount < 3) { continue; } Vector3 normal = BuildRMesh.CalculateNormal(verts[tris[0]], verts[tris[1]], verts[tris[2]]); for (int i = 0; i < edgeShapeCount; i++) { normals[i] = normal;//normCal[i].normalized; } mesh.AddData(verts, uvs, tris, normals, tangents, submesh); if (isGabled) { for (int t = 0; t < triCount; t += 3) { if (tris[t] == 0 || tris[t + 1] == 0 || tris[t + 2] == 0) { int beB = edgeShapeCount - 1; if (tris[t] == beB || tris[t + 1] == beB || tris[t + 2] == beB) { Vector3 b0 = verts[0]; Vector3 b1 = verts[beB]; int topIndex = 0; for (int tx = 0; tx < 3; tx++) { if (tris[t + tx] != 0 && tris[t + tx] != beB) { topIndex = tris[t + tx]; } } Vector3 b2 = verts[topIndex]; Vector3 baseV = b1 - b0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir); // float length = baseV.magnitude; Vector3 center = Vector3.Lerp(b0, b1, 0.5f); Vector3 up = Vector3.Project(b2 - b0, Vector3.up); Vector3 b3 = center + up; mesh.AddTri(b0, b2, b3, face, submesh); //left mesh.AddTri(b1, b3, b2, -face, submesh); //right mesh.AddTri(b0, b3, b1, dir, submesh); //face //clear triangle tris[t] = 0; tris[t + 1] = 0; tris[t + 2] = 0; } } } } } else if (isFloor) { Roof roof = volume.roof; Edge baseEdge = baseEdges[b]; Node nodeA = baseEdge.nodeA; Node nodeB = baseEdge.nodeB; Vector3 p0 = new Vector3(nodeA.position.x, heightScale + roofBaseHeight, nodeA.position.y); Vector3 p1 = new Vector3(nodeB.position.x, heightScale + roofBaseHeight, nodeB.position.y); Vector3 baseV = p1 - p0; Vector3 dir = baseV.normalized; Vector3 face = Vector3.Cross(Vector3.up, dir).normalized; Vector3 parapetEdgeModifier = dir * (roof.overhang - (roof.parapetFrontDepth + roof.parapetBackDepth)) * 1.05f; p0 += parapetEdgeModifier; p1 += -parapetEdgeModifier; // p0 += face * (roof.parapetFrontDepth + roof.parapetBackDepth + roof.overhang); VolumePoint volumePoint = volume[facadeIndices[b]]; bool simpleGable = volumePoint.simpleGable; Gable gableStyle = volume[facadeIndices[b]].gableStyle; if (!simpleGable && gableStyle == null) { simpleGable = true; } float thickness = volume[facadeIndices[b]].gableThickness; float additionalHeight = volume[facadeIndices[b]].gableHeight; float height = roof.height + additionalHeight; if (simpleGable) //generate a simple gable { int wallSubmesh = mesh.submeshLibrary.SubmeshAdd(roof.wallSurface); //surfaceMapping.IndexOf(roof.wallSurface); if (wallSubmesh == -1) { wallSubmesh = submesh; } Vector3 g0 = p0; Vector3 g1 = p0 + Vector3.up * additionalHeight; Vector3 g2 = g1 + dir * roof.floorDepth * 0.5f; Vector3 g3 = g2 + dir * roof.depth * 0.5f + Vector3.up * roof.height; Vector3 g7 = p1; Vector3 g6 = p1 + Vector3.up * additionalHeight; Vector3 g5 = g6 - dir * roof.floorDepth * 0.5f; Vector3 g4 = g5 - dir * roof.depth * 0.5f + Vector3.up * roof.height; Vector3 gF = -face * thickness; mesh.AddPlane(g0, g7, g1, g6, wallSubmesh); //bottom front mesh.AddPlane(g7 + gF, g0 + gF, g6 + gF, g1 + gF, wallSubmesh); //bottom back mesh.AddPlane(g1, g6, g1 + gF, g6 + gF, wallSubmesh); //bottom top mesh.AddPlane(g0, g1, g0 + gF, g1 + gF, wallSubmesh); //bottom sides mesh.AddPlane(g6, g7, g6 + gF, g7 + gF, wallSubmesh); mesh.AddPlane(g2, g5, g3, g4, wallSubmesh); //top front mesh.AddPlane(g5 + gF, g2 + gF, g4 + gF, g3 + gF, wallSubmesh); //top back mesh.AddPlane(g2 + gF, g2, g3 + gF, g3, wallSubmesh); //top sides mesh.AddPlane(g5, g5 + gF, g4, g4 + gF, wallSubmesh); //top sides mesh.AddPlane(g3 + gF, g3, g4 + gF, g4, wallSubmesh); //top top } else { Vector2 baseUV = new Vector2(0, volume.planHeight); GableGenerator.Generate(ref mesh, gableStyle, p0, p1, height, thickness, baseUV); } } } if (generateDormers) { DormerGenerator.Generate(ref mesh, volume, roofFaces); } }