Getting Started: Simple Wrapping

Start with importing module wrap

import wrap

Loading Geometry

Load basemesh from file. The default folder for wrap’s example models is stored in wrap.demoModelsPath

basemeshFileName = wrap.openFileDialog("Select Basemesh",filter = "OBJ-file (*.obj)",dir = wrap.demoModelsPath)
basemesh = wrap.Geom(basemeshFileName)

Load scan.

Note

If scan is in small scale it is highly recommended to pre-scale the model with some reasonable scaleFactor.

scanFileName = wrap.openFileDialog("Select Scan",filter = "OBJ-file (*.obj)",dir = wrap.demoModelsPath)
scan = wrap.Geom(scanFileName,scaleFactor = 1000)

Turn off wireframe

scan.wireframe = False

Load scan’s texture

textureFileName = wrap.openFileDialog("Select Scan's Texture",filter = "Image (*.jpg *.png *.bmp *.tga)",dir = wrap.demoModelsPath)
if textureFileName is not None:
    scan.texture = wrap.Image(textureFileName)

Show texture in 2D-viewport

scan.texture.show()

Pre-Alignment

If the basemesh and the scan are in different scale and orientation we need to pre-align them using rigidAlignment. At least 3 user-defined point correspondences are required to find affine transformation between the basemesh and the scan

# display point selection dialog
(pointsScan, pointsBasemesh) = wrap.selectPoints(scan,basemesh)
# find rigid alignment transformation as matrix 4x4
rigidTransformation = wrap.rigidAlignment(basemesh,pointsBasemesh,scan,pointsScan,matchScale = True)
# apply the transformation to the basemesh
basemesh.transform(rigidTransformation)
basemesh.fitToView()

Non-Rigid Registration

Now that the basemesh and the scan are pre-aligned we can start non-rigid registration. The user can help the registration process by providing several user-defined point correspondences. In some cases you don’t want some polygons of the basemesh to be stitched to the scan. For example when an actor has a stocking on his head. Wrapping the back side of basemesh’s head around the stocking would make no sense as the stocking’s shape does not reflects the real shape of the actor’s head. In this situation it’s better to leave correspondent polygons of the basemesh as less affected as possible. All you need it to select correspondent polygons of the basemesh as Free polygons

# display point selection dialog to define point correspondences
(controlPointsScan,controlPointsBasemesh) = wrap.selectPoints(scan,basemesh)
# display polygon selection dialog to define free polygons
freePolygonsBasemesh = wrap.selectPolygons(basemesh)
# start non-rigid registration
basemesh = wrap.nonRigidRegistration(basemesh,scan,controlPointsBasemesh,controlPointsScan,freePolygonsBasemesh,minNodes = 15,initialRadiusMultiplier = 1.0,smoothnessFinal = 0.1,maxIterations = 20)

Extracting Details

Now that the basemesh is wrapped around the scan you might want to extract more small details from the scan. In order to do that you can subdivide the basemesh and to project it onto the scan

# subdivide
basemesh = wrap.subdivide(basemesh)
# project
disabledPolygons = wrap.selectPolygons(basemesh)
basemesh = wrap.projectMesh(basemesh,scan,maxRelativeDist = 1,disabledPolygonIndicesSrc = disabledPolygons)

Transferring Texture

If the scan has texture we can project it to the basemesh

if scan.texture is not None:
    basemesh.texture = wrap.transferTexture(scan,scan.texture,basemesh,(2048,2048),maxRelativeDist = 3)
    # fill holes on the texture by color extrapolation. This is useful for hiding texture seams.
    basemesh.texture.extrapolate()

Saving Results

Now that we have our final model we can save the model and the texture to file

basemesh.save("wrapped.obj",scaleFactor = 1.0 / scaleFactor)
if scan.texture is not None:
    basemesh.texture.save("wrapped.jpg")