private static void WriteToAppropriateMesh(UncheckedMesh mesh, Mesh iconMesh, Mesh normalMesh) { if (HighLogic.LoadedScene == GameScenes.LOADING) { mesh.WriteTo(iconMesh); } else { mesh.WriteTo(normalMesh); } }
private void GenerateColliderMesh() { var mesh = new UncheckedMesh(CornerCount * 2, SideTriangles + 2 * TrianglesPerCap); GenerateCapVertices(mesh, -HalfHeight, 0); GenerateCapVertices(mesh, HalfHeight, CornerCount); GenerateSideTriangles(mesh, CornerCount, 1); GenerateCapTriangles(mesh, false, SideTriangles); GenerateCapTriangles(mesh, true, SideTriangles + TrianglesPerCap); var colliderMesh = new Mesh(); mesh.WriteTo(colliderMesh); PPart.ColliderMesh = colliderMesh; }
private static void WriteToAppropriateMesh(UncheckedMesh mesh, Mesh iconMesh, Mesh normalMesh) { var target = (HighLogic.LoadedScene == GameScenes.LOADING) ? iconMesh : normalMesh; mesh.WriteTo(target); }
void UpdateFairing() { ProceduralPart ppart = PPart; if (useFairing && ppart != null) { ProceduralAbstractSoRShape shape = ppart.CurrentShape as ProceduralAbstractSoRShape; if (shape != null) { Vector3[] topEndcapVerticies = shape.GetEndcapVerticies(true); Vector3[] topInner = new Vector3[topEndcapVerticies.Length + 1]; topEndcapVerticies.CopyTo(topInner, 0); topInner[topEndcapVerticies.Length] = topEndcapVerticies[0]; int vertCount = topInner.Length; //foreach (Vector3 v in topInner) // Debug.Log(v); Vector3[] topOuter = (Vector3[])topInner.Clone(); for (int i = 0; i < vertCount; ++i) { float r = topInner[i].magnitude; float r_ = r + fairingThickness; float scaleFactor = r_ / r; topOuter[i].x *= scaleFactor; topOuter[i].z *= scaleFactor; } TextureScale.x = topOuter[0].magnitude * 2 * Mathf.PI; Vector3[] sideTop = (Vector3[])topOuter.Clone(); Vector3[] sideBottom = (Vector3[])sideTop.Clone(); Vector3[] bottomInner = (Vector3[])topInner.Clone(); Vector3[] bottomOuter = (Vector3[])topOuter.Clone(); for (int i = 0; i < vertCount; ++i) { if (bottomNode != null) { sideBottom[i].y = bottomNode.position.y; bottomInner[i].y = bottomNode.position.y; bottomOuter[i].y = bottomNode.position.y; } } TextureScale.y = Mathf.Abs(topOuter[0].y - bottomOuter[0].y); Vector3[] innerSideTop = (Vector3[])topInner.Clone(); Vector3[] innerSideBottom = (Vector3[])bottomInner.Clone(); int topInnerStart = 0; int topOuterStart = topInnerStart + vertCount; int sideTopStart = topOuterStart + vertCount; int sideBottomStart = sideTopStart + vertCount; int bottomInnerStart = sideBottomStart + vertCount; int bottomOuterStart = bottomInnerStart + vertCount; int innerSideTopStart = bottomOuterStart + vertCount; int innerSideBottomStart = innerSideTopStart + vertCount; UncheckedMesh m = new UncheckedMesh(vertCount * 8, vertCount * 8 * 6); //int tri = 0; for (int i = 0; i < vertCount; ++i) { m.verticies[topInnerStart + i] = topInner[i]; m.verticies[topOuterStart + i] = topOuter[i]; m.verticies[sideTopStart + i] = sideTop[i]; m.verticies[sideBottomStart + i] = sideBottom[i]; m.verticies[bottomInnerStart + i] = bottomInner[i]; m.verticies[bottomOuterStart + i] = bottomOuter[i]; m.verticies[innerSideTopStart + i] = innerSideTop[i]; m.verticies[innerSideBottomStart + i] = innerSideBottom[i]; m.normals[topInnerStart + i] = new Vector3(0.0f, 1.0f, 0.0f); m.normals[topOuterStart + i] = new Vector3(0.0f, 1.0f, 0.0f); m.normals[sideTopStart + i] = m.verticies[sideTopStart + i].xz().normalized; m.normals[sideBottomStart + i] = m.verticies[sideBottomStart + i].xz().normalized; m.normals[bottomInnerStart + i] = new Vector3(0.0f, -1.0f, 0.0f); m.normals[bottomOuterStart + i] = new Vector3(0.0f, -1.0f, 0.0f); m.normals[innerSideTopStart + i] = -m.verticies[innerSideTopStart + i].xz().normalized; m.normals[innerSideBottomStart + i] = -m.verticies[innerSideBottomStart + i].xz().normalized; m.uv[topInnerStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[topOuterStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[sideTopStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[sideBottomStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[bottomInnerStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[bottomOuterStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[innerSideTopStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[innerSideBottomStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.tangents[topInnerStart + i] = Vector3.Cross(m.normals[topInnerStart + i], m.verticies[topInnerStart + i]).xz().normalized.toVec4(-1); m.tangents[topOuterStart + i] = Vector3.Cross(m.normals[topOuterStart + i], m.verticies[topOuterStart + i]).xz().normalized.toVec4(-1); m.tangents[sideTopStart + i] = Vector3.Cross(m.normals[sideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[sideBottomStart + i] = Vector3.Cross(m.normals[sideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[bottomInnerStart + i] = Vector3.Cross(m.normals[bottomInnerStart + i], m.verticies[topInnerStart + i]).xz().normalized.toVec4(-1); m.tangents[bottomOuterStart + i] = Vector3.Cross(m.normals[bottomOuterStart + i], m.verticies[topOuterStart + i]).xz().normalized.toVec4(-1); m.tangents[innerSideTopStart + i] = Vector3.Cross(m.normals[innerSideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[innerSideBottomStart + i] = Vector3.Cross(m.normals[innerSideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); //Debug.Log(i +" uv: " + Mathf.InverseLerp(0, vertCount - 1, i)); } int triangleOffset = 0; triangleOffset = ConnectRings(m, topInnerStart, topOuterStart, vertCount, 0); triangleOffset = ConnectRings(m, sideTopStart, sideBottomStart, vertCount, triangleOffset); triangleOffset = ConnectRings(m, bottomOuterStart, bottomInnerStart, vertCount, triangleOffset); triangleOffset = ConnectRings(m, innerSideBottomStart, innerSideTopStart, vertCount, triangleOffset); if (fairingMesh != null) { m.WriteTo(fairingMesh); fairingMesh.RecalculateNormals(); } else { Debug.Log("no fairing mesh"); } } oldTextureSet = null; UpdateTexture(); } }
/// <summary> /// Generate the compShape from profile points from pt to bottom. /// Note that this list will have extra interpolated points added if the change in radius is high to avoid /// texture stretching. /// </summary> /// <param name="pts"></param> protected void WriteMeshes(LinkedList <ProfilePoint> pts) { if (pts == null || pts.Count < 2) { return; } // update nodes UpdateNodeSize(pts.First(), bottomNodeName); UpdateNodeSize(pts.Last(), topNodeName); // Move attachments first, before subdividing MoveAttachments(pts); // Horizontal profile point subdivision SubdivHorizontal(pts); // Tank stats float tankVLength = 0; int nVrt = 0; int nTri = 0; int nColVrt = 0; int nColTri = 0; bool customCollider = false; ProfilePoint first = pts.First.Value; ProfilePoint last = pts.Last.Value; if (!first.inCollider || !last.inCollider) { throw new InvalidOperationException("First and last profile points must be used in the collider"); } foreach (ProfilePoint pt in pts) { customCollider = customCollider || pt.CustomCollider; if (pt.inRender) { nVrt += pt.circ.totVertexes + 1; // one for above, one for below nTri += 2 * pt.circ.totVertexes; } if (pt.inCollider) { nColVrt += pt.colliderCirc.totVertexes + 1; nColTri += 2 * pt.colliderCirc.totVertexes; } } // Have double counted for the first and last circles. nTri -= first.circ.totVertexes + last.circ.totVertexes; nColTri -= first.colliderCirc.totVertexes + last.colliderCirc.totVertexes; UncheckedMesh m = new UncheckedMesh(nVrt, nTri); float sumDiameters = 0; //Debug.LogWarning("Display mesh vert=" + nVrt + " tris=" + nTri); bool odd = false; { ProfilePoint prev = null; int off = 0, prevOff = 0; int tOff = 0; foreach (ProfilePoint pt in pts) { if (!pt.inRender) { continue; } pt.circ.WriteVertexes(diameter: pt.dia, y: pt.y, v: pt.v, norm: pt.norm, off: off, m: m, odd: odd); if (prev != null) { CirclePoints.WriteTriangles(prev.circ, prevOff, pt.circ, off, m.triangles, tOff * 3, !odd); tOff += prev.circ.totVertexes + pt.circ.totVertexes; // Deprecated: Volume has been moved up to callers. This way we can use the idealized rather than aproximate volume // Work out the area of the truncated cone // integral_y1^y2 pi R(y)^2 dy where R(y) = ((r2-r1)(y-y1))/(r2-r1) + r1 Integrate circles along a line // integral_y1^y2 pi ( ((r2-r1)(y-y1))/(r2-r1) + r1) ^2 dy Substituted in formula. // == -1/3 pi (y1-y2) (r1^2+r1*r2+r2^2) Do the calculus // == -1/3 pi (y1-y2) (d1^2/4+d1*d2/4+d2^2/4) r = d/2 // == -1/12 pi (y1-y2) (d1^2+d1*d2+d2^2) Take out the factor //volume += (Mathf.PI * (pt.y - prev.y) * (prev.dia * prev.dia + prev.dia * pt.dia + pt.dia * pt.dia)) / 12f; float dy = (pt.y - prev.y); float dr = (prev.dia - pt.dia) * 0.5f; //print("dy=" + dy + " dr=" + dr + " len=" + Mathf.Sqrt(dy * dy + dr * dr).ToString("F3")); tankVLength += Mathf.Sqrt(dy * dy + dr * dr); // average diameter weighted by dy sumDiameters += (pt.dia + prev.dia) * dy; } prev = pt; prevOff = off; off += pt.circ.totVertexes + 1; odd = !odd; } } // Use the weighted average diameter across segments to set the ULength float tankULength = Mathf.PI * sumDiameters / (last.y - first.y); //print("ULength=" + tankULength + " VLength=" + tankVLength); // set the texture scale. RaiseChangeTextureScale("sides", PPart.SidesMaterial, new Vector2(tankULength, tankVLength)); m.WriteTo(SidesMesh); // The endcaps. nVrt = first.circ.totVertexes + last.circ.totVertexes; nTri = first.circ.totVertexes - 2 + last.circ.totVertexes - 2; m = new UncheckedMesh(nVrt, nTri); first.circ.WriteEndcap(first.dia, first.y, false, 0, 0, m, false); last.circ.WriteEndcap(last.dia, last.y, true, first.circ.totVertexes, (first.circ.totVertexes - 2) * 3, m, !odd); m.WriteTo(EndsMesh); // build the collider mesh at a lower resolution than the visual mesh. if (customCollider) { //Debug.LogWarning("Collider mesh vert=" + nColVrt + " tris=" + nColTri); m = new UncheckedMesh(nColVrt, nColTri); odd = false; { ProfilePoint prev = null; int off = 0, prevOff = 0; int tOff = 0; foreach (ProfilePoint pt in pts) { if (!pt.inCollider) { continue; } //Debug.LogWarning("Collider circ (" + pt.dia + ", " + pt.y + ") verts=" + pt.colliderCirc.totVertexes); pt.colliderCirc.WriteVertexes(diameter: pt.dia, y: pt.y, v: pt.v, norm: pt.norm, off: off, m: m, odd: odd); if (prev != null) { CirclePoints.WriteTriangles(prev.colliderCirc, prevOff, pt.colliderCirc, off, m.triangles, tOff * 3, !odd); tOff += prev.colliderCirc.totVertexes + pt.colliderCirc.totVertexes; } prev = pt; prevOff = off; off += pt.colliderCirc.totVertexes + 1; odd = !odd; } } if (colliderMesh == null) { colliderMesh = new Mesh(); } m.WriteTo(colliderMesh); PPart.ColliderMesh = colliderMesh; } else { PPart.ColliderMesh = SidesMesh; } RaiseModelAndColliderChanged(); }
void UpdateFairing() { Transform fairing = part.FindModelTransform("fairing"); Mesh fairingMesh = fairing.GetComponent <MeshFilter>().mesh; if (useFairing && fairingMesh is Mesh && PPart?.CurrentShape is ProceduralAbstractSoRShape shape) { Vector3[] topEndcapVerticies = shape.GetEndcapVerticies(true); Vector3[] topInner = new Vector3[topEndcapVerticies.Length + 1]; topEndcapVerticies.CopyTo(topInner, 0); topInner[topEndcapVerticies.Length] = topEndcapVerticies[0]; int vertCount = topInner.Length; Vector3[] topOuter = (Vector3[])topInner.Clone(); for (int i = 0; i < vertCount; ++i) { float r = topInner[i].magnitude; float r_ = r + fairingThickness; float scaleFactor = r_ / r; topOuter[i].x *= scaleFactor; topOuter[i].z *= scaleFactor; } Vector3[] sideTop = (Vector3[])topOuter.Clone(); Vector3[] sideBottom = (Vector3[])sideTop.Clone(); Vector3[] bottomInner = (Vector3[])topInner.Clone(); Vector3[] bottomOuter = (Vector3[])topOuter.Clone(); for (int i = 0; i < vertCount; ++i) { if (bottomNode != null) { sideBottom[i].y = bottomNode.position.y; bottomInner[i].y = bottomNode.position.y; bottomOuter[i].y = bottomNode.position.y; } } Vector3[] innerSideTop = (Vector3[])topInner.Clone(); Vector3[] innerSideBottom = (Vector3[])bottomInner.Clone(); int topInnerStart = 0; int topOuterStart = topInnerStart + vertCount; int sideTopStart = topOuterStart + vertCount; int sideBottomStart = sideTopStart + vertCount; int bottomInnerStart = sideBottomStart + vertCount; int bottomOuterStart = bottomInnerStart + vertCount; int innerSideTopStart = bottomOuterStart + vertCount; int innerSideBottomStart = innerSideTopStart + vertCount; UncheckedMesh m = new UncheckedMesh(vertCount * 8, vertCount * 8 * 6); //int tri = 0; for (int i = 0; i < vertCount; ++i) { m.vertices[topInnerStart + i] = topInner[i]; m.vertices[topOuterStart + i] = topOuter[i]; m.vertices[sideTopStart + i] = sideTop[i]; m.vertices[sideBottomStart + i] = sideBottom[i]; m.vertices[bottomInnerStart + i] = bottomInner[i]; m.vertices[bottomOuterStart + i] = bottomOuter[i]; m.vertices[innerSideTopStart + i] = innerSideTop[i]; m.vertices[innerSideBottomStart + i] = innerSideBottom[i]; m.normals[topInnerStart + i] = new Vector3(0.0f, 1.0f, 0.0f); m.normals[topOuterStart + i] = new Vector3(0.0f, 1.0f, 0.0f); m.normals[sideTopStart + i] = m.vertices[sideTopStart + i].xz().normalized; m.normals[sideBottomStart + i] = m.vertices[sideBottomStart + i].xz().normalized; m.normals[bottomInnerStart + i] = new Vector3(0.0f, -1.0f, 0.0f); m.normals[bottomOuterStart + i] = new Vector3(0.0f, -1.0f, 0.0f); m.normals[innerSideTopStart + i] = -m.vertices[innerSideTopStart + i].xz().normalized; m.normals[innerSideBottomStart + i] = -m.vertices[innerSideBottomStart + i].xz().normalized; m.uv[topInnerStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[topOuterStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[sideTopStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[sideBottomStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[bottomInnerStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[bottomOuterStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[innerSideTopStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[innerSideBottomStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.tangents[topInnerStart + i] = Vector3.Cross(m.normals[topInnerStart + i], m.vertices[topInnerStart + i]).xz().normalized.toVec4(-1); m.tangents[topOuterStart + i] = Vector3.Cross(m.normals[topOuterStart + i], m.vertices[topOuterStart + i]).xz().normalized.toVec4(-1); m.tangents[sideTopStart + i] = Vector3.Cross(m.normals[sideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[sideBottomStart + i] = Vector3.Cross(m.normals[sideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[bottomInnerStart + i] = Vector3.Cross(m.normals[bottomInnerStart + i], m.vertices[topInnerStart + i]).xz().normalized.toVec4(-1); m.tangents[bottomOuterStart + i] = Vector3.Cross(m.normals[bottomOuterStart + i], m.vertices[topOuterStart + i]).xz().normalized.toVec4(-1); m.tangents[innerSideTopStart + i] = Vector3.Cross(m.normals[innerSideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[innerSideBottomStart + i] = Vector3.Cross(m.normals[innerSideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); } int triangleOffset = 0; triangleOffset = ConnectRings(m, topInnerStart, topOuterStart, vertCount, triangleOffset); triangleOffset = ConnectRings(m, sideTopStart, sideBottomStart, vertCount, triangleOffset); triangleOffset = ConnectRings(m, bottomOuterStart, bottomInnerStart, vertCount, triangleOffset); _ = ConnectRings(m, innerSideBottomStart, innerSideTopStart, vertCount, triangleOffset); m.WriteTo(fairingMesh); fairingMesh.RecalculateNormals(); } UpdateMass(); }
void UpdateFairing() { ProceduralPart ppart = PPart; if (useFairing && ppart != null) { ProceduralAbstractSoRShape shape = ppart.CurrentShape as ProceduralAbstractSoRShape; if (shape != null) { Vector3[] topEndcapVerticies = shape.GetEndcapVerticies(true); Vector3[] topInner = new Vector3[topEndcapVerticies.Length + 1]; topEndcapVerticies.CopyTo(topInner, 0); topInner[topEndcapVerticies.Length] = topEndcapVerticies[0]; int vertCount = topInner.Length; //foreach (Vector3 v in topInner) // Debug.Log(v); Vector3[] topOuter = (Vector3[])topInner.Clone(); for (int i = 0; i < vertCount; ++i) { float r = topInner[i].magnitude; float r_ = r + fairingThickness; float scaleFactor = r_ / r; topOuter[i].x *= scaleFactor; topOuter[i].z *= scaleFactor; } TextureScale.x = topOuter[0].magnitude * 2 * Mathf.PI; Vector3[] sideTop = (Vector3[])topOuter.Clone(); Vector3[] sideBottom = (Vector3[])sideTop.Clone(); Vector3[] bottomInner = (Vector3[])topInner.Clone(); Vector3[] bottomOuter = (Vector3[])topOuter.Clone(); for (int i = 0; i < vertCount; ++i) { if (bottomNode != null) { sideBottom[i].y = bottomNode.position.y; bottomInner[i].y = bottomNode.position.y; bottomOuter[i].y = bottomNode.position.y; } } TextureScale.y = Mathf.Abs(topOuter[0].y - bottomOuter[0].y); Vector3[] innerSideTop = (Vector3[])topInner.Clone(); Vector3[] innerSideBottom = (Vector3[])bottomInner.Clone(); int topInnerStart = 0; int topOuterStart = topInnerStart + vertCount; int sideTopStart = topOuterStart + vertCount; int sideBottomStart = sideTopStart + vertCount; int bottomInnerStart = sideBottomStart + vertCount; int bottomOuterStart = bottomInnerStart + vertCount; int innerSideTopStart = bottomOuterStart + vertCount; int innerSideBottomStart = innerSideTopStart + vertCount; UncheckedMesh m = new UncheckedMesh(vertCount * 8, vertCount * 8 * 6); //int tri = 0; for (int i = 0; i < vertCount; ++i) { m.verticies[topInnerStart + i] = topInner[i]; m.verticies[topOuterStart + i] = topOuter[i]; m.verticies[sideTopStart + i] = sideTop[i]; m.verticies[sideBottomStart + i] = sideBottom[i]; m.verticies[bottomInnerStart + i] = bottomInner[i]; m.verticies[bottomOuterStart + i] = bottomOuter[i]; m.verticies[innerSideTopStart + i] = innerSideTop[i]; m.verticies[innerSideBottomStart + i] = innerSideBottom[i]; m.normals[topInnerStart + i] = new Vector3(0.0f, 1.0f, 0.0f); m.normals[topOuterStart + i] = new Vector3(0.0f, 1.0f, 0.0f); m.normals[sideTopStart + i] = m.verticies[sideTopStart + i].xz().normalized; m.normals[sideBottomStart + i] = m.verticies[sideBottomStart + i].xz().normalized; m.normals[bottomInnerStart + i] = new Vector3(0.0f, -1.0f, 0.0f); m.normals[bottomOuterStart + i] = new Vector3(0.0f, -1.0f, 0.0f); m.normals[innerSideTopStart + i] = -m.verticies[innerSideTopStart + i].xz().normalized; m.normals[innerSideBottomStart + i] = -m.verticies[innerSideBottomStart + i].xz().normalized; m.uv[topInnerStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[topOuterStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[sideTopStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[sideBottomStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[bottomInnerStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[bottomOuterStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.uv[innerSideTopStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 0.0f); m.uv[innerSideBottomStart + i] = new Vector2(Mathf.InverseLerp(0, vertCount - 1, i), 1.0f); m.tangents[topInnerStart + i] = Vector3.Cross(m.normals[topInnerStart + i], m.verticies[topInnerStart + i]).xz().normalized.toVec4(-1); m.tangents[topOuterStart + i] = Vector3.Cross(m.normals[topOuterStart + i], m.verticies[topOuterStart + i]).xz().normalized.toVec4(-1); m.tangents[sideTopStart + i] = Vector3.Cross(m.normals[sideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[sideBottomStart + i] = Vector3.Cross(m.normals[sideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[bottomInnerStart + i] = Vector3.Cross(m.normals[bottomInnerStart + i], m.verticies[topInnerStart + i]).xz().normalized.toVec4(-1); m.tangents[bottomOuterStart + i] = Vector3.Cross(m.normals[bottomOuterStart + i], m.verticies[topOuterStart + i]).xz().normalized.toVec4(-1); m.tangents[innerSideTopStart + i] = Vector3.Cross(m.normals[innerSideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); m.tangents[innerSideBottomStart + i] = Vector3.Cross(m.normals[innerSideTopStart + i], new Vector3(0, 1, 0)).normalized.toVec4(-1); //Debug.Log(i +" uv: " + Mathf.InverseLerp(0, vertCount - 1, i)); } int triangleOffset = 0; triangleOffset = ConnectRings(m, topInnerStart, topOuterStart, vertCount, 0); triangleOffset = ConnectRings(m, sideTopStart, sideBottomStart, vertCount, triangleOffset); triangleOffset = ConnectRings(m, bottomOuterStart, bottomInnerStart, vertCount, triangleOffset); triangleOffset = ConnectRings(m, innerSideBottomStart, innerSideTopStart, vertCount, triangleOffset); if (fairingMesh != null) { m.WriteTo(fairingMesh); fairingMesh.RecalculateNormals(); } else Debug.Log("no fairing mesh"); } oldTextureSet = null; UpdateTexture(); } }
/// <summary> /// Generate the compShape from profile points from pt to bottom. /// Note that this list will have extra interpolated points added if the change in radius is high to avoid /// texture stretching. /// </summary> /// <param name="pts"></param> protected void WriteMeshes(LinkedList<ProfilePoint> pts) { if (pts == null || pts.Count < 2) return; // update nodes UpdateNodeSize(pts.First(), bottomNodeName); UpdateNodeSize(pts.Last(), topNodeName); // Move attachments first, before subdividing MoveAttachments(pts); // Horizontal profile point subdivision SubdivHorizontal(pts); // Tank stats float tankULength = 0; float tankVLength = 0; int nVrt = 0; int nTri = 0; int nColVrt = 0; int nColTri = 0; bool customCollider = false; ProfilePoint first = pts.First.Value; ProfilePoint last = pts.Last.Value; if (!first.inCollider || !last.inCollider) throw new InvalidOperationException("First and last profile points must be used in the collider"); foreach (ProfilePoint pt in pts) { customCollider = customCollider || pt.customCollider; if (pt.inRender) { nVrt += pt.circ.totVertexes + 1; // one for above, one for below nTri += 2 * pt.circ.totVertexes; } if (pt.inCollider) { nColVrt += pt.colliderCirc.totVertexes + 1; nColTri += 2 * pt.colliderCirc.totVertexes; } } // Have double counted for the first and last circles. nTri -= first.circ.totVertexes + last.circ.totVertexes; nColTri -= first.colliderCirc.totVertexes + last.colliderCirc.totVertexes; UncheckedMesh m = new UncheckedMesh(nVrt, nTri); float sumDiameters = 0; //Debug.LogWarning("Display mesh vert=" + nVrt + " tris=" + nTri); bool odd = false; { ProfilePoint prev = null; int off = 0, prevOff = 0; int tOff = 0; foreach (ProfilePoint pt in pts) { if (!pt.inRender) continue; pt.circ.WriteVertexes(diameter: pt.dia, y: pt.y, v: pt.v, norm: pt.norm, off: off, m: m, odd: odd); if (prev != null) { CirclePoints.WriteTriangles(prev.circ, prevOff, pt.circ, off, m.triangles, tOff * 3, !odd); tOff += prev.circ.totVertexes + pt.circ.totVertexes; // Deprecated: Volume has been moved up to callers. This way we can use the idealized rather than aproximate volume // Work out the area of the truncated cone // integral_y1^y2 pi R(y)^2 dy where R(y) = ((r2-r1)(y-y1))/(r2-r1) + r1 Integrate circles along a line // integral_y1^y2 pi ( ((r2-r1)(y-y1))/(r2-r1) + r1) ^2 dy Substituted in formula. // == -1/3 pi (y1-y2) (r1^2+r1*r2+r2^2) Do the calculus // == -1/3 pi (y1-y2) (d1^2/4+d1*d2/4+d2^2/4) r = d/2 // == -1/12 pi (y1-y2) (d1^2+d1*d2+d2^2) Take out the factor //volume += (Mathf.PI * (pt.y - prev.y) * (prev.dia * prev.dia + prev.dia * pt.dia + pt.dia * pt.dia)) / 12f; float dy = (pt.y - prev.y); float dr = (prev.dia - pt.dia) * 0.5f; //print("dy=" + dy + " dr=" + dr + " len=" + Mathf.Sqrt(dy * dy + dr * dr).ToString("F3")); tankVLength += Mathf.Sqrt(dy * dy + dr * dr); // average diameter weighted by dy sumDiameters += (pt.dia + prev.dia) * dy; } prev = pt; prevOff = off; off += pt.circ.totVertexes + 1; odd = !odd; } } // Use the weighted average diameter across segments to set the ULength tankULength = Mathf.PI * sumDiameters / (last.y - first.y); //print("ULength=" + tankULength + " VLength=" + tankVLength); // set the texture scale. RaiseChangeTextureScale("sides", pPart.sidesMaterial, new Vector2(tankULength, tankVLength)); m.WriteTo(sidesMesh); // The endcaps. nVrt = first.circ.totVertexes + last.circ.totVertexes; nTri = first.circ.totVertexes - 2 + last.circ.totVertexes - 2; m = new UncheckedMesh(nVrt, nTri); first.circ.WriteEndcap(first.dia, first.y, false, 0, 0, m, false); last.circ.WriteEndcap(last.dia, last.y, true, first.circ.totVertexes, (first.circ.totVertexes - 2) * 3, m, !odd); m.WriteTo(endsMesh); // build the collider mesh at a lower resolution than the visual mesh. if (customCollider) { //Debug.LogWarning("Collider mesh vert=" + nColVrt + " tris=" + nColTri); m = new UncheckedMesh(nColVrt, nColTri); odd = false; { ProfilePoint prev = null; int off = 0, prevOff = 0; int tOff = 0; foreach (ProfilePoint pt in pts) { if (!pt.inCollider) continue; //Debug.LogWarning("Collider circ (" + pt.dia + ", " + pt.y + ") verts=" + pt.colliderCirc.totVertexes); pt.colliderCirc.WriteVertexes(diameter: pt.dia, y: pt.y, v: pt.v, norm: pt.norm, off: off, m: m, odd: odd); if (prev != null) { CirclePoints.WriteTriangles(prev.colliderCirc, prevOff, pt.colliderCirc, off, m.triangles, tOff * 3, !odd); tOff += prev.colliderCirc.totVertexes + pt.colliderCirc.totVertexes; } prev = pt; prevOff = off; off += pt.colliderCirc.totVertexes + 1; odd = !odd; } } if (colliderMesh == null) colliderMesh = new Mesh(); m.WriteTo(colliderMesh); pPart.colliderMesh = colliderMesh; } else { pPart.colliderMesh = sidesMesh; } RaiseModelAndColliderChanged(); }