int ConnectRings(UncheckedMesh m, int ring1Offset, int ring2Offset, int vertCount, int triOffset, bool inverse = false) { int tri = triOffset; for (int i = 0; i < vertCount; ++i) { //Debug.Log(i); if (i < vertCount - 1) { m.triangles[tri++] = ring1Offset + i; m.triangles[tri++] = ring1Offset + i + 1; m.triangles[tri++] = ring2Offset + i + 1; m.triangles[tri++] = ring1Offset + i; m.triangles[tri++] = ring2Offset + i + 1; m.triangles[tri++] = ring2Offset + i; } else { //m.triangles[tri++] = ring1Offset + i; //m.triangles[tri++] = ring1Offset; //m.triangles[tri++] = ring2Offset; //m.triangles[tri++] = ring1Offset + i; //m.triangles[tri++] = ring2Offset; //m.triangles[tri++] = ring2Offset + i; } } return(tri); }
private void GenerateCapVertices(UncheckedMesh mesh, float y, int offset) { for (var cornerNumber = 0; cornerNumber < CornerCount; cornerNumber++) { CreateCapCornerVertices(mesh, y, offset, cornerNumber); } }
private void GenerateSideVertices(UncheckedMesh mesh, bool outside, float bottomOuterRadius, float bottomInnerRadius, float topOuterRadius, float topInnerRadius, float height, int nbSides, int verticalPoints, int offset) { for (int side = 0; side <= nbSides; side++) { int currSide = side == nbSides ? 0 : side; // Angle around the part, offset to align texture with other parts orientation float t1 = ((float)currSide / nbSides + 0.25f) * 2f * Mathf.PI; for (int verticalPoint = 0; verticalPoint <= verticalPoints; verticalPoint++) { float currFrac = (float)verticalPoint / verticalPoints; float xLength = outside ? (topOuterRadius + currFrac * (bottomOuterRadius - topOuterRadius)) : (topInnerRadius + currFrac * (bottomInnerRadius - topInnerRadius)); Vector3 xVector = Quaternion.AngleAxis(-t1 * Mathf.Rad2Deg, Vector3.up) * new Vector3((outside ? 1:1), 0) * xLength; Vector3 yVector = Vector3.up * (0.5f - currFrac) * height; mesh.vertices[offset + ((verticalPoints + 1) * side + verticalPoint)] = xVector + yVector; Vector3 normalInPlane = new Vector3(Mathf.Cos(t1), 0f, Mathf.Sin(t1)) * (outside ? 1 : -1); Vector3 normal = (normalInPlane * height + Vector3.up * (outside ? (bottomOuterRadius - topOuterRadius) : (topInnerRadius - bottomInnerRadius))).normalized; mesh.normals[offset + ((verticalPoints + 1) * side + verticalPoint)] = normal; mesh.tangents[offset + ((verticalPoints + 1) * side + verticalPoint)] = new Vector4(-Mathf.Sin(t1), 0, Mathf.Cos(t1), (outside ? -1 : 1)); mesh.uv[offset + ((verticalPoints + 1) * side + verticalPoint)] = new Vector2((float)side / nbSides * (outside ? 1 : -1), 1 - currFrac); } } }
private void GenerateMeshes(float bottomOuterRadius, float bottomInnerRadius, float topOuterRadius, float topInnerRadius, float height, int nbSides) { float verticalpointDensity = 12f; int outsideVerticalPoints = (int)Math.Floor(Mathf.Abs(bottomOuterRadius - topOuterRadius) * verticalpointDensity) + 2; int insideVerticalPoints = (int)Math.Floor(Mathf.Abs(bottomInnerRadius - topInnerRadius) * verticalpointDensity) + 2; UncheckedMesh sideMesh = new UncheckedMesh((outsideVerticalPoints + insideVerticalPoints) * (nbSides + 1), (outsideVerticalPoints + insideVerticalPoints - 2) * 3 * (nbSides + 1)); GenerateSideVertices(sideMesh, true, bottomOuterRadius, bottomInnerRadius, topOuterRadius, topInnerRadius, height, nbSides, outsideVerticalPoints - 1, 0); GenerateSideVertices(sideMesh, false, bottomOuterRadius, bottomInnerRadius, topOuterRadius, topInnerRadius, height, nbSides, insideVerticalPoints - 1, outsideVerticalPoints * (nbSides + 1)); GenerateSideTriangles(sideMesh, true, nbSides, outsideVerticalPoints, 0, 0); GenerateSideTriangles(sideMesh, false, nbSides, insideVerticalPoints, outsideVerticalPoints * (nbSides + 1), (outsideVerticalPoints - 1) * 6 * (nbSides + 1)); var tankULength = numSides * NormSideLength * (topOuterRadius + bottomOuterRadius) * 2; var tankVLength = length; RaiseChangeTextureScale("sides", PPart.legacyTextureHandler.SidesMaterial, new Vector2(tankULength, tankVLength)); WriteToAppropriateMesh(sideMesh, PPart.SidesIconMesh, SidesMesh); UncheckedMesh capMesh = new UncheckedMesh(4 * (nbSides + 1), 4 * (nbSides + 1)); GenerateCapVertices(capMesh, true, topOuterRadius, topInnerRadius, height, nbSides, 0); GenerateCapVertices(capMesh, false, bottomOuterRadius, bottomInnerRadius, height, nbSides, 2 * (nbSides + 1)); GenerateCapTriangles(capMesh, true, nbSides, 0, 0); GenerateCapTriangles(capMesh, false, nbSides, 2 * (nbSides + 1), 6 * (nbSides + 1)); WriteToAppropriateMesh(capMesh, PPart.EndsIconMesh, EndsMesh); }
private void GenerateSideVertices(UncheckedMesh mesh, bool outside, float revolutionRadius, float majorFeatureRadius, float height, float filletRadius, int pointsInProfile, int nbSides, int offset) { int pointsInCornerProfile = pointsInProfile / 2; #region Vertices float _2pi = Mathf.PI * 2f; for (int side = 0; side <= nbSides; side++) { int currSide = side == nbSides ? 0 : side; float t1 = ((float)currSide / nbSides + 0.25f) * 2f * Mathf.PI; Vector3 r1 = new Vector3(Mathf.Cos(t1) * revolutionRadius, 0f, Mathf.Sin(t1) * revolutionRadius); foreach (bool top in new [] { true, false }) { for (int profilePoint = 0; profilePoint < pointsInCornerProfile; profilePoint++) { Vector3 xVector = Quaternion.AngleAxis(-t1 * Mathf.Rad2Deg, Vector3.up) * new Vector3((outside ? 1:-1), 0) * (majorFeatureRadius - filletRadius * (1 - Mathf.Sin(((float)profilePoint / (pointsInCornerProfile - 1) + (top ? 0:1)) * Mathf.PI / 2))); Vector3 yVector = Vector3.up * (top ? 1:-1) * (height / 2 - filletRadius * (1 - Mathf.Cos(((float)profilePoint / (pointsInCornerProfile - 1) - (top ? 0:1)) * Mathf.PI / 2))); mesh.vertices[offset + (2 * side + (top?0:1)) * pointsInCornerProfile + profilePoint] = r1 + xVector + yVector; Vector3 normalInPlane = new Vector3(Mathf.Cos(t1), 0f, Mathf.Sin(t1)) * (outside ? 1:-1) * (Mathf.Sin(((float)profilePoint / (pointsInCornerProfile - 1) + (top ? 0f:1f)) * Mathf.PI / 2)); Vector3 normalUp = Vector3.up * (Mathf.Cos(((float)profilePoint / (pointsInCornerProfile - 1) + (top ? 0f:1f)) * Mathf.PI / 2)); Vector3 normal = (normalInPlane + normalUp).normalized; mesh.normals[offset + (2 * side + (top?0:1)) * pointsInCornerProfile + profilePoint] = normal; mesh.tangents[offset + (2 * side + (top?0:1)) * pointsInCornerProfile + profilePoint] = new Vector4(-Mathf.Sin(t1), 0, Mathf.Cos(t1), (outside?-1:1)); float distanceIntoBend = (float)profilePoint / (pointsInCornerProfile - 1) * _2pi / 4 * filletRadius; mesh.uv[offset + (2 * side + (top?0:1)) * pointsInCornerProfile + profilePoint] = new Vector2((float)side / nbSides, 1 - (distanceIntoBend + (top?0:1) * (height + filletRadius * (_2pi / 4 - 2))) / (height + filletRadius * (_2pi / 2 - 2))); } } } #endregion }
/// <summary> /// writes this.totVerticies + 1 xy, verticies, and tangents and this.totVerticies triangles to the passed arrays for a single endcap. /// Callers will need to fill the normals. This will be { 0, 1, 0 } for pt endcap, and { 0, -1, 0 } for bottom. /// </summary> /// <param name="dia">diameter of circle</param> /// <param name="y">y dimension for points</param> /// <param name="up">If this endcap faces up</param> /// <param name="vOff">offset into xy, verticies, and normal arrays to begin at</param> /// <param name="to">offset into triangles array</param> /// <param name="m">Mesh to write into</param> /// <param name="odd">If this is an odd row</param> public void WriteEndcap(float dia, float y, bool up, int vOff, int to, UncheckedMesh m, bool odd) { Complete(); int o = odd ? 1 : 0; for (int i = 0; i <= subdivCount; ++i) { int o0 = vOff + i; m.uv[o0] = new Vector2((-xCoords[o][i] + 1f) * 0.5f, (-zCoords[o][i] + 1f) * 0.5f); m.verticies[o0] = new Vector3(xCoords[o][i] * dia * 0.5f, y, zCoords[o][i] * dia * 0.5f); int o1 = vOff + i + subdivCount + 1; m.uv[o1] = new Vector2((zCoords[o][i] + 1f) * 0.5f, (-xCoords[o][i] + 1f) * 0.5f); m.verticies[o1] = new Vector3(-zCoords[o][i] * dia * 0.5f, y, xCoords[o][i] * dia * 0.5f); int o2 = vOff + i + 2 * (subdivCount + 1); m.uv[o2] = new Vector2((xCoords[o][i] + 1f) * 0.5f, (zCoords[o][i] + 1f) * 0.5f); m.verticies[o2] = new Vector3(-xCoords[o][i] * dia * 0.5f, y, -zCoords[o][i] * dia * 0.5f); int o3 = vOff + i + 3 * (subdivCount + 1); m.uv[o3] = new Vector2((-zCoords[o][i] + 1f) * 0.5f, (xCoords[o][i] + 1f) * 0.5f); m.verticies[o3] = new Vector3(zCoords[o][i] * dia * 0.5f, y, -xCoords[o][i] * dia * 0.5f); m.tangents[o0] = m.tangents[o1] = m.tangents[o2] = m.tangents[o3] = new Vector4(-1, 0, 0, up ? 1 : -1); m.normals[o0] = m.normals[o1] = m.normals[o2] = m.normals[o3] = new Vector3(0, up ? 1 : -1, 0); } for (int i = 1; i < totVertexes - 1; ++i) { m.triangles[to++] = vOff; m.triangles[to++] = vOff + i + (up ? 1 : 0); m.triangles[to++] = vOff + i + (up ? 0 : 1); } }
private void GenerateMeshes(float revolutionRadius, float majorFeatureRadius, float height, float filletRadius, int nbSides) { float maxMeshBendError = 0.05f; int pointsperprofile = (int)Math.Max(Mathf.PI * Mathf.Sqrt(Mathf.Sqrt(fillet) / (2f * maxMeshBendError)), 2) * 2; UncheckedMesh sideMesh = new UncheckedMesh(2 * pointsperprofile * (nbSides + 1), (pointsperprofile - 1) * 3 * (nbSides + 1) * 2); GenerateSideVertices(sideMesh, true, revolutionRadius, majorFeatureRadius, height, filletRadius, pointsperprofile, nbSides, 0); GenerateSideVertices(sideMesh, false, revolutionRadius, majorFeatureRadius, height, filletRadius, pointsperprofile, nbSides, pointsperprofile * (nbSides + 1)); GenerateSideTriangles(sideMesh, true, nbSides, pointsperprofile, 0, 0); GenerateSideTriangles(sideMesh, false, nbSides, pointsperprofile, pointsperprofile * (nbSides + 1), (pointsperprofile - 1) * 2 * 3 * (nbSides + 1)); var tankULength = numSides * NormSideLength * (revolutionRadius + majorFeatureRadius) * 4; var tankVLength = length; RaiseChangeTextureScale("sides", PPart.legacyTextureHandler.SidesMaterial, new Vector2(tankULength, tankVLength)); WriteToAppropriateMesh(sideMesh, PPart.SidesIconMesh, SidesMesh); UncheckedMesh capMesh = new UncheckedMesh(2 * 2 * (nbSides + 1), 2 * 2 * (nbSides + 1)); GenerateCapVertices(capMesh, true, revolutionRadius, majorFeatureRadius - filletRadius, height, nbSides, 0); GenerateCapVertices(capMesh, false, revolutionRadius, majorFeatureRadius - filletRadius, height, nbSides, 2 * (nbSides + 1)); GenerateCapTriangles(capMesh, true, nbSides, 0, 0); GenerateCapTriangles(capMesh, false, nbSides, 2 * (nbSides + 1), 2 * 3 * (nbSides + 1)); WriteToAppropriateMesh(capMesh, PPart.EndsIconMesh, EndsMesh); }
private void SetSideVertexData(UncheckedMesh mesh, float v, int cornerNumber, float cornerAngle, int vertexCornerIndex, int vertexIndex) { mesh.uv[vertexIndex] = new Vector2((float)cornerNumber / CornerCount, v); var normalAngle = cornerAngle + CornerCenterCornerAngle / 2 * (-1 + 2 * vertexCornerIndex); var normal = CreateVectorFromAngle(normalAngle, 0, 1); mesh.normals[vertexIndex] = normal; mesh.tangents[vertexIndex] = new Vector4(normal.z, 0, -normal.x, 1f); }
private void GenerateCapMesh() { var mesh = new UncheckedMesh(CornerCount * 2, TrianglesPerCap * 2); GenerateCapVertices(mesh, -HalfHeight, 0); GenerateCapVertices(mesh, HalfHeight, CornerCount); GenerateCapTriangles(mesh, false, 0); GenerateCapTriangles(mesh, true, TrianglesPerCap); WriteToAppropriateMesh(mesh, PPart.EndsIconMesh, EndsMesh); }
private static void WriteToAppropriateMesh(UncheckedMesh mesh, Mesh iconMesh, Mesh normalMesh) { if (HighLogic.LoadedScene == GameScenes.LOADING) { mesh.WriteTo(iconMesh); } else { mesh.WriteTo(normalMesh); } }
private void GenerateCapTriangles(UncheckedMesh mesh, bool up, int triangleOffset) { var triangleIndexOffset = triangleOffset * 3; var vertexOffset = up ? CornerCount : 0; for (var i = 0; i < TrianglesPerCap; i++) { mesh.triangles[i * 3 + triangleIndexOffset] = vertexOffset; mesh.triangles[i * 3 + 1 + triangleIndexOffset] = (up ? i + 2 : i + 1) + vertexOffset; mesh.triangles[i * 3 + 2 + triangleIndexOffset] = (up ? i + 1 : i + 2) + vertexOffset; } }
private void GenerateSideMesh() { var mesh = new UncheckedMesh(SideVerticesPerCap * 2, SideTriangles); GenerateSideVertices(mesh, -HalfHeight, 0, 0); GenerateSideVertices(mesh, HalfHeight, 1, SideVerticesPerCap); GenerateSideTriangles(mesh, SideVerticesPerCap, 2); var tankULength = CornerCount * NormSideLength * InnerDiameter * 2; var tankVLength = Length; RaiseChangeTextureScale("sides", PPart.legacyTextureHandler.SidesMaterial, new Vector2(tankULength, tankVLength)); WriteToAppropriateMesh(mesh, PPart.SidesIconMesh, SidesMesh); }
private void CreateCapCornerVertices(UncheckedMesh mesh, float y, int offset, int cornerNumber) { var cornerAngle = GetCornerAngle(cornerNumber); var cornerVector = CreateVectorFromAngle(cornerAngle, y, OuterRadius); var verticesPerCorner = 1; for (var vertexCornerIndex = 0; vertexCornerIndex < verticesPerCorner; vertexCornerIndex++) { var vertexIndex = offset + cornerNumber * verticesPerCorner + vertexCornerIndex; mesh.vertices[vertexIndex] = cornerVector; SetCapVertexData(mesh, cornerVector, vertexIndex, y > 0); } }
private void GenerateSideTriangles(UncheckedMesh mesh, int numberOfCapVertices, int verticesPerCorner) { for (var i = 0; i < CornerCount; i++) { var baseVertex = i * verticesPerCorner + verticesPerCorner - 1; mesh.triangles[i * 6] = baseVertex; mesh.triangles[i * 6 + 1] = baseVertex + numberOfCapVertices; mesh.triangles[i * 6 + 2] = (baseVertex + 1) % numberOfCapVertices; mesh.triangles[i * 6 + 3] = (baseVertex + 1) % numberOfCapVertices; mesh.triangles[i * 6 + 4] = baseVertex + numberOfCapVertices; mesh.triangles[i * 6 + 5] = (baseVertex + 1) % numberOfCapVertices + numberOfCapVertices; } }
private void GenerateCapTriangles(UncheckedMesh mesh, bool up, int nbSides, int vertexOffset, int triangleOffset) { int i = 0; for (int side = 0; side < nbSides; side++) { mesh.triangles[triangleOffset + i++] = vertexOffset + side * 2; mesh.triangles[triangleOffset + i++] = vertexOffset + side * 2 + (up ? 1 : 2); mesh.triangles[triangleOffset + i++] = vertexOffset + side * 2 + (up ? 2 : 1); mesh.triangles[triangleOffset + i++] = vertexOffset + side * 2 + (up ? 1 : 3); mesh.triangles[triangleOffset + i++] = vertexOffset + side * 2 + (up ? 3 : 1); mesh.triangles[triangleOffset + i++] = vertexOffset + side * 2 + 2; } }
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 void CreateSideCornerVertices(UncheckedMesh mesh, float y, float v, int offset, int cornerNumber) { var cornerAngle = GetCornerAngle(cornerNumber); var cornerVector = CreateVectorFromAngle(cornerAngle, y, OuterRadius); var verticesPerCorner = 2; for (var vertexCornerIndex = 0; vertexCornerIndex < verticesPerCorner; vertexCornerIndex++) { var vertexIndex = offset + cornerNumber * verticesPerCorner + vertexCornerIndex; mesh.vertices[vertexIndex] = cornerVector; SetSideVertexData(mesh, v, cornerNumber, cornerAngle, vertexCornerIndex, vertexIndex); } mesh.uv[offset].x = 1; }
private void GenerateSideTriangles(UncheckedMesh mesh, bool outside, int nbSides, int pointsInProfile, int vertexOffset, int triangleOffset) { int i = 0; for (int side = 0; side <= nbSides; side++) { for (int segment = 0; segment <= pointsInProfile - 2; segment++) { int current = segment + side * pointsInProfile; int next = segment + (side < nbSides ? (side + 1) * pointsInProfile : 0); mesh.triangles[triangleOffset + i++] = vertexOffset + current; mesh.triangles[triangleOffset + i++] = vertexOffset + next + (outside ? 0 : 1); mesh.triangles[triangleOffset + i++] = vertexOffset + next + (outside ? 1 : 0); mesh.triangles[triangleOffset + i++] = vertexOffset + current + (outside ? 0 : 1); mesh.triangles[triangleOffset + i++] = vertexOffset + next + 1; mesh.triangles[triangleOffset + i++] = vertexOffset + current + (outside ? 1 : 0); } } }
private void GenerateCapVertices(UncheckedMesh mesh, bool top, float revolutionRadius, float majorFeatureRadius, float height, int nbSides, int offset) { #region Vertices float _2pi = Mathf.PI * 2f; for (int side = 0; side <= nbSides; side++) { int currSide = side == nbSides ? 0 : side; float t1 = (float)currSide / nbSides * _2pi; Vector3 r1 = new Vector3(Mathf.Cos(t1) * revolutionRadius, 0f, Mathf.Sin(t1) * revolutionRadius); Vector3 r2 = Quaternion.AngleAxis(-t1 * Mathf.Rad2Deg, Vector3.up) * new Vector3(majorFeatureRadius, 0); mesh.vertices[offset + 2 * side] = r1 + r2 + Vector3.up * height / 2 * (top ? 1:-1); mesh.vertices[offset + 2 * side + 1] = r1 - r2 + Vector3.up * height / 2 * (top ? 1:-1); // ugly, but quick to write mesh.normals[offset + 2 * side] = Vector3.up * (top ? 1:-1); mesh.normals[offset + 2 * side + 1] = Vector3.up * (top ? 1:-1); mesh.uv[offset + 2 * side] = new Vector2(Mathf.Cos(t1) * (top ? 1:-1), Mathf.Sin(t1)) / 2 + new Vector2(0.5f, 0.5f); mesh.uv[offset + 2 * side + 1] = new Vector2(Mathf.Cos(t1) * (top ? 1:-1), Mathf.Sin(t1)) * (revolutionRadius - majorFeatureRadius) / (revolutionRadius + majorFeatureRadius) / 2 + new Vector2(0.5f, 0.5f); mesh.tangents[offset + 2 * side] = new Vector4(1, 0, 0, 1f); mesh.tangents[offset + 2 * side + 1] = new Vector4(1, 0, 0, 1f); } #endregion }
private void GenerateCapVertices(UncheckedMesh mesh, bool top, float outsideRadius, float insideRadius, float height, int nbSides, int offset) { for (int side = 0; side <= nbSides; side++) { int currSide = side == nbSides ? 0 : side; // Angle around the part, offset to align texture with other parts orientation float t1 = ((float)currSide / nbSides + 0.25f) * 2f * Mathf.PI; Vector3 r1 = new Vector3(Mathf.Cos(t1) * outsideRadius, 0f, Mathf.Sin(t1) * outsideRadius); Vector3 r2 = new Vector3(Mathf.Cos(t1) * insideRadius, 0f, Mathf.Sin(t1) * insideRadius); mesh.vertices[offset + 2 * side] = r1 + Vector3.up * height / 2 * (top ? 1 : -1); mesh.vertices[offset + 2 * side + 1] = r2 + Vector3.up * height / 2 * (top ? 1 : -1); mesh.normals[offset + 2 * side] = Vector3.up * (top ? 1 : -1); mesh.normals[offset + 2 * side + 1] = Vector3.up * (top ? 1 : -1); mesh.uv[offset + 2 * side] = new Vector2(Mathf.Cos(t1) * (top ? 1 : -1), Mathf.Sin(t1)) / 2 + new Vector2(0.5f, 0.5f); mesh.uv[offset + 2 * side + 1] = new Vector2(Mathf.Cos(t1) * (top ? 1 : -1), Mathf.Sin(t1)) * (insideRadius) / (outsideRadius) / 2 + new Vector2(0.5f, 0.5f); mesh.tangents[offset + 2 * side] = new Vector4(1, 0, 0, 1f); mesh.tangents[offset + 2 * side + 1] = new Vector4(1, 0, 0, 1f); } }
private void GenerateMeshes(float outerRadius, float innerRadius, float height, int nbSides) { int verticalPoints = 2; UncheckedMesh sideMesh = new UncheckedMesh(verticalPoints * 2 * (nbSides + 1), (verticalPoints - 1) * 6 * (nbSides + 1)); GenerateSideVertices(sideMesh, true, outerRadius, innerRadius, height, nbSides, verticalPoints - 1, 0); GenerateSideVertices(sideMesh, false, outerRadius, innerRadius, height, nbSides, verticalPoints - 1, verticalPoints * (nbSides + 1)); GenerateSideTriangles(sideMesh, true, nbSides, verticalPoints, 0, 0); GenerateSideTriangles(sideMesh, false, nbSides, verticalPoints, verticalPoints * (nbSides + 1), (verticalPoints - 1) * 6 * (nbSides + 1)); var tankULength = numSides * NormSideLength * outerRadius * 2; var tankVLength = length; RaiseChangeTextureScale("sides", PPart.legacyTextureHandler.SidesMaterial, new Vector2(tankULength, tankVLength)); WriteToAppropriateMesh(sideMesh, PPart.SidesIconMesh, SidesMesh); UncheckedMesh capMesh = new UncheckedMesh(4 * (nbSides + 1), 4 * (nbSides + 1)); GenerateCapVertices(capMesh, true, outerRadius, innerRadius, height, nbSides, 0); GenerateCapVertices(capMesh, false, outerRadius, innerRadius, height, nbSides, 2 * (nbSides + 1)); GenerateCapTriangles(capMesh, true, nbSides, 0, 0); GenerateCapTriangles(capMesh, false, nbSides, 2 * (nbSides + 1), 6 * (nbSides + 1)); WriteToAppropriateMesh(capMesh, PPart.EndsIconMesh, EndsMesh); }
/// <summary> /// Write vertexes for the circle. /// </summary> /// <param name="diameter">diameter of the circle</param> /// <param name="y">y coordinate</param> /// <param name="norm">unit normal vector along the generator curve for increasing y. The y param becomes the y of the normal, the x multiplies the normals to the circle</param> /// <param name="v">v coordinate for UV</param> /// <param name="off">offset into following arrays</param> /// <param name="xy">UVs to copy into</param> /// <param name="verticies">vertexes</param> /// <param name="normals">normals</param> /// <param name="tangents">tangents</param> public void WriteVertexes(float diameter, float y, float v, Vector2 norm, int off, bool odd, UncheckedMesh m) { Complete(); int o = odd ? 1 : 0; for (int i = 0; i <= subdivCount; ++i) { int o0 = off + i; m.uv[o0] = new Vector2(uCoords[o][i], v); m.verticies[o0] = new Vector3(xCoords[o][i] * 0.5f * diameter, y, zCoords[o][i] * 0.5f * diameter); m.normals[o0] = new Vector3(xCoords[o][i] * norm.x, norm.y, zCoords[o][i] * norm.x); m.tangents[o0] = new Vector4(zCoords[o][i], 0, -xCoords[o][i], -1.0f); //MonoBehaviour.print("Vertex #" + i + " off=" + o0 + " u=" + xy[o0][0] + " coords=" + verticies[o0]); int o1 = off + i + subdivCount + 1; m.uv[o1] = new Vector2(uCoords[o][i] + 0.25f, v); m.verticies[o1] = new Vector3(-zCoords[o][i] * 0.5f * diameter, y, xCoords[o][i] * 0.5f * diameter); m.normals[o1] = new Vector3(-zCoords[o][i] * norm.x, norm.y, xCoords[o][i] * norm.x); m.tangents[o1] = new Vector4(xCoords[o][i], 0, zCoords[o][i], -1.0f); int o2 = off + i + 2 * (subdivCount + 1); m.uv[o2] = new Vector2(uCoords[o][i] + 0.50f, v); m.verticies[o2] = new Vector3(-xCoords[o][i] * 0.5f * diameter, y, -zCoords[o][i] * 0.5f * diameter); m.normals[o2] = new Vector3(-xCoords[o][i] * norm.x, norm.y, -zCoords[o][i] * norm.x); m.tangents[o2] = new Vector4(-zCoords[o][i], 0, xCoords[o][i], -1.0f); int o3 = off + i + 3 * (subdivCount + 1); m.uv[o3] = new Vector2(uCoords[o][i] + 0.75f, v); m.verticies[o3] = new Vector3(zCoords[o][i] * 0.5f * diameter, y, -xCoords[o][i] * 0.5f * diameter); m.normals[o3] = new Vector3(zCoords[o][i] * norm.x, norm.y, -xCoords[o][i] * norm.x); m.tangents[o3] = new Vector4(-xCoords[o][i], 0, -zCoords[o][i], -1.0f); } // write the wrapping vertex. This is identical to the first one except for u coord += 1 int lp = off + totVertexes; m.uv[lp] = new Vector2(uCoords[o][0] + 1.0f, v); m.verticies[lp] = m.verticies[off]; m.normals[lp] = m.normals[off]; m.tangents[lp] = m.tangents[off]; }
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(); }
/// <summary> /// writes this.totVerticies + 1 xy, verticies, and tangents and this.totVerticies triangles to the passed arrays for a single endcap. /// Callers will need to fill the normals. This will be { 0, 1, 0 } for pt endcap, and { 0, -1, 0 } for bottom. /// </summary> /// <param name="dia">diameter of circle</param> /// <param name="y">y dimension for points</param> /// <param name="vOff">offset into xy, verticies, and normal arrays to begin at</param> /// <param name="xy">xy array, data will be written</param> /// <param name="verticies">verticies array</param> /// <param name="tangents">tangents array</param> /// <param name="to">offset into triangles array</param> /// <param name="triangles"></param> public void WriteEndcap(float dia, float y, bool up, int vOff, int to, UncheckedMesh m, bool odd) { Complete(); int o = odd ? 1 : 0; for (int i = 0; i <= subdivCount; ++i) { int o0 = vOff + i; m.uv[o0] = new Vector2((-xCoords[o][i] + 1f) * 0.5f, (-zCoords[o][i] + 1f) * 0.5f); m.verticies[o0] = new Vector3(xCoords[o][i] * dia * 0.5f, y, zCoords[o][i] * dia * 0.5f); int o1 = vOff + i + subdivCount + 1; m.uv[o1] = new Vector2((zCoords[o][i] + 1f) * 0.5f, (-xCoords[o][i] + 1f) * 0.5f); m.verticies[o1] = new Vector3(-zCoords[o][i] * dia * 0.5f, y, xCoords[o][i] * dia * 0.5f); int o2 = vOff + i + 2 * (subdivCount + 1); m.uv[o2] = new Vector2((xCoords[o][i] + 1f) * 0.5f, (zCoords[o][i] + 1f) * 0.5f); m.verticies[o2] = new Vector3(-xCoords[o][i] * dia * 0.5f, y, -zCoords[o][i] * dia * 0.5f); int o3 = vOff + i + 3 * (subdivCount + 1); m.uv[o3] = new Vector2((-zCoords[o][i] + 1f) * 0.5f, (xCoords[o][i] + 1f) * 0.5f); m.verticies[o3] = new Vector3(zCoords[o][i] * dia * 0.5f, y, -xCoords[o][i] * dia * 0.5f); m.tangents[o0] = m.tangents[o1] = m.tangents[o2] = m.tangents[o3] = new Vector4(-1, 0, 0, up ? 1 : -1); m.normals[o0] = m.normals[o1] = m.normals[o2] = m.normals[o3] = new Vector3(0, up ? 1 : -1, 0); } for (int i = 1; i < totVertexes - 1; ++i) { m.triangles[to++] = vOff; m.triangles[to++] = vOff + i + (up ? 1 : 0); m.triangles[to++] = vOff + i + (up ? 0 : 1); } }
private void SetCapVertexData(UncheckedMesh mesh, Vector3 cornerVector, int vertexIndex, bool up) { mesh.uv[vertexIndex] = new Vector2(cornerVector.x, cornerVector.z) / InnerDiameter / NormHorizontalDiameter + new Vector2(0.5f, 0.5f); mesh.normals[vertexIndex] = new Vector3(0, up ? 1 : -1, 0); mesh.tangents[vertexIndex] = new Vector4(1, 0, 0, 1f); }
/// <summary> /// Write vertexes for the circle. /// </summary> /// <param name="diameter">diameter of the circle</param> /// <param name="y">y coordinate</param> /// <param name="norm">unit normal vector along the generator curve for increasing y. The y param becomes the y of the normal, the x multiplies the normals to the circle</param> /// <param name="v">v coordinate for UV</param> /// <param name="off">offset into following arrays</param> /// <param name="odd">If this is an odd row</param> /// <param name="m">Mesh to write vertexes into</param> public void WriteVertexes(float diameter, float y, float v, Vector2 norm, int off, bool odd, UncheckedMesh m) { Complete(); int o = odd ? 1 : 0; for (int i = 0; i <= subdivCount; ++i) { int o0 = off + i; m.uv[o0] = new Vector2(uCoords[o][i], v); m.verticies[o0] = new Vector3(xCoords[o][i] * 0.5f * diameter, y, zCoords[o][i] * 0.5f * diameter); m.normals[o0] = new Vector3(xCoords[o][i] * norm.x, norm.y, zCoords[o][i] * norm.x); m.tangents[o0] = new Vector4(-zCoords[o][i], 0, xCoords[o][i], -1.0f); //MonoBehaviour.print("Vertex #" + i + " off=" + o0 + " u=" + xy[o0][0] + " coords=" + verticies[o0]); int o1 = off + i + subdivCount + 1; m.uv[o1] = new Vector2(uCoords[o][i] + 0.25f, v); m.verticies[o1] = new Vector3(-zCoords[o][i] * 0.5f * diameter, y, xCoords[o][i] * 0.5f * diameter); m.normals[o1] = new Vector3(-zCoords[o][i] * norm.x, norm.y, xCoords[o][i] * norm.x); m.tangents[o1] = new Vector4(-xCoords[o][i], 0, -zCoords[o][i], -1.0f); int o2 = off + i + 2 * (subdivCount + 1); m.uv[o2] = new Vector2(uCoords[o][i] + 0.50f, v); m.verticies[o2] = new Vector3(-xCoords[o][i] * 0.5f * diameter, y, -zCoords[o][i] * 0.5f * diameter); m.normals[o2] = new Vector3(-xCoords[o][i] * norm.x, norm.y, -zCoords[o][i] * norm.x); m.tangents[o2] = new Vector4(zCoords[o][i], 0, -xCoords[o][i], -1.0f); int o3 = off + i + 3 * (subdivCount + 1); m.uv[o3] = new Vector2(uCoords[o][i] + 0.75f, v); m.verticies[o3] = new Vector3(zCoords[o][i] * 0.5f * diameter, y, -xCoords[o][i] * 0.5f * diameter); m.normals[o3] = new Vector3(zCoords[o][i] * norm.x, norm.y, -xCoords[o][i] * norm.x); m.tangents[o3] = new Vector4(xCoords[o][i], 0, zCoords[o][i], -1.0f); } // write the wrapping vertex. This is identical to the first one except for u coord += 1 int lp = off + totVertexes; m.uv[lp] = new Vector2(uCoords[o][0] + 1.0f, v); m.verticies[lp] = m.verticies[off]; m.normals[lp] = m.normals[off]; m.tangents[lp] = m.tangents[off]; }
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(); } }
int ConnectRings(UncheckedMesh m, int ring1Offset, int ring2Offset, int vertCount, int triOffset, bool inverse = false) { int tri = triOffset; for (int i = 0; i < vertCount; ++i) { //Debug.Log(i); if (i < vertCount - 1) { m.triangles[tri++] = ring1Offset + i; m.triangles[tri++] = ring1Offset + i + 1; m.triangles[tri++] = ring2Offset + i + 1; m.triangles[tri++] = ring1Offset + i; m.triangles[tri++] = ring2Offset + i + 1; m.triangles[tri++] = ring2Offset + i; } else { //m.triangles[tri++] = ring1Offset + i; //m.triangles[tri++] = ring1Offset; //m.triangles[tri++] = ring2Offset; //m.triangles[tri++] = ring1Offset + i; //m.triangles[tri++] = ring2Offset; //m.triangles[tri++] = ring2Offset + i; } } return tri; }
private static void WriteToAppropriateMesh(UncheckedMesh mesh, Mesh iconMesh, Mesh normalMesh) { var target = (HighLogic.LoadedScene == GameScenes.LOADING) ? iconMesh : normalMesh; mesh.WriteTo(target); }
/// <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(); }