2013-07-01 10 views
5

Używam BufferGeometry, aby narysować tysiące sześcianów, które stanowią teren, ale trudno jest dowiedzieć się, jak zaktualizować geometrię, jeśli potrzebuję zmienić pozycję jednej z kostek. Na przykład, mam ten kod, aby zainicjować mój geometrii (robię moje testy na zaktualizowanej wersji this example)Jak szybko zaktualizować dużą BufferGeometry?

// 12 triangles per cube (6 quads) 
var triangles = 12 * 150000; 

var geometry = new THREE.BufferGeometry(); 
geometry.attributes = { 

    position: { 
     itemSize: 3, 
     array: new Float32Array(triangles * 3 * 3), 
     numItems: triangles * 3 * 3 
    }, 

    normal: { 
     itemSize: 3, 
     array: new Float32Array(triangles * 3 * 3), 
     numItems: triangles * 3 * 3 
    }, 

    color: { 
     itemSize: 3, 
     array: new Float32Array(triangles * 3 * 3), 
     numItems: triangles * 3 * 3 
    } 
} 

positions = geometry.attributes.position.array; 
normals = geometry.attributes.normal.array; 
colors = geometry.attributes.color.array; 

Jeśli przeniosę sześcian, to nie wydaje się być przemieszczane aż robię :

geometry.attributes.position.needsUpdate = true; 

Powoduje to spadek FPS podczas aktualizacji. Czy istnieje inny sposób, w jaki mogę to zrobić? Wydaje się nieco niepotrzebne, gdy zmieniam tylko jedną kostkę (12 trójkątów/36 wierzchołków). Chociaż może to być - nie sprawdziłem, co faktycznie robi needsUpdate. Zgadywanie wysyła ponownie tablicę do modułu cieniującego.

Myślałem, że mogę podzielić geometrię na oddzielne mniejsze wartości BufferGeometries, ale nie jestem pewien, czy to pomogłoby w ogólnej wydajności. Z tego co rozumiem, więcej geometrii = mniej FPS.

Jeśli ktoś ma jakieś pomysły, jak bym to zrobił, byłby to docenione! :) Oprócz problemu aktualizacji, BufferGeometry wydaje się dokładnie tym, czego potrzebuję. Dzięki!

Odpowiedz

7

Miałem ten sam problem z bardzo dużą BufferGeometry podczas aktualizowania kilku wierzchołków w nim.

Rozwiązaniem jest użycie _gl.bufferSubData zamiast _gl.bufferData w celu aktualizacji tylko części bufora. (Trzy js używa tylko _gl.bufferData).

Więc jeśli aktualizuje pozycje zrobisz:

// Tworzenie widoku danych do aktualizacji z indeksu offsetSub do offsetSubEnd

var view = geometry.attributes.position.array.subarray(offsetSub, offsetSubEnd);

// Bind bufor dla pozycji (dostać kontekst gl z webglrenderer)

_gl.bindBuffer(_gl.ARRAY_BUFFER, geometry.attributes.position.buffer);

// wstawić nowy Wartości w dobrym wskaźnikiem w buforze GPU (offsetGeometry jest w bajcie)

_gl.bufferSubData(_gl.ARRAY_BUFFER, offsetGeometry,view);

Należy pamiętać, że takie rozwiązanie może być mniejsza, jeśli zmienisz dużą część wierzchołków buforowych w porównaniu do _gl.bufferData.

6

Począwszy od r71 threejs obsługuje bufferSubData.

Użyj DynamicBufferAttribute (lub po prostu ustawić updateRange poprawnie)

var positionAttr = geometry.attributes.position 
// if not using DynamicBufferAttribute initialize updateRange: 
// positionAttr.updateRange = {}; 
positionAttr.updateRange.offset = 0; // where to start updating 
positionAttr.updateRange.count = 1; // how many vertices to update 
positionAttr.needsUpdate = true; 
+2

Nie wiem, która wersja została zmieniona, ale od 'r81' ten został włączony do [' BufferAttribute'] (https: // github.com/mrdoob/three.js/blob/r81/src/core/BufferAttribute.js#L27). – Jay