2017-02-02 52 views
0

编辑;threejs getImageData视频性能

工作codepen(需要提供视频文件,以避免跨域策略)

https://codepen.io/bw1984/pen/pezOXm


我试图修改优良rutt ETRA例如这里https://airtightinteractive.com/demos/js/ruttetra/为视频作品(仍使用threejs),并遇到性能奇怪的问题。

我的代码当前按预期工作,并且实际上在我的macbook pro上运行得非常顺畅,但似乎导致了某种缓慢的内存泄漏,我认为这是所有需要完成的繁重工作由getImageData。奇怪的是,只有当我尝试刷新标签时才会引人注意,所以看起来它可能与Chrome中的垃圾收集有关?无论如何,将咕噜的工作分流到GPU上而不是杀死CPU?

我只是想知道,如果我在代码优化方面缺少任何明显的东西,或者如果我正面临的性能问题是由于我想要做的事情的性质而预期的。

我只对WebGL/chrome功能感兴趣,所以不需要担心任何类型的浏览器兼容性。

<script> 

var container, camera, scene, renderer, controls; 

// PI 
var PI = Math.PI; 
var TWO_PI = PI*2; 

// size 

SCREEN_WIDTH = window.innerWidth; 
SCREEN_HEIGHT = window.innerHeight; 
SCREEN_PIXEL_RATIO = window.devicePixelRatio; 

// camera 

var VIEW_ANGLE = 45; 
var ASPECT = SCREEN_WIDTH/SCREEN_HEIGHT; 
var NEAR = 0.1; 
var FAR = 20000000; 



// video raster 

var video; 
var videoImage; 
var videoImageContext; 

var _imageHeight; 
var _imageWidth; 


// lines 

var _lineGroup; 


// gui 

var _guiOptions = { 
    stageSize:  1, 
    scale:   1.0, 
    scanStep:  5, 
    lineThickness: 10.0, 
    opacity:  1.0, 
    depth:   50, 
    autoRotate:  false 
}; 


// triggered from audio.php getMediaStream 

function runme() 
{ 
    console.log('runme running'); 

    init(); 
    animate(); 
} 

runme(); 


function init() 
{ 
    container = document.createElement('div'); 
    document.body.appendChild(container); 

    //---------- 
    // scene 
    //---------- 

     scene = new THREE.Scene(); 


    //---------- 
    // camera 
    //---------- 

     camera = new THREE.PerspectiveCamera(VIEW_ANGLE, ASPECT, NEAR, FAR); 

     //camera.position.set(0,0,450); 

     camera.position.set(0,150,300); 


    //---------- 
    // objects 
    //---------- 

     // create the video element 
     video = document.createElement('video'); 
     // video.id = 'video'; 
     // video.type = ' video/ogg; codecs="theora, vorbis" '; 
     video.src = 'data/sintel.ogv'; 
     //video.src = 'data/az.mp4'; 

     video.load(); // must call after setting/changing source 
     video.play(); 

     videoImage = document.createElement('canvas'); 
     //videoImage.width = 480; 
     //videoImage.height = 204; 

     videoImageContext = videoImage.getContext('2d'); 

     _imageWidth = videoImage.width; 
     _imageHeight = videoImage.height; 

     //videoImageContext.fillStyle = '#ffffff'; 
     //videoImageContext.fillRect(0, 0, videoImage.width, videoImage.height); 



    //---------- 
    // controls 
    //---------- 

     controls = new THREE.OrbitControls(camera); 


    //---------- 
    // events 
    //---------- 

     window.addEventListener('resize', onWindowResize, false); 


    //---------- 
    // render 
    //---------- 

     var args = { 
      //antialias: true // too slow 
     } 

     renderer = new THREE.WebGLRenderer(args); 

     renderer.setClearColor(0x000000, 1); 
     renderer.setPixelRatio(SCREEN_PIXEL_RATIO); //Set pixel aspect ratio 
     renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); 

     // attach to dom 
     container.appendChild(renderer.domElement); 

     //render(); 
} 


function render() 
{ 

    if(video.readyState === video.HAVE_ENOUGH_DATA && !video.paused && !video.ended) // and video.currentTime > 0 
    { 
     //_imageWidth = videoImage.width; 
     //_imageHeight = videoImage.height; 

     videoImageContext.drawImage(video,0,0,_imageWidth,_imageHeight); 


     // Grab the pixel data from the backing canvas 
     var _data = videoImageContext.getImageData(0,0,videoImage.width,videoImage.height).data; 

     //log(data); 

     //_pixels = data; 

     var x = 0, y = 0; 

     if(_lineGroup) 
     { 
      scene.remove(_lineGroup); 
      //_lineGroup = null; 
     } 

     _lineGroup = new THREE.Object3D(); 


     var _material = new THREE.LineBasicMaterial({ 
      color: 0xffffff, 
      linewidth: _guiOptions.lineThickness 
     }); 


     // loop through the image pixels 

     for(y = 0; y < _imageHeight; y+= _guiOptions.scanStep) 
     { 

      var _geometry = new THREE.Geometry(); 

      for(x=0; x<_imageWidth; x+=_guiOptions.scanStep) 
      { 
       var color = new THREE.Color(getColor(x, y, _data)); 

       var brightness = getBrightness(color); 

       var posn = new THREE.Vector3(x -_imageWidth/2,y - _imageHeight/2, -brightness * _guiOptions.depth + _guiOptions.depth/2); 

       //_geometry.vertices.push(new THREE.Vertex(posn)); 
       _geometry.vertices.push(posn); 

       _geometry.colors.push(color); 

       _color = null; 
       _brightness = null; 
       _posn = null; 
      } 

      // add a line 
      var _line = new THREE.Line(_geometry, _material); 

      //log(line); 

      _lineGroup.add(_line); 

      // gc 
      _geometry = null; 
     } 

     scene.add(_lineGroup); 

     _data = null; 
     _line = null; 

    } 

    renderer.render(scene,camera); 
} 


function animate(){ 

    requestAnimationFrame(animate); 

    stats.update(); 

    render(); 
} 


function onWindowResize(){ 

    camera.aspect = window.innerWidth/window.innerHeight; 
    camera.updateProjectionMatrix(); 
    renderer.setSize(window.innerWidth, window.innerHeight); 
    render(); 
} 



// Returns a hexadecimal color for a given pixel in the pixel array. 

function getColor(x, y, _pixels) 
{ 
    var base = (Math.floor(y) * _imageWidth + Math.floor(x)) * 4; 

    var c = { 
     r: _pixels[base + 0], 
     g: _pixels[base + 1], 
     b: _pixels[base + 2], 
     a: _pixels[base + 3] 
    }; 
    return (c.r << 16) + (c.g << 8) + c.b; 
} 



// return pixel brightness between 0 and 1 based on human perceptual bias 

function getBrightness(c) 
{ 
    return (0.34 * c.r + 0.5 * c.g + 0.16 * c.b); 
} 

</script> 

任何帮助,任何人都可以提供将不胜感激,哪怕它只是指着我在正确的方向,因为我才刚刚开始这个东西进行试验,并已几乎放弃自己的动脉瘤试图总结我的小介意它。

+0

也值得重申...请注意,目前的代码可能会导致Chrome崩溃 – bw1984

+0

我一直在阅读它并不完全理解它应该做什么,但只要我达到了新的THREE.Line'我以为是罪魁祸首。无论你在这里做什么,你都应该缓存,你应该有一个几何构造(矩形中的线条)或者有一个可以放置每个帧的线条池。在渲染循环中,我相信这会强调内存,因为每个节点都有一堆数据,而且数据通常也是以对象的形式出现的(主要是向量和矩阵)。 – pailhead

+0

整体,你不需要读取视频,并做到这一点的CPU,刚读它作为纹理和做着色器 – pailhead

回答

0

慢内存泄漏是最可能是由于:

 // add a line 
     var _line = new THREE.Line(_geometry, _material); 

     //log(line); 

     _lineGroup.add(_line); 

THREE.Line是一个对象,含有其它的目的和大量数据。每次实例化它时,它都会创建.matrix,.matrixWorld,.modelViewMatrix,.normalMatrix,它们都是具有一堆数字的数组。 .position,.quaternion,.scale,.rotation和可能.up是向量,quats等,并且略小,但也有特殊构造函数的数组。

为每16毫秒分配一次所有这些只会释放下一帧,可能是“泄漏”的原因。

您应该创建一个THREE.Line对象池,然后改为绘制每个帧。您可以使用.visible控制的绘制对象的数量并改变它们的转换属性。

0

@pailhead我接受了关于预先渲染线和lineGroup的建议,然后更新每个动画帧的顶点,而现在它的声音像小猫一样。还需要插入以下行以确保更新的坐标被拾取;

e.geometry.verticesNeedUpdate = true; 

我无法弄清楚如何获得托管的视频上codepen(跨域策略违规问题)工作,但我已经把一个版本升级反正显示工作代码。

https://codepen.io/bw1984/pen/pezOXm

我会尽力,只要我能

我一直妄图获得色彩的工作得到了自托管(工作)的版本了,但必须是另一天的锻炼。