【问题标题】:Displaying multiple frames of a video element simultaneously同时显示视频元素的多个帧
【发布时间】:2024-01-05 00:29:01
【问题描述】:

一些背景知识:这里的图形新手,刚刚用 mrdoob 出色的 three.js 在浏览器中涉足 3D 世界。我打算很快通过http://learningwebgl.com/ 的所有tuts :)


我想知道如何大致重新创建类似于: http://yooouuutuuube.com/v/?width=192&height=120&vm=29755443&flux=0&direction=rand

我对 yooouuutuuube 工作原理的幼稚理解如下:

  1. 创建大量 BitmapData(大于任何合理的浏览器窗口大小)。
  2. 根据目标视频帧的宽度/高度确定所需的行数/列数(跨越整个 BitmapData 平面,而不仅仅是可见区域)
  3. 将最新视频帧中的像素复制到 BitmapData 上的某个位置(基于移动方向)
  4. 遍历 BitmapData 中的每个单元格,从其前面的单元格中复制像素
  5. 沿相反方向滚动整个 BitmapData 以创建运动错觉,具有 Zoetrope 类型的效果

我想在 WebGL 中执行此操作,而不是使用 Canvas,以便我可以利用着色器进行后处理(噪声和颜色通道分离以模拟色差)。

这是我目前的截图:

  • 三个视频(相同的视频,但分为 R、G 和 B 通道)被绘制到画布 2D 上下文中。每个视频都略微偏移,以伪造色差外观。
  • 在 Three.JS 中创建了一个纹理,它引用了这个画布。此纹理会在每个绘制周期更新。
  • 在 Three.JS 中创建一个着色器材质,该材质链接到片段着色器(创建噪声/扫描线)
  • 然后将此材质应用于多个 3D 平面。

这对于显示单帧视频效果很好,但我想看看是否可以一次显示多帧而不需要添加额外的几何图形。

完成此类任务的最佳方式是什么?是否有任何我应该进一步详细研究/研究的概念?

【问题讨论】:

    标签: javascript glsl webgl three.js


    【解决方案1】:
    <html>
        <body>
            <script>
    
                var video = document.createElement( 'video' );
                video.autoplay = true;
                video.addEventListener( 'loadedmetadata', function ( event ) {
    
                    var scale = 0.5;
                    var width = video.videoWidth * scale;
                    var height = video.videoHeight * scale;
                    var items_total = ( window.innerWidth * window.innerHeight ) / ( width * height );
    
                    for ( var i = 0; i < items_total - 1; i ++ ) {
    
                        var canvas = document.createElement( 'canvas' );
                        canvas.width = width;
                        canvas.height = height;
    
                        canvas.context = canvas.getContext( '2d' );
                        canvas.context.scale( scale, scale );
    
                        document.body.appendChild( canvas );
    
                    }
    
                    setInterval( function () {
    
                        var child = document.body.insertBefore( document.body.lastChild, document.body.children[ 1 ] ); // children[ 0 ] == <script>
                        child.context.drawImage( video, 0, 0 );
    
                    }, 1000 / 30 );
    
                }, false );
                video.src = 'video.ogv';
    
            </script>
        </body>
    </html>
    

    【讨论】:

    • 哦,我刚刚读到你想要 WebGL 用于后期处理的部分。嗯,我认为这应该是一个很好的基础。相同的技巧:每一帧只更新 1 个纹理,并重新交换所有平面。
    • 我想我肯定是以错误的方式思考问题——我希望提出一个可以包含在 ShaderMaterial 中的解决方案,然后将其应用于一个 PlaneGeometry,仅此而已. (......这甚至可能吗?)我将尝试使用您提供的内容作为基础并使用一些飞机来代替。感谢您的帮助。
    • @RobinPyon 是的,这是可能的。