Skip to content
Permalink
master
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Beyond Reality Face SDK - BRFv5 - Face Tracking for Browser/JavaScript - Minimal ThreeJS Example</title>
<style>
html, body { width: 100%; height: 100%; background-color: #ffffff; margin: 0; padding: 0; overflow: hidden; }
</style>
</head>
<body>
<!--
This is a minimal modules example. It's much shorter than minimal_no_modules.html, because we already
provide lots of functionality within the modules.
-->
<video id="_webcam" style="display: none;" playsinline></video>
<canvas id="_imageData" style="position: absolute"></canvas>
<!-- TODO: ThreeJS canvas, see configureTracking() for scaling -->
<canvas id="__brfv5__threejs_canvas" style="position: absolute; transform: scale(1.0); transform-origin: 0 0"></canvas>
<script type="module">
import { brfv5 } from './js/brfv5/brfv5__init.js'
import { loadBRFv5Model } from './js/brfv5/brfv5__init.js'
import { configureCameraInput } from './js/brfv5/brfv5__configure.js'
import { configureFaceTracking } from './js/brfv5/brfv5__configure.js'
import { configureNumFacesToTrack } from './js/brfv5/brfv5__configure.js'
import { startCamera } from './js/utils/utils__camera.js'
import { drawInputMirrored } from './js/utils/utils__canvas.js'
import { drawCircles } from './js/utils/utils__canvas.js'
import { drawRect, drawRects } from './js/utils/utils__canvas.js'
const _appId = 'brfv5.browser.minimal.modules.threejs' // (mandatory): 8 to 64 characters, a-z . 0-9 allowed
const _webcam = document.getElementById('_webcam')
const _imageData = document.getElementById('_imageData')
// Those variables will be retrieved from the stream and the library.
let _brfv5Manager = null
let _brfv5Config = null
let _width = 0
let _height = 0
// loadBRFv5Model and openCamera are being done simultaneously thanks to Promises. Both call
// configureTracking which only gets executed once both Promises were successful. Once configured
// trackFaces will do the tracking work and draw the results.
startCamera(_webcam, { width: 640, height: 480, frameRate: 30, facingMode: 'user' }).then(({ video }) => {
console.log('openCamera: done: ' + video.videoWidth + 'x' + video.videoHeight)
_width = video.videoWidth
_height = video.videoHeight
_imageData.width = _width
_imageData.height = _height
configureTracking()
}).catch((e) => { if(e) { console.error('Camera failed: ', e) } })
loadBRFv5Model('42l', 6, './js/brfv5/models/', _appId,
(progress) => { console.log(progress) }).then(({ brfv5Manager, brfv5Config }) => {
console.log('loadBRFv5Model: done')
_brfv5Manager = brfv5Manager
_brfv5Config = brfv5Config
configureTracking()
}).catch((e) => { console.error('BRFv5 failed: ', e) })
const configureTracking = () => {
if(_brfv5Config !== null && _width > 0 && _modelsLoaded) {
configureCameraInput(_brfv5Config, _width, _height)
configureNumFacesToTrack(_brfv5Config, 1)
configureFaceTracking(_brfv5Config, 3, true)
// Free rotation results in better tracking, but lower performance.
// _brfv5Config.faceTrackingConfig.enableFreeRotation = true
// _brfv5Config.faceTrackingConfig.maxRotationZReset = 34.0
_brfv5Manager.configure(_brfv5Config)
update3DLayout(t3d, _width, _height)
_threejs.style.transform = 'scale(' + (1.0 / t3d.sceneScale) + ')'
trackFaces()
}
}
const trackFaces = () => {
if(!_brfv5Manager || !_brfv5Config || !_imageData) { return }
const ctx = _imageData.getContext('2d')
drawInputMirrored(ctx, _width, _height, _webcam)
_brfv5Manager.update(ctx.getImageData(0, 0, _width, _height))
let doDrawFaceDetection = !_brfv5Config.enableFaceTracking
if(_brfv5Config.enableFaceTracking) {
const sizeFactor = Math.min(_width, _height) / 480.0
const faces = _brfv5Manager.getFaces()
for(let i = 0; i < faces.length; i++) {
const face = faces[i]
if(face.state === brfv5.BRFv5State.FACE_TRACKING) {
// Update the 3d model placement.
updateByFace(t3d, face, i, true)
drawRect(ctx, _brfv5Config.faceTrackingConfig.regionOfInterest, '#00a0ff', 2.0)
drawCircles(ctx, face.landmarks, '#00a0ff', 2.0 * sizeFactor)
drawRect(ctx, face.bounds, '#ffffff', 1.0)
} else {
doDrawFaceDetection = true
updateByFace(t3d, face, i, false)
}
}
render3DScene(t3d)
}
if(doDrawFaceDetection) {
// Only draw face detection results, if face detection was performed.
drawRect( ctx, _brfv5Config.faceDetectionConfig.regionOfInterest, '#ffffff', 2.0)
drawRects(ctx, _brfv5Manager.getDetectedRects(), '#00a0ff', 1.0)
drawRects(ctx, _brfv5Manager.getMergedRects(), '#ffffff', 3.0)
}
requestAnimationFrame(trackFaces)
}
//
//
//
// Find below most of the additional ThreeJS code for setup, loading models, setting models by face.
//
//
//
import { create3DScene } from './js/threejs/threejs__setup.js'
import { update3DLayout } from './js/threejs/threejs__setup.js'
import { updateByFace } from './js/threejs/threejs__brfv5_mapping.js'
import { hideAllBaseNodes } from './js/threejs/threejs__brfv5_mapping.js'
import { render3DScene, setNumFaces, prepareModelNodes,
hideAllModels, turnIntoOcclusionObject, add3DModel,
set3DModelByName } from './js/threejs/threejs__setup.js'
import { load3DModelList,
getModelInstance } from './js/threejs/threejs__loading.js'
let _models = [
// Load the occlusion model (an invisible head). It hides anything behind it.
{
pathToModel: './assets/3d/occlusion_head.artov5',
pathToTextures: './assets/3d/textures/',
nameModel: null,
isOcclusionModel: true,
isMaterialCollection: false
},
// The actual 3d model as exported from ThreeJS editor.
// either rayban.json or earrings.json
// Textures might be embedded or set as file name in a certain path.
{
pathToModel: './assets/3d/rayban.artov5',
pathToTextures: './assets/3d/textures/',
nameModel: null,
isOcclusionModel: false,
isMaterialCollection: false
},
{
pathToModel: './assets/3d/pearlearring_left.artov5',
pathToTextures: './assets/3d/textures/',
nameModel: null,
isOcclusionModel: false,
isMaterialCollection: false
},
{
pathToModel: './assets/3d/pearlearring_right.artov5',
pathToTextures: './assets/3d/textures/',
nameModel: null,
isOcclusionModel: false,
isMaterialCollection: false
}
]
// TODO: The ThreeJS namespace object
const t3d = { sceneScale: 2.0 } // sceneScale: 2.0 increases render quality, 1.0 for lower render quality
const _threejs = document.getElementById('__brfv5__threejs_canvas')
let _modelsLoaded = false
// TODO: Create scene and load the models:
if(create3DScene(t3d, _threejs)) {
setNumFaces(t3d, 1)
hideAllBaseNodes(t3d)
load3DModelList({ fileList: _models, onProgress: null }).then(() => {
prepareModelNodes(t3d)
hideAllModels(t3d)
for(let i = 0; i < _models.length; i++) {
const model = _models[i]
const obj3d = getModelInstance(t3d, model.pathToModel)
if(model.isOcclusionModel) {
turnIntoOcclusionObject(obj3d)
}
if(!model.isMaterialCollection && obj3d) {
add3DModel(t3d, obj3d)
}
}
for(let i = 0; i < _models.length; i++) {
const model = _models[i]
if(!model.isMaterialCollection) {
set3DModelByName(t3d, model.pathToModel, model.nameModel, (url, name) => {
console.error('SETTING_3D_MODEL_NAME_FAILED:', name, url)
})
}
}
_modelsLoaded = true
configureTracking()
}).catch((e) => { console.error(e) })
}
</script>
</body>
</html>