2017-01-25 15 views
0

Я пытаюсь найти самый быстрый способ изменить вершины сетки с помощью three.js. Я обнаружил, что если я изменю части mesh.geometry.attributes.position.array, тогда установите mesh.geometry.attributes.position.needsUpdate = true, он работает хорошо и не нуждается в перестройке массивов или воссоздании буферов opengl. Я обнаружил, что needsUpdate = true изменяет номер версии атрибута и заставляет его повторно перенастраивать массив вершин атрибутов в буфер opengl.Три js как добавить треугольник в BufferGeometry вручную

Поэтому я попытался сделать это сам, вызвав gl.bindBuffer(), затем gl.bufferData(), но после этого каждый цикл за какое-то время сработает при моем вызове на новый Float32Array(). Что странно, потому что, когда я проверяю использование своей памяти, я использую только 4 МБ прямо перед сбоем. Я понимаю, что это не лучший способ освободить/перераспределить массив каждый цикл, чтобы сделать его немного больше, когда я мог бы удвоить размер массива, когда он наполнится, но я хочу понять, почему он сбой, когда это делается.

https://jsfiddle.net/q1txL19c/3/ Сбой за 20 секунд. Но если я изменил if (0) на if (1), это сработает.

Что такое three.js, выполняющее по-другому, что делает его не аварийным? Почему новый Float32Array() терпит неудачу, когда в зависимости от профилировщика не используется большая часть javascript-памяти?

<!doctype html> 
<html> 
    <body style='margin:0;padding:0'> 
     <script src="https://threejs.org/build/three.js"></script> 
     <script> 

var camera, scene, renderer, mesh 
var triangles = 1 
init() 

function init() 
{ 
    scene = new THREE.Scene() 

    camera = new THREE.PerspectiveCamera(50, window.innerWidth/window.innerHeight, .1, 10000) 
    camera.position.z = 15 
    scene.add(camera) 

    var geometry = new THREE.BufferGeometry() 

    var material = new THREE.MeshBasicMaterial({side: THREE.FrontSide, transparent:false, vertexColors: THREE.VertexColors}) 
    mesh = new THREE.Mesh(geometry, material) 

    var positions = new Float32Array([1,1,0, 0,1,0, 0,0,0]) 
    geometry.addAttribute('position', new THREE.BufferAttribute(positions,3)) 

    var colors = new Float32Array([0,0,1, 0,0,0, 0,0,0]) 
    geometry.addAttribute('color', new THREE.BufferAttribute(colors,3)) 

    scene.add(mesh) 

    renderer = new THREE.WebGLRenderer() 
    renderer.setSize(window.innerWidth, window.innerHeight) 
    renderer.setClearColor(0x6699DD) 

    document.body.appendChild(renderer.domElement) 

    loop() 
} 

function addTriangle(geometry) 
{ 
    // Make 3 new vertices, each with x,y,z. 9 total positions. 
    var newVertices = [] 
    for(var i=0; i<9; i++) 
     newVertices[i] = Math.random()*10-5 

    appendArrayToAttribute(geometry.attributes.position, newVertices) 


    // Make 3 new colors, 1 for each new vertex, each with r,g,b. 9 total slots. 
    var newColors = [] 
    for(var i=0; i<9; i++) 
     newColors[i] = Math.random() 

    appendArrayToAttribute(geometry.attributes.color, newColors) 
} 

function appendArrayToAttribute(attribute, arrayToAppend) 
{ 
    // Make a new array for the geometry to fit the 9 extra positions at the end, since you can't resize Float32Array 
    try 
    { 
     var newArray = new Float32Array(attribute.array.length + arrayToAppend.length) 
    } 
    catch(e) 
    { 
     console.log(e) 
     if(!window.alerted) 
     { 
      alert("out of memory!? can't allocate array size="+(attribute.array.length + arrayToAppend.length)) 
      window.alerted = true 
     } 
     return false 
    } 
    newArray.set(attribute.array) 
    newArray.set(arrayToAppend, attribute.array.length) 


    attribute.setArray(newArray) 

    if(0) 
    { 
     attribute.needsUpdate = true 
    } 
    else 
    { 
     // Have the geometry use the new array and send it to opengl. 
     var gl = renderer.context 
     gl.bindBuffer(gl.ARRAY_BUFFER, renderer.properties.get(attribute).__webglBuffer) 
     gl.bufferData(gl.ARRAY_BUFFER, attribute.array, gl.STATIC_DRAW) 
    } 

} 

function loop() 
{ 
    requestAnimationFrame(loop) 

    mesh.rotation.x += 0.01 
    mesh.rotation.y += 0.02 

    renderer.render(scene, camera) 

    for(var i=0;i<10;i++) 
    { 
     addTriangle(mesh.geometry) 
     triangles++ 
    } 
    if(Math.random()<.03) 
    { 
     console.log("triangles="+triangles) 
     var gl = renderer.context 
     console.log("gl buffer size="+gl.getBufferParameter(gl.ARRAY_BUFFER, gl.BUFFER_SIZE)) 
    } 
} 

     </script> 

    </body> 
</html> 

ответ

2

Вы можете добавить лицо BufferGeometry после первого рендеринг, но вы должны предварительно выделить вашу геометрию attribute буферов должны быть достаточно большим, так как они не могут быть изменены.

Также вы будете обновлять значения массива, а не создавать новые массивы.

Вы можете обновить число граней, чтобы сделать так:

geometry.setDrawRange(0, 3 * numFacesToDraw); // 3 vertices for each face 

this related answer and demo См.

three.js r.84

 Смежные вопросы

  • Нет связанных вопросов^_^