2017-02-02 62 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

我會盡力,只要我能

我一直妄圖獲得色彩的工作得到了自託管(工作)的版本了,但必須是另一天的鍛鍊。