Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  Cloth to simulate slime
#18
(12-09-2018, 02:26 PM)josemendez Wrote: Use Input.GetTouch() instead, passing the index of the touch:

https://unity3d.com/es/learn/tutorials/t...ouch-input

So if I use GetTouch, the dragging works, but it's glitchy. Also, let's say I have a touch count of two (two fingers on screen). On touching with both fingers, the slime actually gets pressed in the center of the distance between the two finger's positions. It's as if the code is averaging out the pressed point's location between all finger locations - resulting in only one "press" on screen. I know I'm going off topic, but I'm lost with multitouch right now.

Also, the touch itself is very glitchy. The "pressed" part constantly seems to vibrate while being dragged as shown in this video.

My guess is the script is getting confused between which particle to select according to ScreenToCamera point, amongst adjacent and close particles. I tried increasing the number of particles by setting up the SheetVHD mesh instead as a cloth, which has many more particles once initialized, but the vibration-on-touch effect is still visible.

These are my changes to the two scripts so far -

ObiClothPicker.cs -

Code:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace Obi {

   public class ObiClothPicker : MonoBehaviour {

       public class ParticlePickEventArgs : EventArgs {

           public int particleIndex;
           public Vector3 worldPosition;

           public ParticlePickEventArgs(int particleIndex, Vector3 worldPosition) {
               this.particleIndex = particleIndex;
               this.worldPosition = worldPosition;
           }
       }

       public event System.EventHandler<ParticlePickEventArgs> OnParticlePicked;
       public event System.EventHandler<ParticlePickEventArgs> OnParticleHeld;
       public event System.EventHandler<ParticlePickEventArgs> OnParticleDragged;
       public event System.EventHandler<ParticlePickEventArgs> OnParticleReleased;

       private MeshCollider meshCollider;
       private ObiClothBase cloth;
       private Mesh currentCollisionMesh;

       private Vector3 lastMousePos = Vector3.zero;
       private int pickedParticleIndex = -1;
       private float pickedParticleDepth = 0;

       public ObiClothBase Cloth {
           get { return cloth; }
       }

       void Awake() {
           cloth = GetComponent<ObiClothBase>();
           lastMousePos = Input.mousePosition;
       }

       void OnEnable() {

           // special case for skinned cloth, the collider must be added to the skeleton's root bone:
           if (cloth is ObiCloth && ((ObiCloth)cloth).IsSkinned) {

               SkinnedMeshRenderer sk = cloth.GetComponent<SkinnedMeshRenderer>();
               if (sk != null && sk.rootBone != null) {
                   meshCollider = sk.rootBone.gameObject.AddComponent<MeshCollider>();
               }
           }
           // regular cloth:
           else {
               meshCollider = gameObject.AddComponent<MeshCollider>();
           }

           // in case we were able to create the mesh collider, set it up:
           if (meshCollider != null) {
               meshCollider.enabled = false;
               meshCollider.hideFlags = HideFlags.HideAndDontSave;
           }

           if (cloth != null)
               cloth.Solver.OnFrameBegin += Cloth_Solver_OnFrameBegin;
       }

       void OnDisable() {

           // destroy the managed mesh collider:
           GameObject.Destroy(meshCollider);

           if (cloth != null)
               cloth.Solver.OnFrameBegin -= Cloth_Solver_OnFrameBegin;
       }

       void Cloth_Solver_OnFrameBegin(object sender, EventArgs e)
       {
           if (meshCollider == null)
               return;

           // Click:
#if UNITY_ANDROID
           Touch myTouch = Input.GetTouch(0);

           Touch[] myTouches = Input.touches;
           for (int i = 0; i < Input.touchCount; i++)
           {
               meshCollider.enabled = true;

               GameObject.Destroy(currentCollisionMesh);
               currentCollisionMesh = GameObject.Instantiate(cloth.clothMesh);
               meshCollider.sharedMesh = currentCollisionMesh;

               Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

               RaycastHit hitInfo;
               if (meshCollider.Raycast(ray, out hitInfo, 100))
               {

                   int[] tris = currentCollisionMesh.triangles;
                   Vector3[] vertices = currentCollisionMesh.vertices;

                   // find closest vertex in the triangle we just hit:
                   int closestVertex = -1;
                   float minDistance = float.MaxValue;

                   for (int j = 0; j < 3; ++j)
                   {
                       int vertex = tris[hitInfo.triangleIndex * 3 + j];
                       float distance = (vertices[vertex] - hitInfo.point).sqrMagnitude;
                       if (distance < minDistance)
                       {
                           minDistance = distance;
                           closestVertex = vertex;
                       }
                   }

                   // get particle index:
                   if (closestVertex >= 0 && closestVertex < cloth.topology.visualMap.Length)
                   {

                       pickedParticleIndex = cloth.topology.visualMap[closestVertex];
                       pickedParticleDepth = Mathf.Abs((cloth.transform.TransformPoint(vertices[closestVertex]) - Camera.main.transform.position).z);

                       if (OnParticlePicked != null)
                       {
                           Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
                           OnParticlePicked(this, new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
                       }
                   }
               }

               meshCollider.enabled = false;
           }

           if (Input.touchCount < 1)
           {
               if (OnParticleReleased != null)
               {
                   Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
                   OnParticleReleased(this, new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
               }

               pickedParticleIndex = -1;
           }
#endif

#if UNITY_EDITOR
           if (Input.GetMouseButton(0))
           {
               meshCollider.enabled = true;

               GameObject.Destroy(currentCollisionMesh);
               currentCollisionMesh = GameObject.Instantiate(cloth.clothMesh);
               meshCollider.sharedMesh = currentCollisionMesh;

               Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

               RaycastHit hitInfo;
               if (meshCollider.Raycast(ray, out hitInfo, 100))
               {

                   int[] tris = currentCollisionMesh.triangles;
                   Vector3[] vertices = currentCollisionMesh.vertices;

                   // find closest vertex in the triangle we just hit:
                   int closestVertex = -1;
                   float minDistance = float.MaxValue;

                   for (int j = 0; j < 3; ++j)
                   {
                       int vertex = tris[hitInfo.triangleIndex * 3 + j];
                       float distance = (vertices[vertex] - hitInfo.point).sqrMagnitude;
                       if (distance < minDistance)
                       {
                           minDistance = distance;
                           closestVertex = vertex;
                       }
                   }

                   // get particle index:
                   if (closestVertex >= 0 && closestVertex < cloth.topology.visualMap.Length)
                   {

                       pickedParticleIndex = cloth.topology.visualMap[closestVertex];
                       pickedParticleDepth = Mathf.Abs((cloth.transform.TransformPoint(vertices[closestVertex]) - Camera.main.transform.position).z);

                       if (OnParticlePicked != null)
                       {
                           Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
                           OnParticlePicked(this, new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
                       }
                   }
               }

               meshCollider.enabled = false;
           }

           else if (pickedParticleIndex >= 0) {

               // Drag:
               /*Vector3 mouseDelta = Input.mousePosition - lastMousePos;
                if (mouseDelta.magnitude > 0.01f && OnParticleDragged != null){

                    Vector3 worldPosition = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));                    
                   OnParticleDragged(this,new ParticlePickEventArgs(pickedParticleIndex,worldPosition));

                }else if (OnParticleHeld != null){

                    Vector3 worldPosition = Camera.main.ScreenToWorldPoint (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
                    OnParticleHeld(this,new ParticlePickEventArgs(pickedParticleIndex,worldPosition));

                }*/

               // Release:                
               if (Input.GetMouseButtonUp(0)) {

                   if (OnParticleReleased != null) {
                       Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, pickedParticleDepth));
                       OnParticleReleased(this, new ParticlePickEventArgs(pickedParticleIndex, worldPosition));
                   }

                   pickedParticleIndex = -1;
               }
           }

           lastMousePos = Input.mousePosition;
#endif
           
       }
   }
}

ObiClothDragger.cs -

Code:
using System;
using UnityEngine;

namespace Obi
{
    [RequireComponent(typeof(ObiClothPicker))]
    public class ObiClothDragger : MonoBehaviour
    {
        public float springStiffness = 50;
        public float springDamping = 1;

        private ObiClothPicker picker;
        private ObiClothPicker.ParticlePickEventArgs pickArgs;

        void OnEnable()
        {
            picker = GetComponent<ObiClothPicker>();
            picker.OnParticlePicked += Picker_OnParticleDragged;
            picker.OnParticleDragged += Picker_OnParticleDragged;
            picker.OnParticleReleased += Picker_OnParticleReleased;
        }

        void OnDisable()
        {
            picker.OnParticlePicked -= Picker_OnParticleDragged;
            picker.OnParticleDragged -= Picker_OnParticleDragged;
            picker.OnParticleReleased -= Picker_OnParticleReleased;
        }

        void FixedUpdate ()
        {
            if (pickArgs != null){
                
                ObiSolver solver = picker.Cloth.Solver;

                // Calculate picking position in solver space:
                Vector3 targetPosition = pickArgs.worldPosition;    
                if (solver.simulateInLocalSpace)
                    targetPosition = solver.transform.InverseTransformPoint(targetPosition);
    
                // Get particle position and velocity:
                Vector4[] positions = new Vector4[1];
                Vector4[] velocities = new Vector4[1];
                int solverIndex = picker.Cloth.particleIndices[pickArgs.particleIndex];
                Oni.GetParticlePositions(solver.OniSolver,positions,1,solverIndex);
                Oni.GetParticleVelocities(solver.OniSolver,velocities,1,solverIndex);

                // Calculate effective inverse mass:
                float invMass = picker.Cloth.invMasses[pickArgs.particleIndex] * picker.Cloth.areaContribution[pickArgs.particleIndex];

                if (invMass > 0){
                    // Calculate and apply spring force:
                   
                    Vector4 force = ((new Vector4(targetPosition[0],-targetPosition[1],targetPosition[2],0) - positions[0]) * springStiffness - velocities[0] * springDamping) / (invMass);                    
                    Oni.AddParticleExternalForce(picker.Cloth.Solver.OniSolver,ref force,new int[]{solverIndex},1);
                }
                
            }
        }

        void Picker_OnParticleDragged (object sender, ObiClothPicker.ParticlePickEventArgs e)
        {
            pickArgs = e;
        }

        void Picker_OnParticleReleased (object sender, ObiClothPicker.ParticlePickEventArgs e)
        {
            pickArgs = null;
        }

    }
}

Lastly, in ObiClothDragger.cs, in fixed update, while calculating and applying spring force, I tried changing the line -
Code:
Vector4 force = ((new Vector4(targetPosition[0],-targetPosition[1],targetPosition[2],0) - positions[0]) * springStiffness - velocities[0] * springDamping) / (invMass);

to this...

Code:
Vector4 force = ((new Vector4(targetPosition[0],-targetPosition[1]-10,targetPosition[2],0) - positions[0]) * springStiffness - velocities[0] * springDamping) / (invMass);

..so that I could provide an increased depth effect at the point of touch (instead of using a splat map, to get required "pressed" visual effect). But it makes the whole cloth glitch out and disappear instantly. How do I increase the depth of the "press"? For now I was assuming "targetPosition[1]" is the Y-Position of the press.
Reply


Messages In This Thread
Cloth to simulate slime - by arrnav96 - 09-09-2018, 06:06 AM
RE: Cloth to simulate slime - by josemendez - 09-09-2018, 11:32 AM
RE: Cloth to simulate slime - by arrnav96 - 10-09-2018, 11:17 AM
RE: Cloth to simulate slime - by josemendez - 10-09-2018, 11:41 AM
RE: Cloth to simulate slime - by arrnav96 - 10-09-2018, 11:55 AM
RE: Cloth to simulate slime - by josemendez - 10-09-2018, 01:45 PM
RE: Cloth to simulate slime - by arrnav96 - 10-09-2018, 03:47 PM
RE: Cloth to simulate slime - by josemendez - 10-09-2018, 03:56 PM
RE: Cloth to simulate slime - by arrnav96 - 10-09-2018, 04:03 PM
RE: Cloth to simulate slime - by josemendez - 10-09-2018, 04:05 PM
RE: Cloth to simulate slime - by josemendez - 10-09-2018, 04:27 PM
RE: Cloth to simulate slime - by arrnav96 - 11-09-2018, 09:25 AM
RE: Cloth to simulate slime - by josemendez - 11-09-2018, 10:32 AM
RE: Cloth to simulate slime - by arrnav96 - 11-09-2018, 10:25 PM
RE: Cloth to simulate slime - by josemendez - 12-09-2018, 08:09 AM
RE: Cloth to simulate slime - by arrnav96 - 12-09-2018, 01:01 PM
RE: Cloth to simulate slime - by josemendez - 12-09-2018, 02:26 PM
RE: Cloth to simulate slime - by arrnav96 - 12-09-2018, 03:44 PM
RE: Cloth to simulate slime - by josemendez - 12-09-2018, 04:45 PM
RE: Cloth to simulate slime - by arrnav96 - 19-09-2018, 10:29 PM
RE: Cloth to simulate slime - by josemendez - 22-09-2018, 02:17 PM
RE: Cloth to simulate slime - by arrnav96 - 30-09-2018, 03:35 PM
RE: Cloth to simulate slime - by arrnav96 - 06-10-2018, 03:47 AM
RE: Cloth to simulate slime - by akayashi1212 - 26-03-2021, 10:00 AM
RE: Cloth to simulate slime - by josemendez - 26-03-2021, 11:03 AM
RE: Cloth to simulate slime - by akayashi1212 - 27-03-2021, 04:24 AM
RE: Cloth to simulate slime - by josemendez - 29-03-2021, 09:59 AM
RE: Cloth to simulate slime - by akayashi1212 - 29-03-2021, 11:35 AM
RE: Cloth to simulate slime - by josemendez - 31-03-2021, 10:09 AM
RE: Cloth to simulate slime - by akayashi1212 - 31-03-2021, 02:47 PM
RE: Cloth to simulate slime - by josemendez - 31-03-2021, 06:21 PM
RE: Cloth to simulate slime - by akayashi1212 - 01-04-2021, 03:27 AM
RE: Cloth to simulate slime - by josemendez - 01-04-2021, 08:40 AM
RE: Cloth to simulate slime - by akayashi1212 - 01-04-2021, 09:57 AM
RE: Cloth to simulate slime - by josemendez - 05-04-2021, 12:06 PM
RE: Cloth to simulate slime - by akayashi1212 - 07-04-2021, 03:35 AM