# Mesh getting offset on combine because of worldmatrix

When I try to combine my mesh, it get offset to an other position, but the collider is still at the same place (because i dont delete and add it again). I saw a fix on internet that is to do:

Matrix4x4 myTransform = transform.worldToLocalMatrix;
combine[i].transform = myTransform*meshFilters[i].transform.localToWorldMatrix;


which worked in one of my script, but I just cant get it to work in this one. How can it be fixed ?

Vector3 cb = Vector3.zero;
Vector3 n = hit.normal;
Vector3 p = hit.point;

if(n == new Vector3(1.0f,0.0f,0.0f) | n == new Vector3(-1.0f,0.0f,0.0f))
{
cb = new Vector3((n.x*0.5f)+p.x,Mathf.Round(p.y),Mathf.Round(p.z));
}
if(n == new Vector3(0.0f,1.0f,0.0f) | n == new Vector3(0.0f,-1.0f,0.0f))
{
cb = new Vector3(Mathf.Round(p.x),(n.y*0.5f)+p.y,Mathf.Round(p.z));
}
if(n == new Vector3(0.0f,0.0f,1.0f) | n == new Vector3(0.0f,0.0f,-1.0f))
{
cb = new Vector3(Mathf.Round(p.x),Mathf.Round(p.y),(n.z*0.5f)+p.z);
}
GameObject cub = Instantiate(cube,cb,Quaternion.identity);
GameObject dupli = Instantiate(hit.collider.gameObject,hit.collider.gameObject.transform.position,Quaternion.identity);
MeshFilter[] meshFilters = new MeshFilter[]{cub.GetComponent<MeshFilter>(),hit.collider.gameObject.GetComponent<MeshFilter>(),dupli.GetComponent<MeshFilter>()};
CombineInstance[] combine = new CombineInstance[meshFilters.Length];
Matrix4x4 myTransform = meshFilters[2].transform.localToWorldMatrix;
combine[0].mesh = meshFilters[0].sharedMesh;
combine[1].mesh = meshFilters[1].sharedMesh;
combine[2].mesh = meshFilters[2].sharedMesh;
combine[0].transform = meshFilters[0].transform.localToWorldMatrix;
combine[1].transform = meshFilters[1].transform.localToWorldMatrix;
combine[2].transform = meshFilters[2].transform.localToWorldMatrix;
meshFilters[2].mesh = new Mesh();
Vector3 sP = meshFilters[2].gameObject.transform.position;
meshFilters[2].gameObject.transform.position = Vector3.zero;
meshFilters[2].mesh.CombineMeshes(combine);
meshFilters[2].gameObject.transform.position = sP;
Destroy(meshFilters[0].gameObject);
Destroy(meshFilters[1].gameObject);


This code is doing all sorts of stuff it doesn't have to, and as I've told you before, still is not the correct way to build your chunks.

If you want to keep doing this the way you have, here's what we can fix:

The first part can be drastically simplified - we don't need if statements to check the direction of the normal, and we can name our variable descriptively.

var placementPosition = hit.point + hit.normal * 0.5f;
for(int i = 0; i < 3; i++)
placementPosition[i] = Mathf.Round(placementPosition[i]);


Next, we know we only need to combine two meshes: the mesh we started with, and the mesh we're adding. You can pre-allocate one array as a member variable:

CombineInstance[] _combinedPair = new CombineInstance[2];


Then just re-use it each time you call your block-spawning function, to save an unnecessary allocation.

var filter = hit.gameObject.GetComponent<MeshFilter>();

// Reproduce the existing mesh, exactly where it is already.
_combinedPair[0].mesh = filter.sharedMesh;
_combinedPair[0].transform = Matrix4x4.identity;

// Add a cube to it, at an offset from its center.
_combinedPair[1].mesh = cubeMesh;
_combinedPair[1].transform = Matrix4x4.Translate(filter.transform.InverseTransformPoint(placementPosition));


Here using a public variable to store our cube mesh, as shown in this answer, so we don't need to instantiate dummy cube objects only to later destroy them.

Then just combine your meshes into your current chunk and be done with it.

var chunkMesh = new Mesh();
chunkMesh.CombineMeshes(_combinedPair);
filter.sharedMesh = chunkMesh;


And if you need to apply the result back to your collision representation too:

((MeshCollider)hit.collider).sharedMesh = chunkMesh;


Note that this still:

• Allocates a whole new mesh every time you add a single cube.

• Includes all internal faces, without any hidden surface removal.

But at least we don't create and destroy sacrificial objects each time, so that's a slight improvement.

So again, please don't do it this way. Just use the answer I've linked you to twice now. But if you're going to do this inefficiently, at least be inefficient as efficiently as possible. ;)