Relaxing a mesh in C#

Hi everyone,

first of all, I don’t intend to recreate kangaroo abilities, I would just like to study the subject a little further and I thought it could be fun to code.

I browsed the K2 examples on github and read a bit the forum .If I understand it right I can relax the mesh by setting its edge length(without physic engine).

If I am not mistaken the steps are the following:
1)Get a vector for each endpoint of the edge(spring) and put it on a tree the vertexIndex as path.
2)Average the vector and move.

Maybe someone could give me a hint: Am I on the right way? Are my assumptions correct? Is it logical?

I started creating some really basic classes and tried and it seems to work somehow, the mesh seems to get a bit relaxed.

My code oviously is really amateurish and I am sure it could get optimized a lot.

A class for the vertices:

 public class Vertex
  {
    public Point3d Position;
    public bool IsAnchor = false;
    public int Index = -1;

    public Vertex(){}

    public Vertex(Point3d position, bool isAnchor, int index)
    {
      Position = position;
      IsAnchor = isAnchor;
      Index = index;
    }

  }

Another one for the springs(as the k2 one)

 public class Spring
  {
    public Vertex Start;
    public Vertex End;
    public double Restlength;
    public double Strength;
    public double Length;
    public Vector3d[] Move = new Vector3d[2];

    public Spring(){}

    public Spring(Vertex start, Vertex end, double restlength, double strength)
    {
      Start = start;
      End = end;
      Restlength = restlength;
      Strength = strength;
      Length = start.Position.DistanceTo(End.Position);

    }

    public void ComputeVector()
    {
      Vector3d current = Start.Position - End.Position;
      double stretchfactor = 1.0 - Restlength / Length;
      Vector3d SpringMove = 0.5 * current * stretchfactor;
      Move[0] = SpringMove;
      Move[1] = -SpringMove;
    }
  }

and one for the mesh:

 public class MeshSystem
  {

    public List<Spring> Springs = new List<Spring>();
    public List<Vertex> Vertices = new List<Vertex>();
    public Mesh Mesh;

    public List<Vector3d> movesList = new List<Vector3d>();

    public MeshSystem(){}
    public MeshSystem(Mesh mesh, List<Spring> springs, List<Vertex> vertices)
    {
      Mesh = mesh;
      Springs = springs;
      Vertices = vertices;
    }


    public void Step()
    {
      var verticesMoves = new DataTree<Vector3d>();

      for (int i = 0; i < Springs.Count; i++)
      {

        Springs[i].ComputeVector();

        if(!Springs[i].Start.IsAnchor)
        {verticesMoves.Add(Springs[i].Move[0], new GH_Path(Springs[i].Start.Index));}

        else
        {verticesMoves.Add(new Vector3d(0, 0, 0), new GH_Path(Springs[i].Start.Index));}

        if(!Springs[i].End.IsAnchor)
        {verticesMoves.Add(Springs[i].Move[1], new GH_Path(Springs[i].End.Index));}

        else
        {verticesMoves.Add(new Vector3d(0, 0, 0), new GH_Path(Springs[i].End.Index));}

      }


      for (int i = 0; i < verticesMoves.BranchCount; i++)
      {
        Vector3d averageVector = Util.average(verticesMoves.Branch(i));
        movesList.Add(averageVector);
      }


      for (int i = 0; i < Mesh.TopologyVertices.Count; i++)
      {
        Mesh.TopologyVertices[i] = (Point3f) ((Point3d) Mesh.TopologyVertices[i] + movesList[i]);
      }

    }

  }

Thanks for everybody taking the time and read!
Have a nice start into the weekend!

The file:20201210_MeshRelax.gh (17.5 KB)

Relaxing consists in minimizing the laplacian, that is, the difference with the neighbours. You don’t need an edge length but you want each point to be close to the average position of its neighbours. You can get the same effect with a spring-mass system trying that each edge has zero length, but if you really only want to relax a mesh, you shouldn’t parameterize it with an edge length but with the number of iterations as the native component Smooth Mesh and the Weaverbird component Laplacian Smoothing does.

If you want to make a particle system, then the question is another. Instead of copying Kangaroo, which is designed to be modulated in GH, you should simplify it for yourself, since it is just create speeds/acceleration on one hand, and update the position with these on the other, no need for classes or complex objects, just points and vectors are enough. If this is your interest, I recommend you to see the theory using the Nature of code of Daniel Shiffman (chapters 2 and 4), and even if it is in java using Processing, knowing C# you will know how to use Java, they are very similar.

1 Like

20201210_MeshRelax.gh (25.5 KB)

private void RunScript(Mesh mesh, double iters, bool naked, ref object A, ref object B)
{

if(mesh == null)
  return;

var strength = 1.0;
var count = mesh.Vertices.Count;
var pts = mesh.Vertices.ToPoint3dArray();
var neps = naked ? mesh.GetNakedEdgePointStatus() : new bool[count];
var energy = double.MaxValue;
while(energy > 1e-5 && iters-- > 0)
{
  // Apply forces
  var vels = new Vector3d[count];
  for (int i = 0; i < count; i++)
  {
    if(neps[i])
      continue;
    var pt = pts[i];
    var ave = Point3d.Origin;
    var gcv = mesh.Vertices.GetConnectedVertices(i);
    foreach(var c in gcv)
      ave += pts[c];
    ave /= gcv.Length;
    vels[i] = strength * (ave - pt);
  }

  //Update
  energy = 0.0;
  for (int i = 0; i < count; i++)
  {
    if(neps[i])
      continue;
    var p = pts[i];
    var v = vels[i];
    p += v;
    pts[i] = p;
    energy += v.Length;
    vels[i] *= 0.0;
  }
  energy /= count;
  //Print(energy.ToString()); // You can see how energy (desired state - current state) is minimized.
}

mesh.Vertices.Clear();
mesh.Vertices.AddVertices(pts);
mesh.RebuildNormals();

A = mesh;

}
1 Like

Hi @Baris
If all you want to do is relax a mesh by averaging vertices, it can be made even simpler :slightly_smiling_face:

rlx.gh (6.0 KB)

This is a further condensed version of what I posted here, just playing a little code golf.
It’s a very fun topic to explore. Enjoy!

2 Likes

Hi @Dani_Abalde,
thanks for the elaboration
I just started out of the blue and all your keywords are really apreciated and I will need to read further to know better what exactly fits my objective.I thought the spring system would be like a membrane would act in real life. I thought it should be possible without custom classes, I just wanted to train a bit their creation and usage but I didnt knew there was a native component, neither that its basically a laplacian applied on the vertices.

Nature of code is a great learning source, I saw it a while back, but forgot about its existence.Thanks for bringing it back to light.

And thanks for the code, it´s always nice to have a example of you pro users for learning and exploring.

Have a nice weekend!

1 Like

Hi @DanielPiker,

that looks like a Linq version, very condensed.

Thanks for the example!
Yesterday I found your old blog and browsed it. Incredible. I didnt even knew kangaroo exists that long.

I recently entered the world of meshes and yes, it¨s really fun to play with.

Have a nice weekend!