AB4D Forum

Full Version: join meshes
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Hi everybody,

I have one question but i'm not sure it is possible or not.
I have two adjacent object (2 meshes), and i need to 'weld' the objects so when i apply a movement to 2nd mesh the 1st stretch itseft to maintain connection.

Is it possible?
This can be done with manually updating the 3D positions that define the 1st mesh - (update the MeshGeometry3D.Positions).

But the problem is probably which positions to move. If you move all of them, then the whole mesh1 will be moved. You may want to move only the positions that face the mesh2. In this case do the following:
1) calculate the vector from mesh1 to mesh2 (vector = mesh2.center - mesh1.center).
2) for all three positions in each mesh1 triangles check if their normal vector is facing in the same direction as the previously calculated vector. In this case mark all three positions to be moved (do not move them immediately to prevent moving them multiple times when one position is used by multiple triangles). 

This step requires that the Normals are set for your mesh1 - if not set them by calling Ab3d.Utilities.MeshUtils.CalculateNormals method.

The in a for loop go through the MeshGeometry3D.TriangleIndices and increase index by 3 on each for iteration. Read indexes for all three positions from 3 following TriangleIndices (var i1 = mesh.TriangleIndices[i]; var i2 = mesh.TriangleIndices[i + 1]; var i3 = mesh.TriangleIndices[i + 2];).

Now get the normals for all 3 indexes (var n1 = mesh.Normals[i1], ...), sum them and divide by 3.

This will get you the normal of the triangle (you could also calculate that from positons and use CrossProduct).

To check if normal is facing the same direction as the vector from (1) use Vector3D.Dot product with passing triangle normal and the vector from (1) to the function. The result is a double value - if it is positive, then the vectors are facing in the same direction; if negative then they are facing in opposite directions; if 0 then they are perpendicular.

3) Finally, move all marked positions.


I hope this will help you. If not, then please define your problem in more detail.


Btw: 
The new version of Ab3d.PowerToys that was released 2 days ago comes with a "Basic WPF 3D tutorial" that can help you get a basic understanding of the WPF 3D objects. You can also get some additional info from link on the Links page (https://www.ab4d.com/Links.aspx).
Ok! it seems exact i need... but...
idefineda mesh with:
Dim mymesh As MeshGeometry3D
but mymesh.center is not  a member of meshgeometry3d!
why?
Ah, this was just the description of the algorithm. You can get the center with MeshGeometry3D.Bounds.GetCenterPosition() - the GetCenterPositon and an extension method from Ab3d.PowerToys library (you need to have a using to Ab3d to be able to use it).
Nothing!always says is not a member.
I found centre of the mesh using bouds and bouds.size (like x=bouds.x+bouds.size.x/2,  y=bouds.y+bouds.size.y/2  z=bouds.z+bouds.size.z/2) Is not the same thing?

But i need to find and move only the positions with the same coordinates in mesh1 and mesh2.
I will explain...

my mesh1 is a jaw and mesh2 is a tooth. If i move the tooth i need to stretch mesh1 moving the positions that, before moving the tooth, had the same coordinates.

I need to mantain the contact between mesh1 and mesh2 after moving the tooth.
I tried to :
1 - read all positions on mesh1 and check which have the same coordinates on mesh2, 
2- if yes marked them for moving, 
3 - calculate vector of mouvement (mesh2.center - mesh2.newcenter)
4 - move all the positions marked using this vector

Maybe it works but my mesh1 has 158000 vertices and code works 20 minutes!!

Some suggestions?
I am glad that you find a working algorithm.

When changing the positions it is (as you have found out) very slow to work directly on Positions in MeshGeometry3D. There each access to Position (e.g. "var p = mesh.Positions[i]") also requires a call to check the thread (to prevent access from another thread - this is done in the getter). Also, the positons are stored in a FrugalStructList that complicates access to values (I really do not understand why this was choosen for positions collection). What is more, each setting of a position checks the thread and also triggers change notifications.

One way to optimize this is to disconnect mesh from the parent GeometryModel3D - set model.Geometry to null, then do the changes and then set the Geometry back to the mesh.

An even better option is to use simple list or array objects to store the positions:
- copy all Positions to a list (List<Point3D>) or even better an array (Point3D[]) and when you need to read them, read the values from array and not from MeshGeometry3D.Positions
- when changing the positions, also do all the changes in an array (or list). When you are done with the changes, set the new positions with: mesh.Positions = new Point3DCollection(myPositions)


If this does not work fast enough, then you may need to generate / update meshes in multiple threads. To make this work, you will need to have separate MeshGeometry3D objects for each thread (one MeshGeometry3D object cannot be updated in multiple threads) - so you can create one MeshGeometry3D object in one background thread. To use that object in the main UI thread, you will need to call Freeze on it - this will prevent any changes and allow it to be used on the main UI thread.

If even this will not be fast enough, then you will need to use Ab3d.DXEngine and its MeshObjectNode or some other low level object - see "Advanced Ab3d.DXEngine usage" section in Ab3d.DXEngine samples for more info.


And one last and probably the most important tip: do not optimize the code without first profiling it and seeing where the actual reasons for slow performance are!
There is a last problem.

I found the positions to move, save them to an point3dcollections, but where i apply transofrmation on the mesh to move the mesh move itself in another location but when to read the new positions (to appli on the other mesh) i read the same positions....
Code:
dentehit.modelhit.transform = mygroup
       Dim newpos As New Point3DCollection
       newpos = dentehit.modelhit.geometry.positions

the collection newpos has the same positions that the mesh had before apply transform, so i don't have the updated position... 
why?
The transformation does not change the position in the MeshGeometry3D - it is send to the graphics card with the positions and then the graphics card applies the transformation in a shader when the 3D objects is rendered. Therefore it is much faster to change transformation then to change the positions. 

But for your case you can manually change the positions when you copy them from the original MeshGeometry3D to the actual one.
I'm not sure to understand,

the transformation is a rotate3d transformation, how i can manually calculate new positions?
Is another way to make a rotation to be sure to have the new positions?
You can transform Position3D with using Transform method - for example:
Code:
var rotateTransform3D = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), 45));

var position = new Point3D(0, 0, 0);
var transformedPosition = rotateTransform3D.Transform(position);