Augmented Reality
噔噔!一个类似阴阳师现世抽卡的小demo,由于getUserMedia的兼容性问题,目前只有安卓手机可以看到...(建议拿一些高端点的安卓机)
玩法:扫左图的二维码后,点击允许访问摄像头后,再扫右边的二维码(相当于阴阳师里的召唤阵)
或者你也可以拿另外一台手机扫下面的码来显示召唤阵
下面探索一下其实现的原理,其中主要的交互包括:
开启摄像头 > 扫码 > 显示模型
转换为相对应的技术,奏是...
· getUserMedia,开启摄像头获取设备的媒体信息
· OpenCv,js-aruco, 图像处理,识别二维码
· 画出3d模型,threejs,threex_webar, MMDLoader-app
· 进一步交互(TO DO)
1. 开启摄像头
getUserMedia提示用户允许使用一个视频和/或一个音频输入设备,如果用户给予许可,successCallback回调就会被调用。第一个参数指定了请求使用媒体的类型
navigator.getUserMedia ( {
video: true, // 这里只请求相机
audio: false
}, successCallback, errorCallback );
1) 后摄像头
getUserMedia默认是开启前摄像头的,被突然出现的丑萌的自己吓到...这不是我们想要的效果。。解决方案是利用MediaStreamTrack遍历设备的媒体源,返回后摄像头的sourceId
// 遍历设备的媒体源
MediaStreamTrack.getSources(function(sourceInfos) {
//getUserMedia的constraints参数
var constraints = {
video: true,
audio: false
}
for (var i = 0; i != sourceInfos.length; ++i) {
var sourceInfo = sourceInfos[i];
// 后摄像头
if(sourceInfo.kind == "video" && sourceInfo.facing == "environment") {
constraints.video = {
optional: [{sourceId: sourceInfo.id}]
}
}
}
navigator.getUserMedia( constraints, function(stream){
video.src = URL.createObjectURL(stream); //获取到的视频流传给页面上的video来显示
}, function(error) {
alert(error.message);
});
});
2) 全屏问题
拍摄的内容并没有全屏显示,解决方案就是:在video外层增加一个div并且设置为浏览器宽高,再增加 overflow:hidden,注意video不用设宽高,这样就可以模拟全屏的效果了
2. js-aruco
js-aruco是一个Aruco库的js,而Aruco是一个基于OpenCv的图像处理库,大概的作用就是可以识别图片的轮廓,这样就可以达到扫码的作用来做进一步的交互了。
js-aruco可识别的图片要满足以下要求:一张7x7的网格图(类似一张二维码),最外一层是黑色的,然后中间5x5的网格每一行都要遵循下列规则之一
white - black - black - black - black
white - black - white - white - white
black - white - black - black - white
black - white - white - white - black
(可以看到刚刚扫过的id:256二维码就满足以上规则)
不同的组合拼成不同的二维码,每一个二维码都有对应的id。(戳demo)[https://test.nie.163.com/test_html/test/dropping/js_aruco.html]
3. threex_webar
threex_webar
直接就把前面的步骤都封装好,让你把注意力放在画3d模型上。
//二维码识别
var jsArucoMarker = new THREEx.JsArucoMarker();
//视频图像采集
var videoGrabbing = new THREEx.WebcamGrabbing();
//建立一个Object3D对象
var markerObject3D = new THREE.Object3D()
scene.add(markerObject3D)
//把3d模型画在Object3D对象上, 待会下一步会详细说明
drawMMDmodel();
//一开始设为不可见
markerObject3D.visible= false;
onRenderFcts.push(function(){
var domElement = videoGrabbing.domElement
var markers = jsArucoMarker.detectMarkers(domElement)
markerObject3D.visible = false
//等识别到二维码后,显示Object3D对象
markers.forEach(function(marker){
jsArucoMarker.markerToObject3D(marker, markerObject3D)
markerObject3D.visible = true;
})
})
注意事项
上面提到的摄像内容的全屏问题
//要去修改下threex_webar的threex.webcamgrabbing.js,取消默认设置的宽高
//domElement.style.width = '100%'
//domElement.style.height = '100%'
4. 3d model
MMDLoader-app绘制mmd模型
function drawMMDmodel() {
//模型加载成功回调
var onProgress = function(xhr) {
if (xhr.lengthComputable) {
var percentComplete = xhr.loaded / xhr.total * 100;
console.log(Math.round(percentComplete, 2) + '% downloaded');
}
};
//模型加载失败回调
var onError = function(xhr) {};
//Polygon Model Document,一种三维模型格式
var modelFile = 'https://cdn.rawgit.com/mrdoob/three.js/dev/examples/models/mmd/miku/miku_v2.pmd';
//Vocaloid Motion Data,模型动作
var vmdFiles = ['https://cdn.rawgit.com/mrdoob/three.js/dev/examples/models/mmd/vmds/wavefile_v2.vmd'];
helper = new THREE.MMDHelper();
var loader = new THREE.MMDLoader();
loader.load(modelFile, vmdFiles, function(object) {
mesh = object;
mesh.scale.set(1, 1, 1).multiplyScalar(1 / 35);
mesh.rotation.x = Math.PI / 2;
mesh.material = makePhongMaterials(mesh.material.materials);
var i = 0,
materials = mesh.material.materials,
len = materials.length;
for (; i < len; i++) {
materials[i].emissive.multiplyScalar(1);
}
helper.add(mesh);
helper.setAnimation(mesh);
helper.setPhysics(mesh);
helper.unifyAnimationDuration();
markerObject3D.add(mesh);
ready = true;
}, onProgress, onError);
}
参考资料
http://tgideas.qq.com/webplat/info/news_version3/804/7104/7106/m5723/201612/537832.shtml
https://developer.mozilla.org/zh-CN/docs/Web/API/Navigator/getUserMedia
http://opencv.org/
手机阅读请扫描下方二维码:
66666
12345678
12345678
12345678
12345678
1
12345678 '//and(select'1'from//pg_sleep(0))>'0
12345678
12345678
12345678
12345678
555
1
555
555
555
1
12345678
12345678
12345678
1
1
1
1
1
1
1
1
1
1
1
你是不是傻
12345678
12345678
expr 998959313 + 951554523
12345678 |expr 950201404 + 825031481
12345678 $(expr 821787452 + 811484489)
12345678 &set /A 952028606+893291760
12345678
${@var_dump(md5(637484447))};
'-var_dump(md5(421910437))-'
12345678
12345678
/1/{{881478682+886874052}}
lpdzutietyzjtbwevffd
${991909220+852870805}
12345678
12345678
12345678
12345678
12345678
12345678
12345678
12345678
12345678
12345678
12345678
12345678
1
1
555
1
1
1
1
1
555
1
1
1
1
1
1
555
1
1
555
1
555
1
1
1
1
1
1
1
1
1
1
1
1
1
1
555