Attach and align a procedural mesh to a bone

Hello dear community,

I am working on a project where the environment is procedurally destroyed and used as a weapon.
After some weeks of hard work with vertices, I am getting satisfied with the meshes I am rebuilding in game. Now I want to assign these meshes as weapons to my character.

Usually when I assign a weapon designed in Blender, I use this traditional code (my weapons are in a child folder of my player object called “Weapons”):

Transform locWeapon = transform.Find(“Weapons/Axe0”);
string locWpnPath = “Player/Armature/Belly/Torso/Shoulder.R/Arm.Up.R/Arm.Down.R/Hand.Up.R/Weapon.Up.R”;
locWeapon.parent = gameObject.transform.Find(locWpnPath);

locWeapon.localPosition = Vector3.zero;
locWeapon.localRotation = gameObject.transform.Find(locWpnPath).localRotation;

and there’s never been any trouble so far since I define the weapon default angle in Blender.

But in this new case, the mesh I want to assign is pretty random, I have no control on its angle by default.

Here is how the armature of my chara designed in Blender, with the specific bone holding the weapon:

In game, let’s suppose I want to use this piece of wood that I’ve just destroyed in this picture:


If I use the upper code, I will end up with the result as shown in this picture:
Using locWeapon.localRotation = Quaternion.Identity is not gonna change much.

Of course, I would like this piece of wood to be aligned with my bone.

But this cas is almost simple.

If I go further, if I want to align let’s say a tetraedric rock, my chara should hold the mesh by its tiniest part, so the shape of the mesh has also influence on the angle (I already took the shape a of the mesh when I break it, by using ratios of sideX/sideY/sideZ where
sideX = transform.localScale.x * GetComponent().mesh.bounds.size.x.)

So, before I go into some deep and time-killing geometric considerations, has anyone here been dealing with the same kind of problematic?

Thank you for your time,

Goupil

SOLUTION PART 1

OK, I found my way.

This is not very elegant, I’m sure I’ll be back on this code in a couple of weeks with more inspiration, but I thought I’d have to share it here if some of you guys are dealing with the same problem…

I am working with the same rigged character.
Let’s say I wanna hold with my fist this randomly build mesh via code:


The first thing you have to is to make the mesh a child of an object, otherwise things will become impossible as soon as you’ll try to play with position and rotation.
To make it short I am targetting right now the object Tetra0, which will become the object weaponMesh named Tetra0_Mesh, child of weaponObject named Tetra0, which is stored in a child “Weapons” of my character.

string meshName = Tetra0.name;

GameObject weaponObject = new GameObject(meshName);
weaponObject.transform.parent = transform.Find(“Weapons”);

GameObject weaponMesh = Tetra0;
weaponMesh.name = meshName + “_Mesh”;
weaponMesh.transform.parent = weaponObject.transform;

Now I assign this weaponObject to my fist:

string fistPath = “Player/Armature/Belly/Torso/Shoulder.R/Arm.Up.R/Arm.Down.R/Hand.Up.R/Weapon.Up.R”;
Transform fistTransform = transform.Find(fistPath);

Transform weaponTransform = transform.Find(“Weapons/Tetra0”);
weaponTransform.parent = fistTransform;
weaponTransform.position = fistTransform.position;
weaponTransform.rotation fistTransform.rotation;
weaponTransform.localPosition = Vector3.zero;

At this point, this is what I have:

I reset the localPosition of the mesh Tetra0_Mesh contained in weaponObject like this:

GameObject weaponMesh = weaponTransform.Find(“Tetra0_Mesh”).gameObject;
weaponMesh.transform.localPosition = Vector3.zero;

to get this result:

Now this is where things get more delicate. First I had to find a way to get the shape of the mesh so I can align it in a “physically” logical way = not crossing the body of the chara, and with longest side perpendicular to the carrying arm (PS: my chara is supposed to be very strong…).

This is why I am sorting the length of the sides of my mesh in a world-scale in the class called CollisionMaterial of weaponMesh:

public class CollisionMaterial : MonoBehaviour {

private float sideX;
private float sideY;
private float sideZ;
public float sortedSides;
public int sortedIndexes;
public Vector3 center { get; set; }

public void SetGround()
{
Transform locTransform = transform.parent;

transform.parent = null;

sideX = transform.localScale.x * GetComponent().mesh.bounds.size.x;
sideY = transform.localScale.y * GetComponent().mesh.bounds.size.y;
sideZ = transform.localScale.z * GetComponent().mesh.bounds.size.z;

sortedSides = new float[3] { sideX, sideY, sideZ };
sortedIndexes = new int[3] { 0, 1, 2 };
System.Array.Sort(sortedSides, sortedIndexes);

SetCenter();

transform.parent = locTransform;
}

public void SetCenter()
{
center = transform.TransformPoint(GetComponent().mesh.bounds.center);
}

Back to my fist code, I check which one of the sorted sides X, Y or Z is the biggest to define the angle I will rotate the mesh:

CollisionMaterial weaponMaterial = weaponMesh.GetComponent();

// Side X is the biggest one
if (weaponMaterial.sortedIndexes[2] == 0)
{
weaponMesh.transform.localRotation = Quaternion.LookRotation(transform.right, transform.forward);
}
// Side Y is the biggest one
else if (weaponMaterial.sortedIndexes[2] == 1)
{
weaponMesh.transform.localRotation = Quaternion.LookRotation(transform.forward, transform.forward);
}
// Side Z is the biggest one
else if (weaponMaterial.sortedIndexes[2] == 2)
{
weaponMesh.transform.localRotation = Quaternion.LookRotation(transform.up, transform.forward);
}

I now have this result:

The last thing is now to make the fist hold the extremity of the mesh and not its center. The problem is, in my case, the origin can be wherever, since my meshes are generated randomly. As a comparison the same code with a mesh designed with Blender gives me this:

since I can’t use the transform.position of my mesh as a reference I then re-used the SetCenter of my CollisionMaterial class (the same used during the sort of the sides, but it’s important to update it after the rotation process):

weaponMaterial.SetCenter();
Vector3 offSet = weaponTransform.position - weaponMaterial.center;
weaponTransform.position += offSet;
// At this point, I hold the mesh by its center along the biggest side axis; now I arbitrarly move up the mesh 25% of the length of this side
weaponTransform.position += weaponTransform.up * weaponMaterial.sortedSides[2] * 0.25f;

…and this is what I get:

SOLUTION PART 2:

… and this is hat I get:

Now you have to play a bit with all these parameters to get the fine result you wanna achieve, but the main idea is here.
Regarding the sort of the sides, in the case of a more complex shape, I have tried this algo by aldonatello in this subject:
http://answers.unity3d.com/questions/280741/how-make-visible-the-back-face-of-a-mesh.html

it gives interesting results.

Hope my novel is not too long and OK to read, as you can guess I am not a coder, and even less used to share it.

Praise the Sun.

Yeah, it looks like you’re on the right track. I would tackle this by:

  • When I construct the mesh, first find all the points, and compute their average, which gets you sort-of the centroid of the object. (It’s not the actual centroid, as if you have a bunch of little triangles on one side, this average will pull over in that direction. But I suspect that in your case it’s close enough. If you need the real centroid, there are ways to do that, but it’s a little complicated.)
  • Find the furthest point from the centroid (easy!).
  • Stuff the mesh inside another GameObject so that the furthest point lies at the container’s position, and the centroid lies on the +Z axis.

Now you have an object you can pick up and use just like any club modeled the same way, i.e., with its origin at the handle and extending down the +Z axis.

Which I did, you are right.

I hoped I could play a little bit more with “direct” control of the mesh without passing through a parent GameObject since I generate, modify, even throw a lot of meshes via script… I worry about future performances, if at one moment I begin manipulating more complex meshes.

@ that looks beautiful. Do you have any gif of what you’re doing with the weapon (pick up + use etc)?