private static void ParseFromFile(ResourceFile file, UnsafeBufferWriter <Vertex> verticesBuffer, UnsafeBufferWriter <int> indicesBuffer) { using var stream = file.GetStream(); using var obj = ObjParser.ParseUnsafe(stream); var hasUV = !obj.UVIndices.IsEmpty; using var uvIndicesBuf = hasUV ? UnsafeRawArray <int> .Empty : new UnsafeRawArray <int>(obj.PositionIndices.Length, true); var uvs = hasUV ? obj.UVs : stackalloc Vector2[1] { Vector2.Zero }; var uvIndices = hasUV ? obj.UVIndices : uvIndicesBuf.AsSpan(); var hasNormal = !obj.NormalIndices.IsEmpty; if (hasNormal == false) { using var normalsBuf = new UnsafeBufferWriter <Vector3>(); var positions = obj.Positions; var posNormalIndices = obj.PositionIndices; var normals = MeshOperations.RecalculateNormal(positions, posNormalIndices, normalsBuf); MeshOperations.CreateInterleavedVertices(positions, posNormalIndices, normals, posNormalIndices, uvs, uvIndices, verticesBuffer, indicesBuffer); } else { MeshOperations.CreateInterleavedVertices(obj.Positions, obj.PositionIndices, obj.Normals, obj.NormalIndices, uvs, uvIndices, verticesBuffer, indicesBuffer); } }
public void UpdateGrainProperties() { Mesh mesh = gameObject.GetComponent <MeshFilter>().mesh; grainVolume = MeshOperations.VolumeOfMesh(mesh, scale); //grainSurfaceArea = MeshOperations.GetMeshSurfaceArea(mesh, scale); grainMass = grainDensity * grainVolume; gameObject.GetComponent <Rigidbody>().mass = grainMass; //Debug.Log("Mass " + grainMass); //Debug.Log("Volume " + grainVolume); //Debug.Log("Density " + grainDensity); //Debug.Log("SA " + grainSurfaceArea); }
//=================================================================== public float GetBestMultiplier(Mesh mesh, float volumeGoal, ResizeType resizeType) { MinMaxFloat minMaxRadius; float initialDiameter = Mathf.Pow(3f / 4f / Mathf.PI * volumeGoal, 1f / 3f) * 2; //Debug.Log("initial Diameter" + initialDiameter); switch (resizeType) { // ================================ case ResizeType.ByVolume: float minMultiplier = .001f; float maxMultiplier = 5f; float middleDiff = 1f; float middleMultiplier = 0; while (middleDiff > .001) { middleMultiplier = (minMultiplier + maxMultiplier) / 2; float middleVolume = MeshOperations.VolumeOfMesh(mesh, middleMultiplier); middleDiff = Mathf.Abs(middleVolume - volumeGoal) / volumeGoal; if (middleVolume >= volumeGoal) { maxMultiplier = middleMultiplier; } if (middleVolume < volumeGoal) { minMultiplier = middleMultiplier; } } return(middleMultiplier); // ================================ case ResizeType.ByRadiusIn: minMaxRadius = GetMinMaxRadius(mesh); return(initialDiameter / (minMaxRadius.max * 2)); // ================================ case ResizeType.ByRadiusOut: minMaxRadius = GetMinMaxRadius(mesh); return(initialDiameter / (minMaxRadius.min * 2)); } return(1f); }
//Amplitude = .05, Frequency = 1, Lacunarity = 2, OctaveCount = 6, Persistence = .5, ResizeType = ByVolume #endregion // Use this for initialization void Start() { // Create Perlin Noise PerlinNoiseOptions perlinOptions = GetPerlinNoiseOptions(amplitudeRange, frequencyRange, lacunarityRange, octaveCountRange, persistenceRange, seed); //Debug.Log(perlinOptions.amplitude); //Debug.Log(perlinOptions.frequency); //Debug.Log(perlinOptions.lacunarity); //Debug.Log(perlinOptions.octaveCount); //Debug.Log(perlinOptions.persistence); //Debug.Log(perlinOptions.seed); if (useRandomSeed == true) { perlinOptions.seed = Mathf.RoundToInt(Random.value * 1000000); } Perlin noise = new Perlin(perlinOptions.frequency, perlinOptions.lacunarity, perlinOptions.persistence, perlinOptions.octaveCount, seed, perlinOptions.quality); Mesh mesh = GetComponent <MeshFilter>().mesh; Vector3[] baseVertices = mesh.vertices; Vector3[] vertices = new Vector3[baseVertices.Length]; // get initial Mass and Volume float initialVolume = MeshOperations.VolumeOfMesh(mesh, 1); float initialMass = gameObject.GetComponent <Rigidbody>().mass; var verticesCH = new Vertex[baseVertices.Length]; // Apply Perlin Noise for (int i = 0; i < vertices.Length; i++) { var vertex = baseVertices[i] * 2; float noiseValue = (float)noise.GetValue(vertex.x, vertex.y, vertex.z); vertex += vertex * noiseValue * perlinOptions.amplitude; vertices[i] = vertex; verticesCH[i] = new Vertex((double)vertex.x, (double)vertex.y, (double)vertex.z); } // Convex Hull mesh = CreateConvexMesh(vertices); Vector3[] vertices2 = mesh.vertices; // Scale Mesh to Equal Sphere Volume float scaleMultiplier = GetBestMultiplier(mesh, initialVolume, resizeType); for (int i = 0; i < vertices2.Length; i++) { var vertex = vertices2[i]; vertex *= scaleMultiplier; vertices2[i] = vertex; } // Finalize Mesh mesh.vertices = vertices2; mesh.RecalculateNormals(); mesh.RecalculateBounds(); // Update Meshes GetComponent <MeshFilter>().mesh = null; GetComponent <MeshFilter>().mesh = mesh; GetComponent <MeshCollider>().sharedMesh = null; GetComponent <MeshCollider>().sharedMesh = mesh; // Update Mass gameObject.GetComponent <Rigidbody>().ResetCenterOfMass(); UpdateGrainProperties(); }
//From triangle where each triangle has one vertex to half edge public static List <HalfEdge> TransformFromTriangleToHalfEdge(List <Triangle> triangles) { //Make sure the triangles have the same orientation MeshOperations.OrientTrianglesClockwise(triangles); //First create a list with all possible half-edges List <HalfEdge> halfEdges = new List <HalfEdge>(triangles.Count * 3); for (int i = 0; i < triangles.Count; i++) { Triangle t = triangles[i]; HalfEdge he1 = new HalfEdge(t.v1); HalfEdge he2 = new HalfEdge(t.v2); HalfEdge he3 = new HalfEdge(t.v3); he1.nextEdge = he2; he2.nextEdge = he3; he3.nextEdge = he1; he1.prevEdge = he3; he2.prevEdge = he1; he3.prevEdge = he2; //The vertex needs to know of an edge going from it he1.v.halfEdge = he2; he2.v.halfEdge = he3; he3.v.halfEdge = he1; //The face the half-edge is connected to t.halfEdge = he1; he1.t = t; he2.t = t; he3.t = t; //Add the half-edges to the list halfEdges.Add(he1); halfEdges.Add(he2); halfEdges.Add(he3); } //Find the half-edges going in the opposite direction for (int i = 0; i < halfEdges.Count; i++) { HalfEdge he = halfEdges[i]; Vertex goingToVertex = he.v; Vertex goingFromVertex = he.prevEdge.v; for (int j = 0; j < halfEdges.Count; j++) { //Dont compare with itself if (i == j) { continue; } HalfEdge heOpposite = halfEdges[j]; //Is this edge going between the vertices in the opposite direction if (goingFromVertex.position == heOpposite.v.position && goingToVertex.position == heOpposite.prevEdge.v.position) { he.oppositeEdge = heOpposite; break; } } } return(halfEdges); }
private ProjectedGeometry MeshToProjectedGeometry(MeshGeometry3D mesh, Transform3D tx) { MeshOperations.RemoveNullFields(mesh); if (mesh.TriangleIndices.Count == 0) { // Having triangle indices in a mesh isn't required // Generate them if they don't exist MeshOperations.GenerateTriangleIndices(mesh); } else { // If we didn't generate them, there could be bad indices in there. // Remove the triangles that would cause our renderer problems in the future. MeshOperations.RemoveBogusTriangles(mesh); } // Having texture coordinates in a mesh isn't required // Generate them if they don't exist if (mesh.TextureCoordinates.Count == 0) { MeshOperations.GenerateTextureCoordinates(mesh); } // We need explicit normal information, so calculate them when they're missing if (mesh.Normals.Count != mesh.Positions.Count) { // We default to counter-clockwise winding order ... MeshOperations.GenerateNormals(mesh, false); } Point3DCollection positions = mesh.Positions; Vector3DCollection normals = mesh.Normals; PointCollection textureCoordinates = mesh.TextureCoordinates; Int32Collection triangleIndices = mesh.TriangleIndices; // We think of the following coordinate systems: // Model space: Coordinates which are model-local // World space: Coordinates which relate all the models // Eye space: Coordinates where the eye point is (0,0,0) and is looking down -Z // Homogeneous space: Projected to a canonical rectangular solid view volume. (-1, -1, 0) -> (1, 1, 1) // Screen space: Scaled homogeneous space so that X,Y correspond to X,Y pixel values on the screen. Matrix3D modelToWorld = tx.Value; Matrix3D worldToEye = MatrixUtils.ViewMatrix(camera); Matrix3D modelToEyeMatrix = modelToWorld * worldToEye; Matrix3D normalTransform = MatrixUtils.MakeNormalTransform(modelToEyeMatrix); Matrix3D projectionMatrix = MatrixUtils.ProjectionMatrix(camera); Matrix3D toScreenSpace = MatrixUtils.HomogenousToScreenMatrix(bounds.ViewportBounds, camera is ProjectionCamera); Matrix3D projectToViewport = projectionMatrix * toScreenSpace; bool reverseWinding = MatrixUtils.Determinant(modelToEyeMatrix) < 0; MeshProjectedGeometry pg = new MeshProjectedGeometry(projectToViewport); int numTriangles = triangleIndices.Count / 3; Vertex v1, v2, v3; int index; for (int n = 0; n < numTriangles; n++) { v1 = new Vertex(); v2 = new Vertex(); v3 = new Vertex(); // We default material colors to pure White (0xff,0xff,0xff) since // we will iluminate against that and then modulate with // the actual textures on a per-pixel level. v1.Color = Colors.White; v2.Color = Colors.White; v3.Color = Colors.White; index = triangleIndices[n * 3]; v1.ModelSpacePosition = positions[index]; v1.ModelSpaceNormal = normals[index]; v1.Position = MatrixUtils.Transform((Point4D)positions[index], modelToEyeMatrix); v1.Normal = MatrixUtils.Transform(normals[index], normalTransform); v1.TextureCoordinates = textureCoordinates[index]; index = triangleIndices[n * 3 + 1]; v2.ModelSpacePosition = positions[index]; v2.ModelSpaceNormal = normals[index]; v2.Position = MatrixUtils.Transform((Point4D)positions[index], modelToEyeMatrix); v2.Normal = MatrixUtils.Transform(normals[index], normalTransform); v2.TextureCoordinates = textureCoordinates[index]; index = triangleIndices[n * 3 + 2]; v3.ModelSpacePosition = positions[index]; v3.ModelSpaceNormal = normals[index]; v3.Position = MatrixUtils.Transform((Point4D)positions[index], modelToEyeMatrix); v3.Normal = MatrixUtils.Transform(normals[index], normalTransform); v3.TextureCoordinates = textureCoordinates[index]; if (reverseWinding) { // Change winding-order so the mesh renders pg.AddTriangle(v1, v3, v2); } else { pg.AddTriangle(v1, v2, v3); } } pg.NormalizeTextureCoordinates(); return(pg); }