2017-02-14 1 views
1

私はthree.jsでアプリケーションを構築していますが、パフォーマンスに大きな問題があります。このアプリケーションのこの部分は、Voxel Painter exampleに基づいています。私のバージョンでは、ユーザーはセルをクリックして配置を開始し、カーソルを配置を終了する位置にドラッグし、クリックして終了します。ユーザーがマウスを移動したときRayCasterでonMouseMoveを使用した場合、Three.jsのパフォーマンスが非常に遅い

function onDocumentMouseMove(event) { 
    //set up mouse and raycaster 
    event.preventDefault(); 
    mouse.set((event.clientX/window.innerWidth) * 2 - 1, -(event.clientY/window.innerHeight) * 2 + 1); 
    raycaster.setFromCamera(mouse, camera); 

    switch (buildMode) { 
     case buildModes.CORRIDOR: 
      scene.add(rollOverFloor); 

      var intersects = raycaster.intersectObjects(gridObject); 
      if (intersects.length > 0) { 

       var intersect = intersects[0]; 

       if (beginPlace == true) { 
        //store the intersection position 
        var endPlace = new THREE.Vector3(0, 0, 0); 
        endPlace.copy(intersect.point).add(intersect.face.normal); 
        endPlace.divideScalar(step).floor().multiplyScalar(step).addScalar(step/step); 
        endPlace.set(endPlace.x, 0, endPlace.z); 

        corridorDrag(endPlace); 

       } 
       //if user hasn't begun to place the wall 
       else { 
        //show temporary wall on grid 
        rollOverFloor.position.copy(intersect.point).add(intersect.face.normal); 
        rollOverFloor.position.divideScalar(step).floor().multiplyScalar(step).addScalar(step/step); 
        rollOverFloor.position.set(rollOverFloor.position.x, 0, rollOverFloor.position.z); 
       } 
      } 
      break; 

    } 
    render(); 
} 

上記のコードは、(そこにメインのアプリケーションには多くのbuildmodesがありますが、私はそれらをここに含まれていない)と呼ばれています。この関数は単に開始および終了ポイントを取得し、corridorDrag()関数は、開始点と終了点との間の細胞を充填:

function corridorDrag(endPlace) { 
    deleteFromScene(stateType.CORRIDOR_DRAG); 

    var startPoint = startPlace; 
    var endPoint = endPlace; 
    var zIntersect = new THREE.Vector3(startPoint.x, 0, endPoint.z); 
    var xIntersect = new THREE.Vector3(endPoint.x, 0, startPoint.z); 

    var differenceZ = Math.abs(startPlace.z - zIntersect.z); 
    var differenceX = Math.abs(startPlace.x - xIntersect.x); 

    var mergedGeometry = new THREE.Geometry(); 

    for (var i = 0; i <= (differenceZ/step); i++) { 
     for (var j = 0; j <= (differenceX/step); j++) { 
      var x = startPlace.x; 
      var y = startPlace.y; 
      var z = startPlace.z; 

      if (endPoint.x <= (startPlace.x)) { 
       if (endPoint.z <= (startPlace.z)) { 
        x = x - (step * j); 
        z = z - (step * i); 
       } 
       else if (endPoint.z >= (startPlace.z)) { 
        x = x - (step * j); 
        z = z + (step * i); 
       } 
      } else if (endPoint.x >= (startPlace.x)) { 
       if (endPoint.z <= (startPlace.z)) { 
        x = x + (step * j); 
        z = z - (step * i); 
       } 
       else if (endPoint.z >= (startPlace.z)) { 
        x = x + (step * j); 
        z = z + (step * i); 
       } 
      } 

      floorGeometry.translate(x, y, z); 
      mergedGeometry.merge(floorGeometry); 
      floorGeometry.translate(-x, -y, -z); 
     } 
    } 

    var voxel = new THREE.Mesh(mergedGeometry, tempMaterial); 
    voxel.state = stateType.CORRIDOR_DRAG; 

    scene.add(voxel); 
    tempObjects.push(voxel); 
} 

まず、deleteFromScene()関数は、シーンのすべての現在強調表示された細胞を除去する(参照します以下)。その後、コードは(私は信じて)、開始点と終了点に応じていくつかのメッシュを作成し、それらをシーンに追加する必要があります。

function deleteFromScene(state) { 
    tempObjects = []; 
    var i = scene.children.length; 
    while (i--) { 
     if (scene.children[i].state != undefined) 
      if (scene.children[i].state == state) 
       scene.children.splice(i, 1); 
    } 
} 

私が言ったように、非常に遅いです。また、WebGLRendererの統計ウィンドウに表示されるように、奇妙な量の頂点をレンダラーに追加するように見えます。私はそれがなぜ非常に多くの頂点を追加しているのか分かりませんが、それがとてもゆっくりとレンダリングされていると仮定しています。

The application can be viewed here - 問題は、1つのセルをクリックし、グリッドのもう一方の端にカーソルをドラッグし、セルを埋める時間を観察することで確認できます。

ありがとうございます。これは本当に最後の手段です。

答えて

1

数年前にTwitterがアップデートを出しました。このアップデートでは、彼らは無限のスクロールを導入したばかりで、リリース日にアップデートがユーザーのブラウザをクラッシュさせていました。 Twitterのエンジニアは何らかの調査を行い、クラッシュが1秒間に数百回スクロールした結果であることを発見しました。

マウスイベントは、1秒に数回多く発生する可能性があり、コードが頻繁に実行される可能性があり、ブラウザが遅くなり(多くの場合)、クラッシュします。 Twitterのソリューション(そしてうまくいけばあなた)はシンプルでした:あなたのイベントに投票してください。

mousemoveイベントハンドラの中で、最後の移動イベントから何ミリ秒経過したかを確認します。

var lastMove = Date.now(); 

function onDocumentMouseMove(event) { 
    if (Date.now() - lastMove < 31) { // 32 frames a second 
     return; 
    } else { 
     lastMove = Date.now(); 
    } 

    // your code here 
} 

私は助けてくれることを願っています!

+0

非常に雄弁な解決策です。 – jdmdevdotnet

+0

私のonDocumentMouseMove(イベント)関数の上にスニペットを追加して下にコードを配置すると、とても良い解決策になりました。@ Brandon.Blanchyard – user3329161

+0

コード実行時にこれらのエラーが発生します。 捕捉されなかっにReferenceError:isVectorEqualはHTMLDocument.onDocumentMouseDown(3dblueprint.uk/:216) –

関連する問題