freePolygonIndicesFloating with controlPointsFloating

Hey Guys,
So I’m using the new polyGroup functions to pass in to the nonRigidRegistration function. If I have control points on both the fixed and floating mesh on those areas that I want to exclude (the points are auto-derived but the polyGroups were pre-defined) it seems that the control points still solve to the areas that I want to exclude.

excludePolysGroups = ['scalp', 'ears']
freePolys = []
for groups in excludePolysGroups:
    polyIds = sourceMesh.selectPolygonsByPolygroup(groups)
    for poly in polyIds:
        freePolys.append(poly)
        
# Put them in order        
freePolys.sort()
wrapped = wrap.nonRigidRegistration(sourceMesh, targetMesh, sourcePoints, targetPoints, freePolys, minNodes=20, maxIterations=20, smoothnessFinal=0.1)

Is there something I’m missing to have the controlPoints not influenced by the polyGroups?

Also, the wrap.save() doesn’t seem to force a save if a model already exists. Can you guys confirm?

Hello!

Yes, control points always take part in optimization. That was done for a reason and in many cases that is a desired behaviour, especially when you want to wrap parts of scan (fingers, toes, ears) that has so much noise that the scan’s geometry is almost useless.

Please take a look at this tutorial where free polygons and control points are explained in details: http://www.russian3dscanner.com/portfolio/free-polygons-introduction

Also, the wrap.save() doesn't seem to force a save if a model already exists. Can you guys confirm?

We have tryed to reproduce this behaviour with no luck. Could you please double-check it? Script example would be very helful.

Hi,
Thanks Andrew! I think the save issue was a windows time stamp issue. It does overwrite the model.

So what would be the best approach to exclude poly faces from the float geom at runtime? I was looking the the subset function.

btw, I’ve been using the console calls to wrapX and it’s been working great. I’ve even been able to spawn multiple processes and batch must faster. What’s the ETA on a non-gui windows version? It would be great to batch a big set of models in the background.

Thanks guys,
-Sean

Hi Sean,

If you want the excluded polygons being completely locked the best solution would be
wrap.subset(geom, polygonIndices) and wrap.applySubset(geom, geomSubset, vertexMapping)

I feel like i didn’t get your usecase. I could help if you provide more info or screenshots of what you are trying to achieve.

Yea, let me give you a breakdown of what I’m after here and what I’ve done.
I have a high res face with blendshapes as well as LOD heads without blendshapes. I’ve extracted out all the targets from the high res as obj’s and bring them into WrapX to wrap the low res neutral to the morph on the high res.

My first pass was to create a mapping between the high and low res models. I loop through a sparse number of verts on the low res and use those vert ID’s to project the points onto the high res. This builds the control point sets for both models. This mapping is used for the nonRigidRegistration pass.

The polygroups would be used to lock down parts of the low res model since the control points were auto generated.

The wrap pass brings in each of the high res targets and wraps the low res neutral to it and saves out the new low res blendshape.

Now I know people reading this would say why didn’t I use Transfer Attributes in Maya. While this sort of works, it requires that UV’s be really tight and lay exactly on top of each other. There was still areas that required a fair amount of clean up. The process I have above leaves little to no clean up needed and is UV independent.

Hope that helps paint a better picture.

Thank you for great explanation! Now I got it!

Why do you prefer autogenerated vertex IDs? What if you predefine an accurate set of correspondences once and use it in each nonRigidRegistration pass?

I would take a neutral high res face and neutral LOD and specify point correspondences manually using

pointsHigh, pointsLOD = wrap.selectPoints(highResFace,lodFace);

This should be done once. Yes it may take some time but this would give better accuracy for eyes and mouth areas (as you can carefuly specify a loop of points) and symmetry.

wrap.PointOnTrianle representation keeps barycentric coordinates of points and does not depend on actual vertex positions, so you can use the same pointsHigh and pointsLOD for each blend shape.

Well, the auto-generated approach is really just a test. You’re right I would have better results if I created a much smaller, manual selection of points.

I do have another process I’m working out. Basically the workflow consists of making a model live in Maya so I can place joints on one side of the surface of the mesh. This way I can place a joint arbitrarily on the mesh. I rename the joints like “r_scanPoints#”. I then mirror the joints over so I have perfect symmetry. I grab all the joints and get the (X,Y,Z) coords. This gets spit out to a file and read into wrapX and I loop through each of the positions to get the PointOnTriangle.

# Loop through each position and get triangle on base mesh
for pos in vertPosition:
    nearPoint = basemesh.pointToPointOnTriangle(pos[0], pos[1], pos[2])
    try:
        # Try and get the triangle at that location
        items = (nearPoint.triangleInd, nearPoint.u, nearPoint.v)
        point = wrap.PointOnTriangle(items)
        basePoints.append(point)
    except ValueError:
        # Didn't get it so find the closest point
        nearestId = basemesh.nearestVertexInd(pos[0], pos[1], pos[2])
        vertToTri = basemesh.vertexIndToPointOnTriangle(nearestId)
        items = (vertToTri.triangleInd, vertToTri.u, vertToTri.v)
        point = wrap.PointOnTriangle(items)
        basePoints.append(point)

Basically find the triangle at that position. If it’s not found ( probably at a border edge of the mesh) get the nearest Vertex.

Very smart! You bring the use cases that I could not even imagine :slight_smile:

Thanks Andrew! :wink: