Detto cio' viene mostrato un breve esempio di come gestire un marker per la realta' aumentata catturato da una WebCam e creare un oggetto 3D che interagisca con il marker, il tutto gestito all'interno di un browser (in questo caso Firefox...Chrome non ha funzionato ma credo che sia dovuto ai permessi della webcam)
La libreria di AR utilizzata e' stata ArucoJS, la versione javascript di una libreria disponibile anche in C
successivamente ho leggermente modificato l'esempio debug-posit presente nella cartella samples per generare un cubo al di sopra del marker con i comandi WebGL. Le modifiche, veramente minime, sono indicate dal segno giallo nel sorgente
Da notare che quando e' in esecuzione la pagina su Firefox, il processore entra in funzione in modo pesante con accensione delle ventole (su MacBook) e la pagina diventa un po' scattosa
il progetto puo' essere scaricato da questo link
---------------------------------------------------------------------------
<html>
<head>
<title>Augmented Reality</title>
<script type="text/javascript" src="libs/Three.js"></script>
<script type="text/javascript" src="svd.js"></script>
<script type="text/javascript" src="posit1.js"></script>
<script type="text/javascript" src="cv.js"></script>
<script type="text/javascript" src="aruco.js"></script>
<script>
var video, canvas, context, imageData, detector, posit;
var renderer1, renderer2, renderer3;
var scene1, scene2, scene3, scene4;
var camera1, camera2, camera3, camera4;
var plane1, plane2, model, texture;
var step = 0.0;
var modelSize = 35.0; //millimeters
function onLoad(){
video = document.getElementById("video");
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
canvas.width = parseInt(canvas.style.width);
canvas.height = parseInt(canvas.style.height);
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
if (navigator.getUserMedia){
init();
}
};
function init(){
navigator.getUserMedia({video:true},
function (stream){
if (window.webkitURL) {
video.src = window.webkitURL.createObjectURL(stream);
} else if (video.mozSrcObject !== undefined) {
video.mozSrcObject = stream;
} else {
video.src = stream;
}
},
function(error){
}
);
detector = new AR.Detector();
posit = new POS.Posit(modelSize, canvas.width);
createRenderers();
createScenes();
requestAnimationFrame(tick);
};
function tick(){
requestAnimationFrame(tick);
if (video.readyState === video.HAVE_ENOUGH_DATA){
snapshot();
var markers = detector.detect(imageData);
drawCorners(markers);
updateScenes(markers);
render();
}
};
function snapshot(){
context.drawImage(video, 0, 0, canvas.width, canvas.height);
imageData = context.getImageData(0, 0, canvas.width, canvas.height);
};
function drawCorners(markers){
var corners, corner, i, j;
context.lineWidth = 3;
for (i = 0; i < markers.length; ++ i){
corners = markers[i].corners;
context.strokeStyle = "red";
context.beginPath();
for (j = 0; j < corners.length; ++ j){
corner = corners[j];
context.moveTo(corner.x, corner.y);
corner = corners[(j + 1) % corners.length];
context.lineTo(corner.x, corner.y);
}
context.stroke();
context.closePath();
context.strokeStyle = "green";
context.strokeRect(corners[0].x - 2, corners[0].y - 2, 4, 4);
}
};
function createRenderers(){
renderer1 = new THREE.WebGLRenderer();
renderer1.setClearColorHex(0xffff00, 1);
renderer1.setSize(canvas.width, canvas.height);
document.getElementById("container1").appendChild(renderer1.domElement);
scene1 = new THREE.Scene();
camera1 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
scene1.add(camera1);
renderer2 = new THREE.WebGLRenderer();
renderer2.setClearColorHex(0xffff00, 1);
renderer2.setSize(canvas.width, canvas.height);
document.getElementById("container2").appendChild(renderer2.domElement);
scene2 = new THREE.Scene();
camera2 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
scene2.add(camera2);
renderer3 = new THREE.WebGLRenderer();
renderer3.setClearColorHex(0xffffff, 1);
renderer3.setSize(canvas.width, canvas.height);
document.getElementById("container").appendChild(renderer3.domElement);
scene3 = new THREE.Scene();
camera3 = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5);
scene3.add(camera3);
scene4 = new THREE.Scene();
camera4 = new THREE.PerspectiveCamera(40, canvas.width / canvas.height, 1, 1000);
scene4.add(camera4);
};
function render(){
renderer1.clear();
renderer1.render(scene1, camera1);
renderer2.clear();
renderer2.render(scene2, camera2);
renderer3.autoClear = false;
renderer3.clear();
renderer3.render(scene3, camera3);
renderer3.render(scene4, camera4);
};
function createScenes(){
plane1 = createPlane();
scene1.add(plane1);
plane2 = createPlane();
scene2.add(plane2);
texture = createTexture();
scene3.add(texture);
model = createModel();
scene4.add(model);
};
function createPlane(){
var object = new THREE.Object3D(),
geometry = new THREE.PlaneGeometry(1.0, 1.0, 0.0),
material = new THREE.MeshNormalMaterial(),
mesh = new THREE.Mesh(geometry, material);
object.add(mesh);
return object;
};
function createTexture(){
var texture = new THREE.Texture(video),
object = new THREE.Object3D(),
geometry = new THREE.PlaneGeometry(1.0, 1.0, 0.0),
material = new THREE.MeshBasicMaterial( {map: texture, depthTest: false, depthWrite: false} ),
mesh = new THREE.Mesh(geometry, material);
object.position.z = -1;
object.add(mesh);
return object;
};
function createModel(){
var object = new THREE.Object3D(),
cubo_geometry = new THREE.CubeGeometry(1,1,1),
cubo_material = new THREE.MeshNormalMaterial(),
mesh = new THREE.Mesh(cubo_geometry, cubo_material);
object.add(mesh);
return object;
};
function updateScenes(markers){
var corners, corner, pose, i;
if (markers.length > 0){
corners = markers[0].corners;
for (i = 0; i < corners.length; ++ i){
corner = corners[i];
corner.x = corner.x - (canvas.width / 2);
corner.y = (canvas.height / 2) - corner.y;
}
pose = posit.pose(corners);
updateObject(plane1, pose.bestRotation, pose.bestTranslation);
updateObject(plane2, pose.alternativeRotation, pose.alternativeTranslation);
updateObject(model, pose.bestRotation, pose.bestTranslation);
updatePose("pose1", pose.bestError, pose.bestRotation, pose.bestTranslation);
updatePose("pose2", pose.alternativeError, pose.alternativeRotation, pose.alternativeTranslation);
step += 0.025;
model.rotation.z -= step;
}
texture.children[0].material.map.needsUpdate = true;
};
function updateObject(object, rotation, translation){
object.scale.x = modelSize;
object.scale.y = modelSize;
object.scale.z = modelSize;
object.rotation.x = -Math.asin(-rotation[1][2]);
object.rotation.y = -Math.atan2(rotation[0][2], rotation[2][2]);
object.rotation.z = Math.atan2(rotation[1][0], rotation[1][1]);
object.position.x = translation[0];
object.position.y = translation[1];
object.position.z = -translation[2];
};
function updatePose(id, error, rotation, translation){
var yaw = -Math.atan2(rotation[0][2], rotation[2][2]);
var pitch = -Math.asin(-rotation[1][2]);
var roll = Math.atan2(rotation[1][0], rotation[1][1]);
var d = document.getElementById(id);
d.innerHTML = " error: " + error
+ "<br/>"
+ " x: " + (translation[0] | 0)
+ " y: " + (translation[1] | 0)
+ " z: " + (translation[2] | 0)
+ "<br/>"
+ " yaw: " + Math.round(-yaw * 180.0/Math.PI)
+ " pitch: " + Math.round(-pitch * 180.0/Math.PI)
+ " roll: " + Math.round(roll * 180.0/Math.PI);
};
window.onload = onLoad;
</script>
</head>
<body style="text-align: center; font-family: monospace;">
<video id="video" width=320 height=240 autoplay="true" style="display:none;"></video>
<div style="margin: 10px;"><strong>-= Augmented Reality =-</strong></div>
<div style="width: 100%;">
<div style="width: 650px; margin-left:auto; margin-right:auto;">
<canvas id="canvas" style="width: 320px; height: 240px; float: left; border: solid 1px black;"></canvas>
<div id="container" style="width: 320px; height: 240px; float: left; border: solid 1px black; background: green;"></div>
<div style="clear: both;"></div>
<div style="float: left; border: solid 1px black;">
<div id="container1" style="width: 320px; height: 240px; background: red;"></div>
<div id="pose1"></div>
</div>
<div style="float: left; border: solid 1px black;">
<div id="container2" style="width: 320px; height: 240px; background: blue;"></div>
<div id="pose2"></div>
</div>
</div>
</div>
<div style="clear: both;"></div>
<div style="margin: 15px;"><strong>Powered by <a href="http://code.google.com/p/js-aruco/">js-aruco</a> and <a href="https://github.com/mrdoob/three.js">Three.js</a></strong></div>
</body>
</html>