예제 #1
0
    IEnumerator DecreaseTerrain(float contactTime, float[,] heightMapPrimitive, int[,] heightMapPrimitiveBool, int x, int z)
    {
        // 1. Apply frame-per-frame deformation ("displacement")
        for (int zi = -gridSensorSize; zi <= gridSensorSize; zi++)
        {
            for (int xi = -gridSensorSize; xi <= gridSensorSize; xi++)
            {
                // Calculate each cell position wrt World and Heightmap - Left Foot
                Vector3 rayGridPrimitive      = new Vector3(x + xi, terrain.Get(x + xi, z + zi), z + zi);
                Vector3 rayGridWorldPrimitive = terrain.Grid2World(rayGridPrimitive);

                // Create each ray for the grid (wrt World) - Left
                RaycastHit primitiveHit;
                Ray        upRayPrimitive = new Ray(rayGridWorldPrimitive, Vector3.up);

                // If hits the Left Foot, increase counter and add cell to be affected
                if (PrimitiveCollider.Raycast(upRayPrimitive, out primitiveHit, rayPrimitiveDistanceUp))
                {
                    // Cell contacting directly
                    heightMapPrimitiveBool[zi + gridSensorSize, xi + gridSensorSize] = 2;
                    heightMapPrimitive[zi + gridSensorSize, xi + gridSensorSize]     = terrain.Get(rayGridPrimitive.x, rayGridPrimitive.z) - (displacement);
                }
                else
                {
                    // No contact
                    heightMapPrimitiveBool[zi + gridSensorSize, xi + gridSensorSize] = 0;
                    heightMapPrimitive[zi + gridSensorSize, xi + gridSensorSize]     = terrain.Get(rayGridPrimitive.x, rayGridPrimitive.z);
                }
            }
        }

        // 2. Pre-filter Gaussian filter
        if (applyPreFilterPrimitive)
        {
            heightMapPrimitive = FilterBufferPrimitive(heightMapPrimitive, heightMapPrimitiveBool);
        }

        // 3. Save terrain
        if (applyNewTerrainModification)
        {
            for (int zi = -gridSensorSize; zi <= gridSensorSize; zi++)
            {
                for (int xi = -gridSensorSize; xi <= gridSensorSize; xi++)
                {
                    Vector3 rayGridPrimitive = new Vector3(x + xi, terrain.Get(x + xi, z + zi), z + zi);
                    terrain.Set(rayGridPrimitive.x, rayGridPrimitive.z, heightMapPrimitive[zi + gridSensorSize, xi + gridSensorSize]);
                }
            }
        }

        yield return(null);
    }
예제 #2
0
 /// <summary>Adds or adjusts a primitive collider on the mesh.</summary>
 /// <remarks>
 /// Type of the primitive collider is chosen basing on the primitive type.
 /// </remarks>
 /// <param name="primitive">Primitive game object to adjust.</param>
 /// <param name="meshSize">Size of the collider in local units.</param>
 /// <param name="colliderType">Determines how a collider type should be selected.</param>
 /// <param name="shapeType">
 /// Type of the primitive when <paramref name="colliderType"/> is
 /// <see cref="PrimitiveCollider.Shape"/>. It will determine the type of the collider. Only
 /// <see cref="PrimitiveType.Cylinder"/>, <see cref="PrimitiveType.Sphere"/>, and
 /// <see cref="PrimitiveType.Cube"/> are supported.
 /// </param>
 public static void AdjustCollider(
     GameObject primitive, Vector3 meshSize, PrimitiveCollider colliderType,
     PrimitiveType?shapeType = null)
 {
     UnityEngine.Object.Destroy(primitive.GetComponent <Collider>());
     if (colliderType == PrimitiveCollider.Mesh)
     {
         var collider = primitive.AddComponent <MeshCollider>();
         collider.convex = true;
     }
     else if (colliderType == PrimitiveCollider.Shape)
     {
         // FIXME: non tirival scales does't fit simple colliders. Fix it.
         if (shapeType.Value == PrimitiveType.Cylinder)
         {
             // TODO(ihsoft): Choose direction so what the volume is minimized.
             var collider = primitive.AddComponent <CapsuleCollider>();
             collider.direction = 2;          // Z axis
             collider.height    = meshSize.z; // It's now length.
             collider.radius    = meshSize.x;
         }
         else if (shapeType.Value == PrimitiveType.Sphere)
         {
             var collider = primitive.AddComponent <SphereCollider>();
             collider.radius = meshSize.x;
         }
         else if (shapeType.Value == PrimitiveType.Cube)
         {
             var collider = primitive.AddComponent <BoxCollider>();
             collider.size = meshSize;
         }
         else
         {
             DebugEx.Warning("Unknown primitive type {0}. Droppping collider.", shapeType.Value);
         }
     }
     else if (colliderType == PrimitiveCollider.Bounds)
     {
         SetSimpleCollider(primitive, PrimitiveType.Cube, inscribeBoundaryIntoCollider: true);
     }
     else if (colliderType != PrimitiveCollider.None)
     {
         DebugEx.Warning(
             "Unsupported collider type {0}. Droppping whatever collider part had", colliderType);
     }
 }
예제 #3
0
        /// <summary>Adds or adjusts a primitive collider on the mesh.</summary>
        /// <remarks>
        /// Type of the primitive collider is chosen basing on the primitive type.
        /// </remarks>
        /// <param name="primitive">The primitive game object to adjust.</param>
        /// <param name="meshSize">
        /// The size of the collider in local units. Depending on <paramref name="shapeType"/> the meaning
        /// of the components is different. If the shape has a "round" component, then it's a "diameter"
        /// in this vector.
        /// </param>
        /// <param name="colliderType">Determines how a collider type should be selected.</param>
        /// <param name="shapeType">
        /// The type of the primitive when <paramref name="colliderType"/> is
        /// <see cref="PrimitiveCollider.Shape"/>. It will determine the type of the collider. Only
        /// <see cref="PrimitiveType.Cylinder"/>, <see cref="PrimitiveType.Sphere"/>, and
        /// <see cref="PrimitiveType.Cube"/> are supported.
        /// </param>
        /// <returns>The adjusted collider.</returns>
        /// FIXME: it's not working with asymmetric meshes
        /// FIXME: use GameObject.GetRendererBounds?
        public static Collider AdjustCollider(
            GameObject primitive, Vector3 meshSize, PrimitiveCollider colliderType,
            PrimitiveType?shapeType = null)
        {
            if (colliderType == PrimitiveCollider.None)
            {
                SafeDestroy(GetActiveCollider <Collider>(primitive));
                return(null);
            }
            if (colliderType == PrimitiveCollider.Mesh)
            {
                var collider = GetColliderOfType <MeshCollider>(primitive);
                collider.convex = true;
                return(collider);
            }
            if (colliderType == PrimitiveCollider.Shape)
            {
                switch (shapeType)
                {
                // FIXME: non trivial scales doesn't fit simple colliders. Fix it.
                case null:
                    SafeDestroy(GetActiveCollider <Collider>(primitive));
                    DebugEx.Warning("Primitive type not set. Dropping collider.");
                    return(null);

                case PrimitiveType.Cylinder: {
                    // TODO(ihsoft): Choose direction so what the volume is minimized.
                    var collider = GetColliderOfType <CapsuleCollider>(primitive);
                    collider.direction = 2;          // Z axis
                    collider.height    = meshSize.z; // It's now length.
                    collider.radius    = meshSize.x / 2.0f;
                    return(collider);
                }

                case PrimitiveType.Sphere: {
                    var collider = GetColliderOfType <SphereCollider>(primitive);
                    collider.radius = meshSize.x / 2.0f;
                    return(collider);
                }

                case PrimitiveType.Cube: {
                    var collider = GetColliderOfType <BoxCollider>(primitive);
                    collider.size = meshSize;
                    return(collider);
                }

                default:
                    SafeDestroy(GetActiveCollider <Collider>(primitive));
                    DebugEx.Warning("Unknown primitive type {0}. Dropping collider.", shapeType.Value);
                    return(null);
                }
            }
            if (colliderType == PrimitiveCollider.Bounds)
            {
                return(SetSimpleCollider(primitive, PrimitiveType.Cube, inscribeBoundaryIntoCollider: true));
            }
            SafeDestroy(GetActiveCollider <Collider>(primitive));
            DebugEx.Warning(
                "Unsupported collider type {0}. Dropping whatever collider part had", colliderType);
            return(null);
        }
예제 #4
0
    /// <summary>
    /// Method that takes the IK positions for each feet and apply displacement to ground.
    /// </summary>
    /// <param name="xLeft"></param>
    /// <param name="zLeft"></param>
    /// <param name="xRight"></param>
    /// <param name="zRight"></param>
    public override void DrawFootprint(int x, int z)
    {
        //=============//

        // Reset counter hits
        counterHitsPrimitive = 0;

        // Clear cells to be affected
        //cellsAffected.Clear();

        // Primitive
        float[,] heightMapPrimitive   = new float[2 * gridSensorSize + 1, 2 * gridSensorSize + 1];
        int[,] heightMapPrimitiveBool = new int[2 * gridSensorSize + 1, 2 * gridSensorSize + 1];

        // Warning: Supossing that terrain is squared!
        if (printTerrainInformation)
        {
            Debug.Log("[INFO] Length Terrain - X: " + terrain.TerrainSize().x);
            Debug.Log("[INFO] Length Terrain - Z: " + terrain.TerrainSize().z);
            Debug.Log("[INFO] Number of heightmap cells: " + (terrain.GridSize().x - 1));
            Debug.Log("[INFO] Lenght of one cell - X: " + (terrain.TerrainSize().x / (terrain.GridSize().x - 1)));
            Debug.Log("[INFO] Lenght of one cell - Z: " + (terrain.TerrainSize().z / (terrain.GridSize().z - 1)));
            Debug.Log("[INFO] Area of one cell: " + (terrain.TerrainSize().x / (terrain.GridSize().x - 1)) * (terrain.TerrainSize().z / (terrain.GridSize().z - 1)));
        }

        // Calculate area per cell outside the loop
        lenghtCellX = terrain.TerrainSize().x / (terrain.GridSize().x - 1);
        lenghtCellZ = terrain.TerrainSize().z / (terrain.GridSize().z - 1);
        areaCell    = lenghtCellX * lenghtCellZ;

        //=============//

        // 2D iteration for primitive
        // It counts the number of hits, save the classified cell in a list and debug ray-casting
        for (int zi = -gridSensorSize; zi <= gridSensorSize; zi++)
        {
            for (int xi = -gridSensorSize; xi <= gridSensorSize; xi++)
            {
                // Calculate each cell position wrt World and Heightmap - Primitive
                Vector3 rayGridPrimitive      = new Vector3(x + xi, terrain.Get(x + xi, z + zi) - offset, z + zi);
                Vector3 rayGridWorldPrimitive = terrain.Grid2World(rayGridPrimitive);

                // Create each ray for the grid (wrt World) - Primitive
                RaycastHit primitiveHit;
                Ray        upRayPrimitive = new Ray(rayGridWorldPrimitive, Vector3.up);

                // If hits the Left Foot, increase counter and add cell to be affected
                if (PrimitiveCollider.Raycast(upRayPrimitive, out primitiveHit, rayPrimitiveDistanceUp))
                {
                    counterHitsPrimitive++;

                    if (showGridDebug)
                    {
                        Debug.DrawRay(rayGridWorldPrimitive, Vector3.up * rayPrimitiveDistanceUp, Color.blue);
                    }
                }
                else
                {
                    //cellsNotAffected.Add(rayGridLeft);

                    if (showGridDebug)
                    {
                        Debug.DrawRay(rayGridWorldPrimitive, Vector3.up * rayPrimitiveDistanceUp, Color.red);
                    }
                }
            }
        }

        //=============//

        // 1. TotalForce gives the total force applicable (gravity + reaction impulse)
        //Debug.Log("Total Force now: " + TotalForce);

        // 2. Total Contact Area in Frame.
        // TODO: Keep always larger area - (?)
        oldAreaTotal = ((counterHitsPrimitive) * areaCell);
        if (oldAreaTotal >= areaTotal)
        {
            areaTotal = ((counterHitsPrimitive) * areaCell);
        }

        // 3. Calculate Pressure applicable per Frame - no contact, no pressure.
        if (counterHitsPrimitive == 0)
        {
            pressure = 0f;
        }
        else
        {
            pressure = (TotalForce) / areaTotal;
        }

        // Plot
        //pressurePlot = pressure;

        //=============//

        // 4. Given those cells, and pressure, which should be the decrement in the terrain?
        // The decrement will depend entirely on the pressure and time.

        // A. Test - Interpolated Value
        //float normalizedValuePressure = Mathf.InverseLerp(0, 2000, pressure);
        //heightCellDisplacement = Mathf.Lerp(0f, 0.1f, normalizedValuePressure);

        // B. Test - Constant Value
        //heightCellDisplacement = 0.015f;

        // C. Young Modulus to calculate maximum displacement for a equivalent rod of cross-section "areaTotal" and length "originalLength"
        // We keep the maximum displacement caused - (?)
        oldHeightCellDisplacementYoung = pressure * (originalLength / (youngModulus));
        if (oldHeightCellDisplacementYoung >= heightCellDisplacementYoung)
        {
            heightCellDisplacementYoung = pressure * (originalLength / youngModulus);
        }

        // Then, if the previous displacement is the total deformation, we need to calculate the small step
        // that we do per frame until we reach the given "ContactTime".
        displacement = (Time.deltaTime * (float)heightCellDisplacementYoung) / ContactTime;
        //Debug.Log("For the pressure " + pressure + " we have a displacement/cell of " + displacement);

        // Plot
        //displacementPlot = (float)heightCellDisplacementYoung;

        //=============//

        //if (printFootprintsInformation)
        //{
        //    Debug.Log("[INFO] Counter Hits Left: " + counterHitsLeft);
        //    Debug.Log("[INFO] Counter Hits Right: " + counterHitsRight);
        //    Debug.Log("[INFO] Total Contact Area: " + areaTotal);
        //    Debug.Log("[INFO] Current Force: " + Force);
        //    Debug.Log("[INFO] Pressure/Cell NOW: " + pressure);
        //    Debug.Log("[INFO] Min Pressure: " + minPressure);
        //    Debug.Log("[INFO] Max Pressure: " + maxPressure);
        //}

        //if (printDeformationInformation)
        //{
        //    Debug.Log("normalizedValuePressure: " + normalizedValuePressure);
        //    Debug.Log("heightCellDisplacement: " + heightCellDisplacement);
        //}

        //=============//

        // 2D iteration Deformation
        // Once we have the displacement based on the weight, we saved the actual result of applying it to the terrain
        if (counterHitsPrimitive != 0)
        {
            // Once we touch the ground, clock starts. It will deform the terrain during delta_t.
            // TODO: We need to reset times for the steps example later on.
            timePassed += Time.deltaTime;
            if (timePassed <= ContactTime)
            {
                StartCoroutine(DecreaseTerrain(ContactTime, heightMapPrimitive, heightMapPrimitiveBool, x, z));
            }
        }
    }