对threejs官方案例webgl_kinect的思考

在上次按照自己的想法使用粒子系统对图片进行处理之后,我最近又看到了官方案例中,使用粒子使视频呈现出3D效果,既然是官方案例就需要仔细研究一下。

这是该案例的实现效果:可以看到屏幕中由粒子构成了一个人在整理桌面的东西,效果十分的酷炫,大家可以在官方案例中看到动态的效果。

官方案例地址:https://threejs.org/examples/#webgl_kinect


下面是我自己对于代码的分析:程序首先创建了一个video视频播放div,随后设置好该视频块的播放参数,当视频加载完成后将其当作材质,然后创建一个BufferGeometry对象,遍历行列贴图视频的长宽,给BufferGeometry对象赋值(该对象具有视频长像素个数*视频宽像素个数个点,这也是一种利用粒子系统的方法),x,y的值分别按照长方形平铺下去,z值不设置,将会在着色器里对其进行计算,显示出3D效果。

video = document.createElement( 'video' );
video.addEventListener( 'loadedmetadata', function ( event ) {    //视频纹理先加载完成

   texture = new THREE.VideoTexture( video );
   texture.minFilter = THREE.NearestFilter;                              //纹理缩放时采用最近点采样

   var width = 640, height = 480;
   var nearClipping = 850, farClipping = 4000;

   geometry = new THREE.BufferGeometry();                         //创建buffergeometry

   var vertices = new Float32Array( width * height * 3 );             //创建数组填充到buffergeometry中

   for ( var i = 0, j = 0, l = vertices.length; i < l; i += 3, j ++ ) {

      vertices[ i ] = j % width;                                           //x方向的值
      vertices[ i + 1 ] = Math.floor( j / width );                           //y方向的值,z方向的值为0

   }

   geometry.addAttribute( 'position', new THREE.BufferAttribute( vertices, 3 ) );
剩下一个重点就是片元着色器的处理,这里的处理很有意思,首先这个视频中人和物体的深度与颜色直接关联,颜色越浅深度与大,根据颜色的RGB值加和求出该点的z值偏移量(也就是深度变量),再给它乘以一个值,经过处理让相邻的点之间的距离不那么远。还有就是这里的uv展开没有直接使用默认着色器给定的uv值,而是经过计算,将每一个点对应video长宽的值。

<script id="vs" type="x-shader/x-vertex">

   uniform sampler2D map;

   uniform float width;
   uniform float height;
   uniform float nearClipping, farClipping;

   uniform float pointSize;
   uniform float zOffset;

   varying vec2 vUv;

   const float XtoZ = 1.11146; // tan( 1.0144686 / 2.0 ) * 2.0;
   const float YtoZ = 0.83359; // tan( 0.7898090 / 2.0 ) * 2.0;

   void main() {

      vUv = vec2( position.x / width, position.y / height );

      vec4 color = texture2D( map, vUv );
      float depth = ( color.r + color.g + color.b ) / 3.0;         //颜色越暗值越大啊

      // Projection code by @kcmic

      float z = ( 1.0 - depth ) * (farClipping - nearClipping) + nearClipping;//计算z值

      vec4 pos = vec4(
         ( position.x / width - 0.5 ) * z * XtoZ,      //让画面偏移不变形
         
         ( position.y / height - 0.5 ) * z * YtoZ,
         - z + zOffset,
         1.0);

      gl_PointSize = pointSize;
      gl_Position = projectionMatrix * modelViewMatrix * pos;

   }

</script>
如果想自己实现这个效果,不仅需要这样一段程序,更重要的还需要色彩与深度相关的视频作为辅助~下面是原始视频图片



总结:之前我使用THREE.point创建了很多个点,然后人为排列它们的位置,使其组成一幅图片,优点是方便了对于每一个粒子对象的控制,缺点是组成的图片间距需要自己调整,容易出现水波纹的现象。与我不同的是官方使用了BufferGeometry对象,方便了着色器的对其的控制,这种方法更加适合图片、视频纹理特效的呈现。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章