// you need to SetSimulation in Simualtion class's OnAfterDeserialize() callback. this is a hack
 //becaue unity serializaiton does not keep references.
 public void SetParticles(Simulation sim)
 {
     this.sim  = sim;
     particleA = sim.getParticle(indexA);
     particleB = sim.getParticle(indexB);
     particleM = sim.getParticle(indexM);
 }
 // you need to SetSimulation in Simualtion class's OnAfterDeserialize() callback. this is a hack
 public void SetParticles(Simulation sim)
 {
     this.sim      = sim;
     a             = sim.getParticle(indexA);
     b             = sim.getParticle(indexB);
     a.PositionOld = a.Position;
     b.PositionOld = b.Position;
 }
 public Spring2D(Simulation sim, int indexA, int indexB, float restLength)
 {
     this.indexA      = indexA;
     this.indexB      = indexB;
     this.sim         = sim;
     a                = sim.getParticle(indexA);
     b                = sim.getParticle(indexB);
     this.restLength2 = restLength * restLength;
     on               = true;
 }
 void TraverseBinaryTreeForCircle(BinaryTree branch)
 {
     if (branch.branchA != null && branch.branchB != null)
     {
         if (branch.depth < this.minTraverseDepth)
         {
             TraverseBinaryTreeForCircle(branch.branchA);
             TraverseBinaryTreeForCircle(branch.branchB);
         }
         else
         {
             searchCount++;
             if (branch.boundingCircle.Overlaps(this.targetPos, this.cc.radius))
             {
                 TraverseBinaryTreeForCircle(branch.branchA);
                 TraverseBinaryTreeForCircle(branch.branchB);
             }
         }
     }
     else if (branch.branchA == null && branch.branchB == null)
     {
         Vector2 dir;
         searchCount++;
         if (branch.boundingCircle.OverlapsResults(this.targetPos, this.cc.radius, out dir))
         {
             if (isDebugCollidingOn)
             {
                 branch.boundingCircle.DebugDraw(transform.localToWorldMatrix, branch.depth, Color.magenta);
             }
             //apply collision
             Particle2D pp = sim.getParticle(branch.leafIndex);
             pp.Position -= dir * leafForceFeedback;
             dir          = transform.TransformDirection(dir);
             targetRb2D.AddForce(dir * targetForceFeedback, ForceMode2D.Force);
         }
     }
 }
        public SimBuffer_Spring(Simulation sim, Vector2[] particleUV, int width, int height)
        {
            this.sim = sim;
            rt       = new RenderTexture[sim.maxSpringConvergenceID];
            int parNum = sim.numberOfParticles();

            ID_SpringParamRT  = Shader.PropertyToID("_SpringParamRT");
            ID_SpringConstant = Shader.PropertyToID("_SpringConstant");
            ID_PositionRT     = Shader.PropertyToID("_PositionRT");

            //rg = the other end point's uv, b = restlength, a = state
            Color[]   tempColor = new Color[width * height];
            Texture2D tempTex   = new Texture2D(width, height, TextureFormat.RGBAFloat, false, false);

            for (int i = 0; i < sim.maxSpringConvergenceID; i++)
            {
                //init rt
                rt[i] = new RenderTexture(width, height, 0, RTFormat.ARGB);
                rt[i].Create();

                //prepare temp color
                for (int k = 0; k < width * height; k++)
                {
                    if (k < parNum)
                    {
                        Vector2 uv = particleUV[k];
                        tempColor[k] = new Color(uv.x, uv.y, 1f, (sim.getParticle(k).IsFree) ? 1f : 0f);
                    }
                    else
                    {
                        tempColor[k] = new Color(0f, 0f, 1f, 0f);
                    }
                }

                //get info
                for (int j = 0; j < sim.numberOfSprings(); j++)
                {
                    Spring2D sp = sim.getSpring(j);
                    if (sp.convergenceGroupID == i + 1)
                    {
                        int a = sim.getParticleIndex(sp.ParticleA);
                        int b = sim.getParticleIndex(sp.ParticleB);
                        tempColor[a].r = particleUV[b].x;
                        tempColor[a].g = particleUV[b].y;
                        tempColor[a].b = sp.restLength2;
                        tempColor[a].a = (sp.ParticleA.IsFree) ? 1f : 0f;
                        tempColor[b].r = particleUV[a].x;
                        tempColor[b].g = particleUV[a].y;
                        tempColor[b].b = sp.restLength2;
                        tempColor[b].a = (sp.ParticleB.IsFree) ? 1f : 0f;
                    }
                }

                //blit
                tempTex.SetPixels(tempColor);
                tempTex.Apply();
                Graphics.Blit(tempTex, rt[i]);
            }

            Extension.ObjDestroy(tempTex);

            //mpb
            mpb = new MaterialPropertyBlock[sim.maxSpringConvergenceID];
            for (int i = 0; i < sim.maxSpringConvergenceID; i++)
            {
                mpb[i] = new MaterialPropertyBlock();
                mpb[i].SetTexture(ID_SpringParamRT, rt[i]);
                mpb[i].SetFloat(ID_SpringConstant, sim.Settings.springConstant);
            }

            //tempRT
            tempRT = new RenderTexture[sim.maxSpringConvergenceID - 1];
        }