├── .gitignore ├── .gitmodules ├── README.md ├── dist ├── aframe.depthkit.js └── aframe.depthkit.min.js ├── docs ├── movement.gif └── screenshot.png ├── examples └── simple.html ├── package-lock.json ├── package.json └── src └── index.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "ext/DepthKit"] 2 | path = ext/DepthKit 3 | url = git@github.com:juniorxsound/DepthKit.js.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DepthKit for A-Frame 2 | [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) 3 | 4 | An A-Frame component for rendering [DepthKit](http://www.depthkit.tv) volumetric videos in WebVR. The A-Frame component wraps [DepthKit.js](https://github.com/juniorxsound/DepthKit.js) which is a small library that provides the same functionality for [Three.js](https://github.com/mrdoob/three.js) projects. 5 | - [Usage](#usage) 6 | - [Contribute](#contribute) 7 | 8 | ![DepthKit AFrame](https://raw.githubusercontent.com/juniorxsound/DepthKit-A-Frame/master/docs/movement.gif?token=APLD_It_uvXAHdio-sYe_JUHWQEXUHslks5aZRfAwA%3D%3D) 9 | 10 | ## Usage 11 | Start by cloning/forking the repository and including ```aframe.depthkit.min.js``` from the ```./dist``` folder (make sure to clone using ```--recursive``` flag if you plan to run the examples to clone the git submodules too) 12 | 13 | The simplest way you can initialize a DepthKit video is to create a ```depthkit``` entity inside an A-Frame ```a-scene``` tag: 14 | ```html 15 | 16 | 21 | 22 | 23 | ``` 24 | Where the ```type``` attribute support ```wire/points/mesh``` for rendering different styles, ```metaPath``` is the path to the ```.txt``` file with the parameters (exported by DepthKit Visualize) and ```videoPath``` is for the path to the video file. 25 | 26 | ## Contribute 27 | PRs are welcome ✊🏻 make sure to clone using the ```git clone --recursive```. 28 | 29 | ### Build system 30 | - ```npm run start``` uses ```concurrently``` to start both an ```http-server``` and a ```watchify``` build opreation on every save to ```./dist/aframe.depthkit.js``` 31 | - ```npm run build``` builds and minifies to ```./dist/aframe.depthkit.min.js``` 32 | -------------------------------------------------------------------------------- /dist/aframe.depthkit.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o _DepthSaturationThreshhold && depthsamplehsv.b > _DepthBrightnessThreshold ? depthsamplehsv.r : 0.0;\n}\n\nvoid main() {\n vec4 texSize = vec4(1.0 / width, 1.0 / height, width, height);\n\n vec2 centerpix = texSize.xy * .5;\n vec2 textureStep = 1.0 / meshDensity;\n vec2 basetex = floor(position.xy * textureStep * texSize.zw) * texSize.xy;\n vec2 imageCoordinates = crop.xy + (basetex * crop.zw);\n basetex.y = 1.0 - basetex.y;\n\n vec2 depthTexCoord = basetex * vec2(1.0, 0.5) + centerpix;\n vec2 colorTexCoord = basetex * vec2(1.0, 0.5) + vec2(0.0, 0.5) + centerpix;\n\n vUv = colorTexCoord;\n vPos = (modelMatrix * vec4(position, 1.0 )).xyz;\n vNormal = normalMatrix * normal;\n\n //check neighbors\n //texture coords come in as [0.0 - 1.0] for this whole plane\n float depth = depthForPoint(depthTexCoord);\n\n float neighborDepths[8];\n neighborDepths[0] = depthForPoint(depthTexCoord + vec2(0.0, textureStep.y));\n neighborDepths[1] = depthForPoint(depthTexCoord + vec2(textureStep.x, 0.0));\n neighborDepths[2] = depthForPoint(depthTexCoord + vec2(0.0, -textureStep.y));\n neighborDepths[3] = depthForPoint(depthTexCoord + vec2(-textureStep.x, 0.0));\n neighborDepths[4] = depthForPoint(depthTexCoord + vec2(-textureStep.x, -textureStep.y));\n neighborDepths[5] = depthForPoint(depthTexCoord + vec2(textureStep.x, textureStep.y));\n neighborDepths[6] = depthForPoint(depthTexCoord + vec2(textureStep.x, -textureStep.y));\n neighborDepths[7] = depthForPoint(depthTexCoord + vec2(-textureStep.x, textureStep.y));\n\n visibility = 1.0;\n int numDudNeighbors = 0;\n //search neighbor verts in order to see if we are near an edge\n //if so, clamp to the surface closest to us\n if (depth < _Epsilon || (1.0 - depth) < _Epsilon)\n {\n // float depthDif = 1.0;\n float nearestDepth = 1.0;\n for (int i = 0; i < 8; i++)\n {\n float depthNeighbor = neighborDepths[i];\n if (depthNeighbor >= _Epsilon && (1.0 - depthNeighbor) > _Epsilon)\n {\n // float thisDif = abs(nearestDepth - depthNeighbor);\n if (depthNeighbor < nearestDepth)\n {\n // depthDif = thisDif;\n nearestDepth = depthNeighbor;\n }\n }\n else\n {\n numDudNeighbors++;\n }\n }\n\n depth = nearestDepth;\n visibility = 0.8;\n\n // blob filter\n if (numDudNeighbors > 6)\n {\n visibility = 0.0;\n }\n }\n\n // internal edge filter\n float maxDisparity = 0.0;\n for (int i = 0; i < 8; i++)\n {\n float depthNeighbor = neighborDepths[i];\n if (depthNeighbor >= _Epsilon && (1.0 - depthNeighbor) > _Epsilon)\n {\n maxDisparity = max(maxDisparity, abs(depth - depthNeighbor));\n }\n }\n visibility *= 1.0 - maxDisparity;\n\n float z = depth * (maxdepth - mindepth) + mindepth;\n vec4 worldPos = extrinsics * vec4((imageCoordinates * imageDimensions - principalPoint) * z / focalLength, z, 1.0);\n worldPos.w = 1.0;\n\n gl_Position = projectionMatrix * modelViewMatrix * worldPos;\n}"]);switch (this.video = document.createElement("video"), this.video.id = "depthkit-video", this.video.crossOrigin = "anonymous", this.video.setAttribute("crossorigin", "anonymous"), this.video.setAttribute("webkit-playsinline", "webkit-playsinline"), this.video.setAttribute("playsinline", "playsinline"), this.video.src = i, this.video.autoplay = !1, this.video.loop = !1, this.video.load(), this.videoTexture = new THREE.VideoTexture(this.video), this.videoTexture.minFilter = THREE.NearestFilter, this.videoTexture.magFilter = THREE.LinearFilter, this.videoTexture.format = THREE.RGBFormat, this.videoTexture.generateMipmaps = !1, this.manager = new THREE.LoadingManager(), this.props, s.geo || s.buildGeomtery(), this.material = new THREE.ShaderMaterial({ uniforms: { map: { type: "t", value: this.videoTexture }, time: { type: "f", value: 0 }, mindepth: { type: "f", value: 0 }, maxdepth: { type: "f", value: 0 }, meshDensity: { value: new THREE.Vector2(l, h) }, focalLength: { value: new THREE.Vector2(1, 1) }, principalPoint: { value: new THREE.Vector2(1, 1) }, imageDimensions: { value: new THREE.Vector2(512, 828) }, extrinsics: { value: new THREE.Matrix4() }, crop: { value: new THREE.Vector4(0, 0, 1, 1) }, width: { type: "f", value: 0 }, height: { type: "f", value: 0 }, opacity: { type: "f", value: 1 }, isPoints: { type: "b", value: !1 }, pointSize: { type: "f", value: 3 } }, vertexShader: r, fragmentShader: n, transparent: !0 }), this.material.side = THREE.DoubleSide, e) {case "wire": 47 | this.material.wireframe = !0, this.mesh = new THREE.Mesh(s.geo, this.material);break;case "points": 48 | this.material.uniforms.isPoints.value = !0, this.mesh = new THREE.Points(s.geo, this.material);break;default: 49 | this.mesh = new THREE.Mesh(s.geo, this.material);}return this.jsonLoader = new THREE.FileLoader(this.manager), this.jsonLoader.setResponseType("json"), this.jsonLoader.load(t, function (e) { 50 | o.props = e, o.material.uniforms.width.value = o.props.textureWidth, o.material.uniforms.height.value = o.props.textureHeight, o.material.uniforms.mindepth.value = o.props.nearClip, o.material.uniforms.maxdepth.value = o.props.farClip, o.material.uniforms.focalLength.value = o.props.depthFocalLength, o.material.uniforms.principalPoint.value = o.props.depthPrincipalPoint, o.material.uniforms.imageDimensions.value = o.props.depthImageSize, o.material.uniforms.crop.value = o.props.crop;var t = o.props.extrinsics;o.material.uniforms.extrinsics.value.set(t.e00, t.e10, t.e20, t.e30, t.e01, t.e11, t.e21, t.e31, t.e02, t.e12, t.e22, t.e32, t.e03, t.e13, t.e23, t.e33);var i = new THREE.BoxGeometry(o.props.boundsSize.x, o.props.boundsSize.y, o.props.boundsSize.z), 51 | n = new THREE.MeshBasicMaterial({ color: 16776960, wireframe: !0 });o.collider = new THREE.Mesh(i, n), o.collider.visible = !1, o.mesh.add(o.collider), THREE.SceneUtils.detach(o.collider, o.mesh, o.mesh.parent), o.collider.position.set(0, 1, 0); 52 | }), this.mesh.frustumCulled = !1, (this.mesh.depthkit = this).mesh.name = "depthkit", this.mesh; 53 | }return n(s, [{ key: "setPointSize", value: function value(e) { 54 | this.material.uniforms.isPoints.value ? this.material.uniforms.pointSize.value = e : console.warn("Can not set point size because the current character is not set to render points"); 55 | } }, { key: "setOpacity", value: function value(e) { 56 | this.material.uniforms.opacity.value = e; 57 | } }, { key: "setLineWidth", value: function value(e) { 58 | this.material.wireframe ? this.material.wireframeLinewidth = e : console.warn("Can not set the line width because the current character is not set to render wireframe"); 59 | } }, { key: "play", value: function value() { 60 | this.video.isPlaying ? console.warn("Can not play because the character is already playing") : this.video.play(); 61 | } }, { key: "stop", value: function value() { 62 | this.video.currentTime = 0, this.video.pause(); 63 | } }, { key: "pause", value: function value() { 64 | this.video.pause(); 65 | } }, { key: "setLoop", value: function value(e) { 66 | this.video.loop = e; 67 | } }, { key: "setVolume", value: function value(e) { 68 | this.video.volume = e; 69 | } }, { key: "update", value: function value(e) { 70 | this.material.uniforms.time.value = e; 71 | } }, { key: "toggleColliderVisiblity", value: function value() { 72 | this.mesh.collider.visible = !this.mesh.collider.visible; 73 | } }, { key: "dispose", value: function value() { 74 | try { 75 | this.mesh.parent.remove(this.mesh); 76 | } catch (e) { 77 | console.warn(e); 78 | } finally { 79 | this.mesh.traverse(function (e) { 80 | void 0 !== e.geometry && (e.geometry.dispose(), e.material.dispose()); 81 | }); 82 | } 83 | } }], [{ key: "buildGeomtery", value: function value() { 84 | s.geo = new THREE.Geometry();for (var e = 0; e < h; e++) { 85 | for (var t = 0; t < l; t++) { 86 | s.geo.vertices.push(new THREE.Vector3(t, e, 0)); 87 | } 88 | }for (var i = 0; i < h - 1; i++) { 89 | for (var n = 0; n < l - 1; n++) { 90 | s.geo.faces.push(new THREE.Face3(n + i * l, n + (i + 1) * l, n + 1 + i * l)), s.geo.faces.push(new THREE.Face3(n + 1 + i * l, n + (i + 1) * l, n + 1 + (i + 1) * l)); 91 | } 92 | } 93 | } }]), s; 94 | }();i.default = o; 95 | }, { glslify: 1 }], 3: [function (e, t, i) { 96 | "use strict"; 97 | Object.defineProperty(i, "__esModule", { value: !0 }), i.DepthKit = void 0;var n, 98 | o = "function" == typeof Symbol && "symbol" == _typeof(Symbol.iterator) ? function (e) { 99 | return typeof e === "undefined" ? "undefined" : _typeof(e); 100 | } : function (e) { 101 | return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e === "undefined" ? "undefined" : _typeof(e); 102 | }, 103 | r = e("./depthkit"), 104 | s = (n = r) && n.__esModule ? n : { default: n };"undefined" != typeof window && "object" === o(window.THREE) ? window.DepthKit = s.default : console.warn("[DepthKit.js] It seems like THREE is not included in your code, try including it before DepthKit.js"), i.DepthKit = s.default; 105 | }, { "./depthkit": 2 }] }, {}, [3]); 106 | 107 | //Make sure AFrame is available 108 | if (typeof AFRAME === 'undefined') { 109 | throw new Error('Component attempted to register before AFRAME was available.'); 110 | } 111 | 112 | //AFrame DepthKit.js wrapper entity 113 | AFRAME.registerComponent('depthkit', { 114 | 115 | schema: { 116 | type: { type: 'string', default: 'mesh' }, 117 | videoPath: { type: 'string' }, 118 | metaPath: { type: 'string' }, 119 | loop: { type: 'boolean', default: true }, 120 | autoplay: { type: 'boolean', default: true } 121 | }, 122 | 123 | /** 124 | * Set if component needs multiple instancing. 125 | */ 126 | multiple: true, 127 | 128 | /** 129 | * Called once when component is attached. Generally for initial setup. 130 | */ 131 | init: function init() { 132 | 133 | //Create a depthkit instance 134 | var character = new DepthKit(this.data.type, this.data.metaPath, this.data.videoPath); 135 | //Will it loop? 136 | character.depthkit.setLoop(this.data.loop); 137 | 138 | //Rotate it back to position 139 | character.rotation.z = THREE.Math.degToRad(90); 140 | 141 | //If autoplay is on play the take 142 | if (this.data.autoplay) character.depthkit.play(); 143 | 144 | //Set the Object3D 145 | this.el.setObject3D('mesh', character); 146 | 147 | //Translate it so it is in front of you at eye level 148 | this.el.object3D.scale.multiplyScalar(0.001); 149 | this.el.object3D.position.z = -2; 150 | this.el.object3D.position.y = 1; 151 | }, 152 | 153 | /** 154 | * Called when component is attached and when component data changes. 155 | * Generally modifies the entity based on the data. 156 | */ 157 | update: function update(oldData) {}, 158 | 159 | /** 160 | * Called when a component is removed (e.g., via removeAttribute). 161 | * Generally undoes all modifications to the entity. 162 | */ 163 | remove: function remove() {}, 164 | 165 | /** 166 | * Called on each scene tick. 167 | */ 168 | // tick: function (t) { }, 169 | 170 | /** 171 | * Called when entity pauses. 172 | * Use to stop or remove any dynamic or background behavior such as events. 173 | */ 174 | pause: function pause() {}, 175 | 176 | /** 177 | * Called when entity resumes. 178 | * Use to continue or add any dynamic or background behavior such as events. 179 | */ 180 | play: function play() {} 181 | }); 182 | 183 | },{}]},{},[1]); 184 | -------------------------------------------------------------------------------- /dist/aframe.depthkit.min.js: -------------------------------------------------------------------------------- 1 | !function e(t,i,n){function o(a,s){if(!i[a]){if(!t[a]){var l="function"==typeof require&&require;if(!s&&l)return l(a,!0);if(r)return r(a,!0);var p=new Error("Cannot find module '"+a+"'");throw p.code="MODULE_NOT_FOUND",p}var h=i[a]={exports:{}};t[a][0].call(h.exports,function(e){var i=t[a][1][e];return o(i||e)},h,h.exports,e,t,i,n)}return i[a].exports}for(var r="function"==typeof require&&require,a=0;a _DepthSaturationThreshhold && depthsamplehsv.b > _DepthBrightnessThreshold ? depthsamplehsv.r : 0.0;\n}\n\nvoid main() {\n vec4 texSize = vec4(1.0 / width, 1.0 / height, width, height);\n\n vec2 centerpix = texSize.xy * .5;\n vec2 textureStep = 1.0 / meshDensity;\n vec2 basetex = floor(position.xy * textureStep * texSize.zw) * texSize.xy;\n vec2 imageCoordinates = crop.xy + (basetex * crop.zw);\n basetex.y = 1.0 - basetex.y;\n\n vec2 depthTexCoord = basetex * vec2(1.0, 0.5) + centerpix;\n vec2 colorTexCoord = basetex * vec2(1.0, 0.5) + vec2(0.0, 0.5) + centerpix;\n\n vUv = colorTexCoord;\n vPos = (modelMatrix * vec4(position, 1.0 )).xyz;\n vNormal = normalMatrix * normal;\n\n //check neighbors\n //texture coords come in as [0.0 - 1.0] for this whole plane\n float depth = depthForPoint(depthTexCoord);\n\n float neighborDepths[8];\n neighborDepths[0] = depthForPoint(depthTexCoord + vec2(0.0, textureStep.y));\n neighborDepths[1] = depthForPoint(depthTexCoord + vec2(textureStep.x, 0.0));\n neighborDepths[2] = depthForPoint(depthTexCoord + vec2(0.0, -textureStep.y));\n neighborDepths[3] = depthForPoint(depthTexCoord + vec2(-textureStep.x, 0.0));\n neighborDepths[4] = depthForPoint(depthTexCoord + vec2(-textureStep.x, -textureStep.y));\n neighborDepths[5] = depthForPoint(depthTexCoord + vec2(textureStep.x, textureStep.y));\n neighborDepths[6] = depthForPoint(depthTexCoord + vec2(textureStep.x, -textureStep.y));\n neighborDepths[7] = depthForPoint(depthTexCoord + vec2(-textureStep.x, textureStep.y));\n\n visibility = 1.0;\n int numDudNeighbors = 0;\n //search neighbor verts in order to see if we are near an edge\n //if so, clamp to the surface closest to us\n if (depth < _Epsilon || (1.0 - depth) < _Epsilon)\n {\n // float depthDif = 1.0;\n float nearestDepth = 1.0;\n for (int i = 0; i < 8; i++)\n {\n float depthNeighbor = neighborDepths[i];\n if (depthNeighbor >= _Epsilon && (1.0 - depthNeighbor) > _Epsilon)\n {\n // float thisDif = abs(nearestDepth - depthNeighbor);\n if (depthNeighbor < nearestDepth)\n {\n // depthDif = thisDif;\n nearestDepth = depthNeighbor;\n }\n }\n else\n {\n numDudNeighbors++;\n }\n }\n\n depth = nearestDepth;\n visibility = 0.8;\n\n // blob filter\n if (numDudNeighbors > 6)\n {\n visibility = 0.0;\n }\n }\n\n // internal edge filter\n float maxDisparity = 0.0;\n for (int i = 0; i < 8; i++)\n {\n float depthNeighbor = neighborDepths[i];\n if (depthNeighbor >= _Epsilon && (1.0 - depthNeighbor) > _Epsilon)\n {\n maxDisparity = max(maxDisparity, abs(depth - depthNeighbor));\n }\n }\n visibility *= 1.0 - maxDisparity;\n\n float z = depth * (maxdepth - mindepth) + mindepth;\n vec4 worldPos = extrinsics * vec4((imageCoordinates * imageDimensions - principalPoint) * z / focalLength, z, 1.0);\n worldPos.w = 1.0;\n\n gl_Position = projectionMatrix * modelViewMatrix * worldPos;\n}"]);switch(this.video=document.createElement("video"),this.video.id="depthkit-video",this.video.crossOrigin="anonymous",this.video.setAttribute("crossorigin","anonymous"),this.video.setAttribute("webkit-playsinline","webkit-playsinline"),this.video.setAttribute("playsinline","playsinline"),this.video.src=s,this.video.autoplay=!1,this.video.loop=!1,this.video.load(),this.videoTexture=new THREE.VideoTexture(this.video),this.videoTexture.minFilter=THREE.NearestFilter,this.videoTexture.magFilter=THREE.LinearFilter,this.videoTexture.format=THREE.RGBFormat,this.videoTexture.generateMipmaps=!1,this.manager=new THREE.LoadingManager,this.props,e.geo||e.buildGeomtery(),this.material=new THREE.ShaderMaterial({uniforms:{map:{type:"t",value:this.videoTexture},time:{type:"f",value:0},mindepth:{type:"f",value:0},maxdepth:{type:"f",value:0},meshDensity:{value:new THREE.Vector2(r,a)},focalLength:{value:new THREE.Vector2(1,1)},principalPoint:{value:new THREE.Vector2(1,1)},imageDimensions:{value:new THREE.Vector2(512,828)},extrinsics:{value:new THREE.Matrix4},crop:{value:new THREE.Vector4(0,0,1,1)},width:{type:"f",value:0},height:{type:"f",value:0},opacity:{type:"f",value:1},isPoints:{type:"b",value:!1},pointSize:{type:"f",value:3}},vertexShader:p,fragmentShader:l,transparent:!0}),this.material.side=THREE.DoubleSide,t){case"wire":this.material.wireframe=!0,this.mesh=new THREE.Mesh(e.geo,this.material);break;case"points":this.material.uniforms.isPoints.value=!0,this.mesh=new THREE.Points(e.geo,this.material);break;default:this.mesh=new THREE.Mesh(e.geo,this.material)}return this.jsonLoader=new THREE.FileLoader(this.manager),this.jsonLoader.setResponseType("json"),this.jsonLoader.load(i,function(e){n.props=e,n.material.uniforms.width.value=n.props.textureWidth,n.material.uniforms.height.value=n.props.textureHeight,n.material.uniforms.mindepth.value=n.props.nearClip,n.material.uniforms.maxdepth.value=n.props.farClip,n.material.uniforms.focalLength.value=n.props.depthFocalLength,n.material.uniforms.principalPoint.value=n.props.depthPrincipalPoint,n.material.uniforms.imageDimensions.value=n.props.depthImageSize,n.material.uniforms.crop.value=n.props.crop;var t=n.props.extrinsics;n.material.uniforms.extrinsics.value.set(t.e00,t.e10,t.e20,t.e30,t.e01,t.e11,t.e21,t.e31,t.e02,t.e12,t.e22,t.e32,t.e03,t.e13,t.e23,t.e33);var i=new THREE.BoxGeometry(n.props.boundsSize.x,n.props.boundsSize.y,n.props.boundsSize.z),o=new THREE.MeshBasicMaterial({color:16776960,wireframe:!0});n.collider=new THREE.Mesh(i,o),n.collider.visible=!1,n.mesh.add(n.collider),THREE.SceneUtils.detach(n.collider,n.mesh,n.mesh.parent),n.collider.position.set(0,1,0)}),this.mesh.frustumCulled=!1,(this.mesh.depthkit=this).mesh.name="depthkit",this.mesh}return n(e,[{key:"setPointSize",value:function(e){this.material.uniforms.isPoints.value?this.material.uniforms.pointSize.value=e:console.warn("Can not set point size because the current character is not set to render points")}},{key:"setOpacity",value:function(e){this.material.uniforms.opacity.value=e}},{key:"setLineWidth",value:function(e){this.material.wireframe?this.material.wireframeLinewidth=e:console.warn("Can not set the line width because the current character is not set to render wireframe")}},{key:"play",value:function(){this.video.isPlaying?console.warn("Can not play because the character is already playing"):this.video.play()}},{key:"stop",value:function(){this.video.currentTime=0,this.video.pause()}},{key:"pause",value:function(){this.video.pause()}},{key:"setLoop",value:function(e){this.video.loop=e}},{key:"setVolume",value:function(e){this.video.volume=e}},{key:"update",value:function(e){this.material.uniforms.time.value=e}},{key:"toggleColliderVisiblity",value:function(){this.mesh.collider.visible=!this.mesh.collider.visible}},{key:"dispose",value:function(){try{this.mesh.parent.remove(this.mesh)}catch(e){console.warn(e)}finally{this.mesh.traverse(function(e){void 0!==e.geometry&&(e.geometry.dispose(),e.material.dispose())})}}}],[{key:"buildGeomtery",value:function(){e.geo=new THREE.Geometry;for(var t=0;t 2 | 3 | A-Frame DepthKit 4 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aframe-depthkit", 3 | "version": "0.0.2", 4 | "description": "An A-Frame component for rendering DepthKit volumetric videos in WebVR", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "start": "concurrently \"http-server -s --cors\" \"watchify src/index.js -o dist/aframe.depthkit.js -v\"", 8 | "build": "browserify src/index.js | uglifyjs -mc warnings=false > dist/aframe.depthkit.min.js", 9 | "test": "npm run build" 10 | }, 11 | "keywords": [ 12 | "aframe", 13 | "three.js", 14 | "volumetric", 15 | "3D", 16 | "depthkit" 17 | ], 18 | "repository": { 19 | "type": "git", 20 | "url": "https://github.com/juniorxsound/DepthKit-A-Frame" 21 | }, 22 | "author": "Or Fleisher ", 23 | "license": "MIT", 24 | "dependencies": { 25 | "aframe": "^0.7.1" 26 | }, 27 | "devDependencies": { 28 | "babel-core": "^6.26.0", 29 | "babel-preset-env": "^1.6.1", 30 | "babelify": "^8.0.0", 31 | "browserify": "^15.1.0", 32 | "concurrently": "^3.5.1", 33 | "uglify-js": "^3.3.5", 34 | "watchify": "^3.9.0" 35 | }, 36 | "browserify": { 37 | "transform": [ 38 | [ 39 | "babelify", 40 | { 41 | "presets": [ 42 | "env" 43 | ] 44 | } 45 | ] 46 | ] 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | //Depthkit.js minified 2 | !function r(s,a,l){function h(i,e){if(!a[i]){if(!s[i]){var t="function"==typeof require&&require;if(!e&&t)return t(i,!0);if(p)return p(i,!0);var n=new Error("Cannot find module '"+i+"'");throw n.code="MODULE_NOT_FOUND",n}var o=a[i]={exports:{}};s[i][0].call(o.exports,function(e){var t=s[i][1][e];return h(t||e)},o,o.exports,r,s,a,l)}return a[i].exports}for(var p="function"==typeof require&&require,e=0;e _DepthSaturationThreshhold && depthsamplehsv.b > _DepthBrightnessThreshold ? depthsamplehsv.r : 0.0;\n}\n\nvoid main() {\n vec4 texSize = vec4(1.0 / width, 1.0 / height, width, height);\n\n vec2 centerpix = texSize.xy * .5;\n vec2 textureStep = 1.0 / meshDensity;\n vec2 basetex = floor(position.xy * textureStep * texSize.zw) * texSize.xy;\n vec2 imageCoordinates = crop.xy + (basetex * crop.zw);\n basetex.y = 1.0 - basetex.y;\n\n vec2 depthTexCoord = basetex * vec2(1.0, 0.5) + centerpix;\n vec2 colorTexCoord = basetex * vec2(1.0, 0.5) + vec2(0.0, 0.5) + centerpix;\n\n vUv = colorTexCoord;\n vPos = (modelMatrix * vec4(position, 1.0 )).xyz;\n vNormal = normalMatrix * normal;\n\n //check neighbors\n //texture coords come in as [0.0 - 1.0] for this whole plane\n float depth = depthForPoint(depthTexCoord);\n\n float neighborDepths[8];\n neighborDepths[0] = depthForPoint(depthTexCoord + vec2(0.0, textureStep.y));\n neighborDepths[1] = depthForPoint(depthTexCoord + vec2(textureStep.x, 0.0));\n neighborDepths[2] = depthForPoint(depthTexCoord + vec2(0.0, -textureStep.y));\n neighborDepths[3] = depthForPoint(depthTexCoord + vec2(-textureStep.x, 0.0));\n neighborDepths[4] = depthForPoint(depthTexCoord + vec2(-textureStep.x, -textureStep.y));\n neighborDepths[5] = depthForPoint(depthTexCoord + vec2(textureStep.x, textureStep.y));\n neighborDepths[6] = depthForPoint(depthTexCoord + vec2(textureStep.x, -textureStep.y));\n neighborDepths[7] = depthForPoint(depthTexCoord + vec2(-textureStep.x, textureStep.y));\n\n visibility = 1.0;\n int numDudNeighbors = 0;\n //search neighbor verts in order to see if we are near an edge\n //if so, clamp to the surface closest to us\n if (depth < _Epsilon || (1.0 - depth) < _Epsilon)\n {\n // float depthDif = 1.0;\n float nearestDepth = 1.0;\n for (int i = 0; i < 8; i++)\n {\n float depthNeighbor = neighborDepths[i];\n if (depthNeighbor >= _Epsilon && (1.0 - depthNeighbor) > _Epsilon)\n {\n // float thisDif = abs(nearestDepth - depthNeighbor);\n if (depthNeighbor < nearestDepth)\n {\n // depthDif = thisDif;\n nearestDepth = depthNeighbor;\n }\n }\n else\n {\n numDudNeighbors++;\n }\n }\n\n depth = nearestDepth;\n visibility = 0.8;\n\n // blob filter\n if (numDudNeighbors > 6)\n {\n visibility = 0.0;\n }\n }\n\n // internal edge filter\n float maxDisparity = 0.0;\n for (int i = 0; i < 8; i++)\n {\n float depthNeighbor = neighborDepths[i];\n if (depthNeighbor >= _Epsilon && (1.0 - depthNeighbor) > _Epsilon)\n {\n maxDisparity = max(maxDisparity, abs(depth - depthNeighbor));\n }\n }\n visibility *= 1.0 - maxDisparity;\n\n float z = depth * (maxdepth - mindepth) + mindepth;\n vec4 worldPos = extrinsics * vec4((imageCoordinates * imageDimensions - principalPoint) * z / focalLength, z, 1.0);\n worldPos.w = 1.0;\n\n gl_Position = projectionMatrix * modelViewMatrix * worldPos;\n}"]);switch(this.video=document.createElement("video"),this.video.id="depthkit-video",this.video.crossOrigin="anonymous",this.video.setAttribute("crossorigin","anonymous"),this.video.setAttribute("webkit-playsinline","webkit-playsinline"),this.video.setAttribute("playsinline","playsinline"),this.video.src=i,this.video.autoplay=!1,this.video.loop=!1,this.video.load(),this.videoTexture=new THREE.VideoTexture(this.video),this.videoTexture.minFilter=THREE.NearestFilter,this.videoTexture.magFilter=THREE.LinearFilter,this.videoTexture.format=THREE.RGBFormat,this.videoTexture.generateMipmaps=!1,this.manager=new THREE.LoadingManager,this.props,s.geo||s.buildGeomtery(),this.material=new THREE.ShaderMaterial({uniforms:{map:{type:"t",value:this.videoTexture},time:{type:"f",value:0},mindepth:{type:"f",value:0},maxdepth:{type:"f",value:0},meshDensity:{value:new THREE.Vector2(l,h)},focalLength:{value:new THREE.Vector2(1,1)},principalPoint:{value:new THREE.Vector2(1,1)},imageDimensions:{value:new THREE.Vector2(512,828)},extrinsics:{value:new THREE.Matrix4},crop:{value:new THREE.Vector4(0,0,1,1)},width:{type:"f",value:0},height:{type:"f",value:0},opacity:{type:"f",value:1},isPoints:{type:"b",value:!1},pointSize:{type:"f",value:3}},vertexShader:r,fragmentShader:n,transparent:!0}),this.material.side=THREE.DoubleSide,e){case"wire":this.material.wireframe=!0,this.mesh=new THREE.Mesh(s.geo,this.material);break;case"points":this.material.uniforms.isPoints.value=!0,this.mesh=new THREE.Points(s.geo,this.material);break;default:this.mesh=new THREE.Mesh(s.geo,this.material)}return this.jsonLoader=new THREE.FileLoader(this.manager),this.jsonLoader.setResponseType("json"),this.jsonLoader.load(t,function(e){o.props=e,o.material.uniforms.width.value=o.props.textureWidth,o.material.uniforms.height.value=o.props.textureHeight,o.material.uniforms.mindepth.value=o.props.nearClip,o.material.uniforms.maxdepth.value=o.props.farClip,o.material.uniforms.focalLength.value=o.props.depthFocalLength,o.material.uniforms.principalPoint.value=o.props.depthPrincipalPoint,o.material.uniforms.imageDimensions.value=o.props.depthImageSize,o.material.uniforms.crop.value=o.props.crop;var t=o.props.extrinsics;o.material.uniforms.extrinsics.value.set(t.e00,t.e10,t.e20,t.e30,t.e01,t.e11,t.e21,t.e31,t.e02,t.e12,t.e22,t.e32,t.e03,t.e13,t.e23,t.e33);var i=new THREE.BoxGeometry(o.props.boundsSize.x,o.props.boundsSize.y,o.props.boundsSize.z),n=new THREE.MeshBasicMaterial({color:16776960,wireframe:!0});o.collider=new THREE.Mesh(i,n),o.collider.visible=!1,o.mesh.add(o.collider),THREE.SceneUtils.detach(o.collider,o.mesh,o.mesh.parent),o.collider.position.set(0,1,0)}),this.mesh.frustumCulled=!1,(this.mesh.depthkit=this).mesh.name="depthkit",this.mesh}return n(s,[{key:"setPointSize",value:function(e){this.material.uniforms.isPoints.value?this.material.uniforms.pointSize.value=e:console.warn("Can not set point size because the current character is not set to render points")}},{key:"setOpacity",value:function(e){this.material.uniforms.opacity.value=e}},{key:"setLineWidth",value:function(e){this.material.wireframe?this.material.wireframeLinewidth=e:console.warn("Can not set the line width because the current character is not set to render wireframe")}},{key:"play",value:function(){this.video.isPlaying?console.warn("Can not play because the character is already playing"):this.video.play()}},{key:"stop",value:function(){this.video.currentTime=0,this.video.pause()}},{key:"pause",value:function(){this.video.pause()}},{key:"setLoop",value:function(e){this.video.loop=e}},{key:"setVolume",value:function(e){this.video.volume=e}},{key:"update",value:function(e){this.material.uniforms.time.value=e}},{key:"toggleColliderVisiblity",value:function(){this.mesh.collider.visible=!this.mesh.collider.visible}},{key:"dispose",value:function(){try{this.mesh.parent.remove(this.mesh)}catch(e){console.warn(e)}finally{this.mesh.traverse(function(e){void 0!==e.geometry&&(e.geometry.dispose(),e.material.dispose())})}}}],[{key:"buildGeomtery",value:function(){s.geo=new THREE.Geometry;for(var e=0;e