Esempio n. 1
0
	public void Impact(Vector3 impactPoint, Vector3 impactForce, Meshinator.ImpactShapes impactShape, Meshinator.ImpactTypes impactType)
	{
		// Look through all triangles to see which ones are within the impactForce from the impactPoint,
		// and measure the area of every triangle in the list
		Dictionary<int, float> triangleIndexToTriangleArea = new Dictionary<int, float>();
		foreach (int triangleIndex in GetIntersectedTriangleIndices(impactPoint, impactForce.magnitude))
		{
			float areaOfTriangle = GetAreaOfTriangle(triangleIndex);
			triangleIndexToTriangleArea.Add(triangleIndex, areaOfTriangle);
		}

		// Keep breaking down the largest triangle until there are more than c_MinTrianglesPerImpact
		// triangles in the list
		while (triangleIndexToTriangleArea.Keys.Count < c_MinTrianglesPerImpact)
		{
			// If we have 64988 vertices or more, we can't add any more or we risk going over the
			// 65000 limit, which causes problems for unity.
			if (m_Vertices.Count > 64988)
				break;
			
			// Get the index of the biggest triangle in our dictionary
			int indexOfLargestTriangle = GetIndexOfLargestTriangle(triangleIndexToTriangleArea);

			// Break that triangle down and remove it from the dictionary
			List<int> newTriangleIndices = BreakDownTriangle(indexOfLargestTriangle);
			triangleIndexToTriangleArea.Remove(indexOfLargestTriangle);
			
			// Measure the areas of the resulting triangles, and add them to the dictionary
			foreach (int triangleIndex in newTriangleIndices)
			{
				// Make sure each triangle is still intersected by our force before we add it back to the list
				if (IsTriangleIndexIntersected(triangleIndex, impactPoint, impactForce.magnitude))
				{
					float areaOfTriangle = GetAreaOfTriangle(triangleIndex);
					triangleIndexToTriangleArea.Add(triangleIndex, areaOfTriangle);
				}
			}
		}

		// Now that we have the proper vertices and triangles, actually go about deforming the mesh
		// by moving the vertices around.
		AdjustVerticesForImpact(impactPoint, impactForce, impactShape, impactType);
	}
    public void Impact(Vector3 point, Vector3 force, ImpactShapes impactShape, ImpactTypes impactType)
    {
        // See if we can do this right now
        if (!CanDoImpact(point, force))
        {
            return;
        }

        // We're now set on course to calculate the impact deformation
        m_Calculating = true;

        // Set up m_Hull
        InitializeHull();

        // Figure out the true impact force
        if (force.magnitude > m_MaxForcePerImpact)
        {
            force = force.normalized * m_MaxForcePerImpact;
        }
        float impactFactor = (force.magnitude - m_ForceResistance) * m_ForceMultiplier;

        if (impactFactor <= 0)
        {
            return;
        }

        // Localize the point and the force to account for transform scaling (and maybe rotation or translation)
        Vector3 impactPoint = transform.InverseTransformPoint(point);
        Vector3 impactForce = transform.InverseTransformDirection(force.normalized) * impactFactor;

        // Limit the force by the extents of the initial bounds to keep things reasonable
        float impactForceX = Mathf.Max(Mathf.Min(impactForce.x, m_InitialBounds.extents.x), -m_InitialBounds.extents.x);
        float impactForceY = Mathf.Max(Mathf.Min(impactForce.y, m_InitialBounds.extents.y), -m_InitialBounds.extents.y);
        float impactForceZ = Mathf.Max(Mathf.Min(impactForce.z, m_InitialBounds.extents.z), -m_InitialBounds.extents.z);

        impactForce = new Vector3(impactForceX, impactForceY, impactForceZ);

        // Run the mesh deformation on another thread
        ThreadManager.RunAsync(() =>
        {
            // Do all the math to deform this mesh
            m_Hull.Impact(impactPoint, impactForce, impactShape, impactType);

            // Queue the final mesh setting on the main thread once the deformations are done
            ThreadManager.QueueOnMainThread(() =>
            {
                // Clear out the current Mesh and MeshCollider (if we have one) for now
                MeshFilter meshFilter = gameObject.GetComponent <MeshFilter>();
                if (meshFilter != null)
                {
                    meshFilter.sharedMesh = null;
                }
                MeshCollider meshCollider = gameObject.GetComponent <MeshCollider>();
                if (meshCollider != null)
                {
                    meshCollider.sharedMesh = null;
                }

                // Get the newly-adjusted Mesh so we can work with it
                Mesh newMesh = m_Hull.GetMesh();

                // If this is a fracture, then create a new GameObject for the chunk that broke off
                if (impactType == ImpactTypes.Fracture)
                {
                    Mesh subHullMesh = m_Hull.GetSubHullMesh();
                    if (subHullMesh != null)
                    {
                        // Create the new GameObject
                        GameObject newGO = (GameObject)GameObject.Instantiate(gameObject);

                        // Set the new Mesh onto the MeshFilter and MeshCollider
                        MeshFilter newMeshFilter     = newGO.GetComponent <MeshFilter>();
                        MeshCollider newMeshCollider = newGO.GetComponent <MeshCollider>();
                        if (newMeshFilter != null)
                        {
                            newMeshFilter.sharedMesh = subHullMesh;
                        }
                        if (newMeshCollider != null)
                        {
                            newMeshCollider.sharedMesh = subHullMesh;
                        }

                        // If using convex MeshColliders, it's possible for colliders to overlap right after a
                        // fracture, which causes exponentially more fractures... So, right after a fracture,
                        // temporarily disable impacts to both the old GameObject, and the new one we just created
                        DelayCollisions();
                        Meshinator subHullMeshinator = newGO.GetComponent <Meshinator>();
                        if (subHullMeshinator != null)
                        {
                            subHullMeshinator.DelayCollisions();
                        }

                        // Figure out the approximate volume of our Hull and SubHull meshes. This
                        // will be used to calculate the rigidbody masses (if a rigidbodies are present)
                        // for the old and new GameObjects.
                        if (gameObject.GetComponent <Rigidbody>() != null && newGO.GetComponent <Rigidbody>() != null)
                        {
                            Vector3 hullSize = newMesh.bounds.size;
                            float hullVolume = hullSize.x * hullSize.y * hullSize.z;

                            Vector3 subHullSize = subHullMesh.bounds.size;
                            float subHullVolume = subHullSize.x * subHullSize.y * subHullSize.z;

                            float totalVolume = hullVolume + subHullVolume;
                            float totalMass   = gameObject.GetComponent <Rigidbody>().mass;

                            gameObject.GetComponent <Rigidbody>().mass = totalMass * (hullVolume / totalVolume);
                            newGO.GetComponent <Rigidbody>().mass      = totalMass * (subHullVolume / totalVolume);

                            // Set the old velocity onto the new GameObject's rigidbody
                            newGO.GetComponent <Rigidbody>().velocity = gameObject.GetComponent <Rigidbody>().velocity;

                            // Set the centers of mass to be within the new meshes
                            gameObject.GetComponent <Rigidbody>().centerOfMass = newMesh.bounds.center;
                            newGO.GetComponent <Rigidbody>().centerOfMass      = subHullMesh.bounds.center;
                        }
                    }
                }

                // Set the hull's new mesh back onto this game object
                if (meshFilter != null)
                {
                    meshFilter.sharedMesh = newMesh;
                }

                // If this GameObject has a MeshCollider, put the new mesh there too
                if (meshCollider != null)
                {
                    meshCollider.sharedMesh = newMesh;
                }

                // Drop our cached Hull if we're not supposed to keep it around
                if (m_CacheOption == CacheOptions.None)
                {
                    m_Hull = null;
                }

                // Our calculations are done
                m_Calculating = false;
            });
        });
    }
Esempio n. 3
0
	private void AdjustVerticesForImpact(Vector3 impactPoint, Vector3 impactForce,
		Meshinator.ImpactShapes impactShape, Meshinator.ImpactTypes impactType)
	{
		// Get the radius from the impactPoint that we'll be looking into
		float impactRadius = impactForce.magnitude;
		
		// Figure out how many vertices we will move
		Dictionary<int, float> movedVertexToForceMagnitudeMap = new Dictionary<int, float>();
		for (int i = 0; i < m_Vertices.Count; i++)
		{
			Vector3 vertex = m_Vertices[i];

			// Figure out the distance from the impact to this vector in different ways to
			// determine the shape of the impact
			Vector3 distanceVector = Vector3.zero;
			switch (impactShape)
			{
				case Meshinator.ImpactShapes.FlatImpact:
					distanceVector = Vector3.Project(vertex - impactPoint, impactForce.normalized);
					break;
					
				case Meshinator.ImpactShapes.SphericalImpact:
					distanceVector = vertex - impactPoint;
					break;
			}
			
			// If we're using a FlatImpact and the angle between the impact vector, and this vertex to the point
			// if impact is greater than 90 degrees, then make the distance the negative of itself. This fixes some
			// weird issues that pop up by the physics system determining that the point of collision is inside the
			// mesh instead of on the surface
			float distance = distanceVector.magnitude;
			if (impactShape == Meshinator.ImpactShapes.FlatImpact &&
				Vector3.Angle(vertex - impactPoint, impactForce) > 90f)
				distance = -distance;
			
			// If this vertex is within the impact radius, then we'll be moving this vertex.
			// Store the magnitude of the force by which this vertex will be moved
			float vertexForceMagnitude = Mathf.Max(0, (impactRadius - distance)) * c_CompressionResistance;
			if (distance < impactRadius && vertexForceMagnitude > 0)
				movedVertexToForceMagnitudeMap.Add(i, vertexForceMagnitude);
		}
		
		// Depending on our ImpactType, deform the mesh appropriately
		switch (impactType)
		{
			case Meshinator.ImpactTypes.Compression:
				CompressMeshVertices(movedVertexToForceMagnitudeMap, impactForce);
				break;
			
			case Meshinator.ImpactTypes.Fracture:
				FractureMeshVertices(movedVertexToForceMagnitudeMap, impactForce);
				break;
		}
	}