Я пытаюсь найти самый быстрый способ изменить вершины сетки с помощью 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>