【问题标题】:Three.js: texture to datatextureThree.js:纹理到数据纹理
【发布时间】:2012-09-17 04:06:48
【问题描述】:

我正在尝试在 javascript 中实现延迟的网络摄像头查看器,使用 Three.js 实现 WebGL 功能。

我需要存储从网络摄像头抓取的帧,以便它们可以在一段时间后显示(几毫秒到几秒)。我可以在没有 Three.js 的情况下使用canvasgetImageData() 来做到这一点。你可以找到an example on jsfidle

我正在尝试找到一种无需画布但使用 Three.js TextureDataTexture 对象的方法。 Here an example of what I'm trying。问题是我找不到如何将图像从Textureimage 的类型为HTMLVideoElement)复制到另一个。

rotateFrames() 函数中,旧帧应该丢失,新帧应该替换,就像在 FIFO 中一样。但是这条线

frames[i].image = frames[i + 1].image;

只是复制参考,而不是纹理数据。我猜DataTexture 应该这样做,但我无法从TextureHTMLVideoElement 中得到DataTexture

有什么想法吗?

警告:您必须有一个摄像头并允许浏览器使用它来获取示例工作。显然,您必须有一个更新的浏览器。

【问题讨论】:

  • 不确定我明白了,但应该有一种方法可以做到这一点,而无需手动复制字节,只需旋转指针。我有一个类似的项目,并使用了多个屏幕外画布和内置的 drawImage() 来传输到屏幕。这非常快,因为 Chrome 直接在 GPU 上完成所有工作。所以,如果你想使用 shaders/three.js,我会准备最终的画布并更新纹理。这有意义吗?
  • 是的,我在一个类似的 C++ 项目中做过这个。旋转指针是正确的方式,see this image。但是每个新帧都需要复制到图像历史数组(每次都在不同的位置)。如果不复制数据而只复制指针,则会丢失旧帧,因为每个指针都会指向较新的帧,

标签: javascript html5-canvas webgl three.js


【解决方案1】:

这是你要找的吗?

http://fiddle.jshell.net/m4Bh7/10/

编辑:

function onFrame(dt) {
    if (video.readyState === video.HAVE_ENOUGH_DATA) { /* new frame available from webcam */
        context.drawImage(video, 0, 0,videoWidth,videoHeight);
        frames[framesNum - 1].image.data = new Uint8Array(context.getImageData(0,0,videoWidth, videoHeight).data.buffer);
        frames[framesNum - 1].needsUpdate = true;
    }
}

这是最重要的部分:它制作帧的副本并将其作为数据保存在 dataTexture 中。

function rotateFrames() {
    for (var i = 0; i != framesNum - 1; ++i) {
/*
         * FIXME: this does not work!
         */
        frames[i].image.data = frames[i + 1].image.data;
        frames[i].needsUpdate = true;
    }
}

这会将数据从纹理复制到帧中的纹理。

新版本:http://fiddle.jshell.net/hWL2E/4/

function onFrame(dt) {
    if (video.readyState === video.HAVE_ENOUGH_DATA) { /* new frame available from webcam */
        context.drawImage(video, 0, 0,videoWidth,videoHeight);
         var frame = new THREE.DataTexture(new Uint8Array(context.getImageData(0,0,videoWidth, videoHeight).data.buffer) ,videoWidth,videoHeight);
        frames[framesNum - 1] = frame;
        frames[framesNum - 1].needsUpdate = true;
        sprites[framesNum - 1].map = frames[framesNum - 1];
    }
}

它为视频图像的每一帧生成一个新的纹理。

function rotateFrames() {
    for (var i = 0; i != framesNum - 1; ++i) {
/*
         * FIXME: this does not work!
         */
        frames[i] = frames[i + 1];
        sprites[i].map = frames[i];

    }
}

这就是让它变得更好的原因。因为它重用了使用过的纹理,这意味着它不需要重新发送到 GPU。

【讨论】:

  • 这就是我要找的。请在答案中解释您在做什么,我会接受答案。当您调用frames[i].image.data = frames[i + 1].image.data; 时,您是在复制帧缓冲区还是只是移动引用?
  • 我添加了一个小解释和一个更好的版本。
猜你喜欢
  • 1970-01-01
  • 2017-10-05
  • 1970-01-01
  • 1970-01-01
  • 2014-05-31
  • 2013-05-19
  • 2016-02-27
  • 2017-04-26
  • 2014-03-26
相关资源
最近更新 更多