TriMesh ciFaceTracker::getMesh(const vector<vec3>& points) const { TriMesh mesh; if (!mIsFailed) { int n = size(); for (int i = 0; i < n; i++) { mesh.appendPosition(points[i]); mesh.appendTexCoord({ getImagePoint(i).x / mImgSize.x, getImagePoint(i).y / mImgSize.y }); } addTriangleIndices(mesh); } return mesh; }
void FaceOff::trackerThreadFn() { jing::Option option; option.scale = 0.5f; mOfflineTracker = jing::BaseFaceTracker::create(); mOnlineTracker = jing::BaseFaceTracker::create(option); bool shouldInitFaceMesh = false; while (!mShouldQuit) { // TODO: more robust with update_signal if (!mCapture.checkNewFrame()) { sleep(1.0f); continue; } if (mDoesCaptureNeedsInit) { // TODO: more robust with setup_signal mDoesCaptureNeedsInit = false; CAM_W = mCapture.size.x; CAM_H = mCapture.size.y; auto createFboFn = [this] { gl::Fbo::Format fboFormat; fboFormat.enableDepthBuffer(false); mRenderedOfflineFaceFbo = gl::Fbo::create(CAM_W, CAM_H, fboFormat); mFaceMaskFbo = gl::Fbo::create(CAM_W, CAM_H, fboFormat); mClone.setup(CAM_W, CAM_H); mClone.setStrength(16); }; dispatchAsync(createFboFn); } if (mPeopleId != PEOPLE_ID) { mPeopleId = PEOPLE_ID; ImageSourceRef img = loadImage(loadAsset("people/" + mPeopleNames[PEOPLE_ID])); updateOfflineImage(img); shouldInitFaceMesh = true; } mOnlineTracker->update(mCapture.surface); if (!mOnlineTracker->getFound()) { mHasNewRenderedFace = false; continue; } int nPoints = mOnlineTracker->size(); if (shouldInitFaceMesh) { shouldInitFaceMesh = false; mFaceMesh.getBufferTexCoords0().clear(); auto imgSize = mOfflineTracker->getImageSize(); for (int i = 0; i < nPoints; i++) { vec3 point = mOfflineTracker->getImagePoint(i); mFaceMesh.appendTexCoord({ point.x / imgSize.x, point.y / imgSize.y }); } mOnlineTracker->addTriangleIndices(mFaceMesh); } mFaceMesh.getBufferPositions().clear(); for (int i = 0; i < nPoints; i++) { mFaceMesh.appendPosition(mOnlineTracker->getImagePoint(i)); } if (VFX_VISIBLE && mOfflineFaceTex) { dispatchAsync(bind(&FaceOff::updateClone, this)); } } }