Changing from THREE.Geometry to THREE.BufferGeometry with THREE JS - javascript

Hi I'm new to Three JS and need a little help. I am using a piece of code I found to create a sphere of random points but since THREE.Geometry has since been depreciated I need to change THREE.Geometry to THREE.BufferGeometry in the code.
The original code is :
var pointsGeometry = new THREE.Geometry();
for (var i = 0; i < 1000; i++) {
var vector = new THREE.Vector3();
// for simplicity I have omitted script
// that would be placed here for creating random
// values for vector.x, vector.y, vector.z etc etc
pointsGeometry.vertices.push(vector);
}
So now I believe I need to use:
const pointsGeometry = new THREE.BufferGeometry();
but how do I push each vector into an array that exists in an attribute of pointsGeometry named 'vertices'?
In the for loop I cannot use :
pointsGeometry.setAttribute( 'vertices', new THREE.Float32BufferAttribute( vector ) );
I thought I needed to manually create an array 'vectorsArray' and push each vector into the array in the for loop and then add it after the loop
pointsGeometry.setAttribute( 'vertices', new THREE.Float32BufferAttribute( vectorsArray ) );
while this does create a vertices attribute and add an array of 1000, each value is NaN when it should be:
0: Object { x: -21.16441539757467, y: 112.77250047881454, z: -37.63426937227097, … } etc
I have checked that vectorsArray does posses the correct values which they do, but for some reason they are not getting passed into pointsGeometry.setAttribute( 'vertices'). What am I doing wrong please?
Thanks in advance.

Try it like so:
const geometry = new THREE.BufferGeometry();
const points = [];
const point = new THREE.Vector3();
for ( let i = 0; i < 1000; i ++ ) {
point.random();
points.push( point.x, point.y, point.z );
}
geometry.setAttribute( 'position', new THREE.Float32BufferAttribute( points, 3 ) );
When using this geometry with THREE.Points, it will create a random point cloud.

Related

Best way to get vertices of a mesh three.js

I am new to Three.js so perhaps I am not going abut this optimally,
I have geometry which I create as follows,
const geo = new THREE.PlaneBufferGeometry(10,0);
I then apply a rotation to it
geo.applyMatrix( new THREE.Matrix4().makeRotationX( Math.PI * 0.5 ) );
then I create a Mesh from it
const open = new THREE.Mesh( geo, materialNormal);
I then apply a bunch of operations to the mesh to position it correctly, as follows:
open.position.copy(v2(10,20);
open.position.z = 0.5*10
open.position.x -= 20
open.position.y -= 10
open.rotation.z = angle;
Now what is the best way to get the vertices of the mesh both before and after it's position is changed? I was surpised to discover that the vertices of a mesh are not in-built into three.js.
Any hints and code samples would be greatly appreciated.
I think you're getting tripped-up by some semantics regarding three.js objects.
1) A Mesh does not have vertices. A Mesh contains references to Geometry/BufferGeometry, and Material(s). The vertices are contained in the Mesh's geometry property/object.
2) You're using PlaneBufferGeometry, which means an implementation of a BufferGeometry object. BufferGeometry keeps its vertices in the position attribute (mesh.geometry.attributes.position). Keep in mind that the vertex order may be affected by the index property (mesh.geometry.index).
Now to your question, the geometric origin is also its parent Mesh's origin, so your "before mesh transformation" vertex positions are exactly the same as when you created the mesh. Just read them out as-is.
To get the "after mesh transformation" vertex positions, you'll need to take each vertex, and convert it from the Mesh's local space, into world space. Luckily, three.js has a convenient function to do this:
var tempVertex = new THREE.Vector3();
// set tempVertex based on information from mesh.geometry.attributes.position
mesh.localToWorld(tempVertex);
// tempVertex is converted from local coordinates into world coordinates,
// which is its "after mesh transformation" position
Here's an example written by typescript.
It gets the grid's position in the world coordinate system.
GetObjectVertices(obj: THREE.Object3D): { pts: Array<THREE.Vector3>, faces: Array<THREE.Face3> }
{
let pts: Array<THREE.Vector3> = [];
let rs = { pts: pts, faces: null };
if (obj.hasOwnProperty("geometry"))
{
let geo = obj["geometry"];
if (geo instanceof THREE.Geometry)
{
for (let pt of geo.vertices)
{
pts.push(pt.clone().applyMatrix4(obj.matrix));
}
rs.faces = geo.faces;
}
else if (geo instanceof THREE.BufferGeometry)
{
let tempGeo = new THREE.Geometry().fromBufferGeometry(geo);
for (let pt of tempGeo.vertices)
{
pts.push(pt.applyMatrix4(obj.matrix));
}
rs.faces = tempGeo.faces;
tempGeo.dispose();
}
}
return rs;
}
or
if (geo instanceof THREE.BufferGeometry)
{
let positions: Float32Array = geo.attributes["position"].array;
let ptCout = positions.length / 3;
for (let i = 0; i < ptCout; i++)
{
let p = new THREE.Vector3(positions[i * 3], positions[i * 3 + 1], positions[i * 3 + 2]);
}
}

Three js how to add triangle to BufferGeometry manually

I've been trying to find the fastest way to change a mesh's vertices with three.js. I found that if I change parts of mesh.geometry.attributes.position.array, then set mesh.geometry.attributes.position.needsUpdate=true, it works well and doesn't have to rebuild arrays or recreate opengl buffers. I found that needsUpdate=true changes the version number of the attribute and that makes it resend the attributes vertices array to the opengl buffer.
So I tried doing that myself instead by calling gl.bindBuffer() then gl.bufferData() but then after doing that every loop for a while it crashes on my call to new Float32Array(). Which is weird because when I check my memory usage I'm only using 4MB right before it crashes. I realize it's not the best way to be deallocating/reallocating the array every loop just to make it slightly bigger when I could be doubling the size of the array when it gets full, but I want to understand why it's crashing when done this way.
https://jsfiddle.net/q1txL19c/3/ Crashes in 20 seconds.
But if I change the if(0) to if(1) it works.
What is three.js doing differently that makes it not crash? Why does new Float32Array() fail when not much javascript memory has been used up according to the profiler?
<!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>
You can add faces to BufferGeometry after the first render, but you must pre-allocate your geometry attribute buffers to be large enough, as they can't be resized.
Also, you will be updating array values, not instantiating new arrays.
You can update the number of faces to render like so:
geometry.setDrawRange( 0, 3 * numFacesToDraw ); // 3 vertices for each face
See this related answer and demo.
three.js r.84

THREE.js Copy from SphereBufferGeometry to BufferGeometry

I have created a BufferGeometry to store a bunch of triangles (for later manipulation with a vertex shader). The vertice position coordinates and colors were generated randomly and added as arrays inside the bufferGeometry.attributes property. When used to make a mesh it worked fine. here is the code:-
//... Buffer Geometry
triangles = 500;
Bgeometry = new THREE.BufferGeometry();
Bgeometry.dynamic = true;
//... Bvertex_coords
Bvertex_coords = new Float32Array( triangles * 3 * 3 );
for ( var i = 0, l = triangles * 3 * 3; i < l; i += 3 )
{
Bvertex_coords[ i ] = Math.random() - 0.5;//... x
Bvertex_coords[ i + 1 ] = 2*(Math.random() - 0.5);//... y
Bvertex_coords[ i + 2 ] = Math.random() - 0.5;//... z
}
Bgeometry.addAttribute( 'position', new THREE.BufferAttribute( Bvertex_coords, 3 ) );
Next I want to create a similar BufferGeometry but this time the triangles should be initially arranged into a spherical "surface". So I created a "donor" SphereBufferGeometry with the appropriate configuration.
The idea was to then simply copy the relevant data from the donor SphereBufferGeometry into the BufferGeometry.
Here is the code I have been using:-
//... Buffer Geometries
////... new (r72) method - create a "donor" sphereBufferGeometry
var Cgeometry = new THREE.SphereBufferGeometry( 1, 4, 4 );
var num_Cgeom_pos_coords = Cgeometry.attributes.position.array.length;
var num_Cgeom_vertices = num_Cgeom_pos_coords/3;
//...Dgeometry
//... first make a plain buffer geometry
//... then copies data from an existing BufferSphereGeometry
Dgeometry = new THREE.BufferGeometry();
Dgeometry.dynamic = true;
Dpos_coords = new Float32Array( num_Cgeom_pos_coords );
Dpos_normals = new Float32Array( num_Cgeom_pos_coords );
for ( var pc = 0; pc < num_Cgeom_pos_coords ; pc ++ )
{
Dpos_coords[ pc ] = Cgeometry.attributes.position.array[pc];
Dpos_normals[ pc ] = Cgeometry.attributes.normal.array[pc];
}
Dgeometry.addAttribute( 'position', new THREE.BufferAttribute( Dpos_coords, 3 ) );
Dgeometry.addAttribute( 'normal', new THREE.BufferAttribute( Dpos_normals,3 ) );
Pack_of_Triangles_mesh_D = new THREE.Mesh( Dgeometry, Sphere_Ord_material);
For some reason when I copy from the SphereBufferGeometry to a BufferGeometry and make a mesh only a small fraction (about 20-25%?) of the triangles are actually plotted.
QUESTION
So my question is: What do I need to do to get all the triangles to plot?
UPDATE1
By contrast the following method works OK: (1) make a mesh with a SphereGeometry, (2) make a new BufferGeometry with .setFromObject(mesh) (3) copy from the previous BufferGeometry to a new BufferGeometry and use the latter to make a new mesh. But this seems a long-winded approach.
UPDATE2
The following method also works OK when Cgeometry is a SphereBufferGeometry.
Dgeometry = new THREE.BufferGeometry();
Dgeometry.copy ( Cgeometry );
var num_Dgeom_pos_coords = Dgeometry.attributes.position.array.length;
var num_D_geom_vertices = num_D_geom_pos_coords/3;
It seems that the original problem is due to indexing being used in a SphereBufferGeometry and no index being built by default in a new BufferGeometry.
There doesn't seem to be a simple way of copying the index from the SphereBufferGeometry to the new BufferGeometry.
I am a bit confused because I thought the idea of BufferGeomtry involved doing without indexing.

Issue in Extruding The Geometry

I am trying to Extrude the Rectangle drawn in the canvas to Three.js canvas.
Here Blue one is 2d canvas drawing and Green is 3d
var Shape = new THREE.Shape();
Shape.moveTo(0,0,0);
for(var i=0;i<=point.length/2;i++)
{
Shape.lineTo(point[i],point[i+1]);
}
var ExtrusionSettings = {
curveSegments: 3,
bevelThickness:0, bevelSize: 0, bevelEnabled: false,
material: 0, extrudeMaterial: 1,amount: 10
};
var Geometry = new THREE.ExtrudeGeometry( Shape, ExtrusionSettings );
var Material = new THREE.MeshLambertMaterial({color: 0xff8800});
Material.side = THREE.DoubleSide;
Mesh = new THREE.Mesh(Geometry,Material);
Mesh.position.set(0,0,0);
Scene.add(Mesh);
The points is passed as an array which contain the x,y coordinates of the lines in the canvas
the points are passed by
function mouseDown(event)
{
Line[0] = event.pageX - this.offsetLeft;
Line[1] = event.pageY - this.offsetTop;
console.log("down");
}
function mouseUp(event)
{
Line[2] = event.pageX - this.offsetLeft;
Line[3] = event.pageY - this.offsetTop;
console.log("up");
var Width = Math.abs(Line[2] - Line[0]);
var Height = Math.abs(Line[3] - Line[1]);
Context.beginPath();
//Context.moveTo(Line[0], Line[1]);
//Context.lineTo(Line[2], Line[3]);
//Context.rect(Line[0],Line[1],Width,Height);
Context.lineWidth="5";
Context.strokeStyle="red";
var L1P1x = Line[0];
var L1P1y = Line[1];
var L1P2x = Line[0]+Width;
var L1p2Y = Line[1];
var L2P1x = Line[0]+Width;
var L2P1y = Line[1];
var L2P2x = Line[2];
var L2P2y = Line[3];
var L3P1x = Line[2];
var L3P1y = Line[3];
var L3P2x = Line[0];
var L3P2y = Line[1]+Height;
var L4P1x = Line[0];
var L4P1y = Line[1]+Height;
var L4P2x = Line[0];
var L4P2y = Line[1];
Context.moveTo(L1P1x,L1P1y);
Context.lineTo(L1P2x,L1p2Y);
Context.moveTo(L2P1x,L2P1y);
Context.lineTo(L2P2x,L2P2y);
Context.moveTo(L3P1x,L3P1y);
Context.lineTo(L3P2x,L3P2y);
Context.moveTo(L4P1x,L4P1y);
Context.lineTo(L4P2x,L4P2y);
Context.stroke();
Points.push(L1P1x,L1P1y,L1P2x,L1p2Y,L2P1x,L2P1y,L2P2x,L2P2y,L3P1x,L3P1y,L3P2x,L3P2y,L4P1x,L4P1y,L4P2x,L4P2y);
addMesh(Points);//points are passes to draw in 3d
//console.log(Points);
}
Not a fan of three.js but looking at your code you have some basic logic errors.
The short answer
Logic errors in the for loop! Change your first snippet to the following. You have Points in the second snippet and Point in the first. I have used point in the fix as I assume that is the correct name for the array of coordinates.
var i, len, mesh; // define all the vars you will use
len = point.length; // get the number of coordinates.
if(len > 1) { // make sure there are points.
shape.moveTo(point[0], point[1]); // move to the first point
for(i = 2; i < len; i += 2) { // iterate other points and lineTo them
shape.lineTo(point[i], point[i + 1]); // add the line.
}
mesh = new THREE.Mesh(
new THREE.ExtrudeGeometry( // Create geom
shape,
{ // extrusion settings.
curveSegments : 3,
bevelThickness : 0,
bevelSize : 0,
bevelEnabled : false,
material : 0,
extrudeMaterial : 1,
amount : 10
}
),
new THREE.MeshLambertMaterial({color: 0xff8800}) // material
);
mesh.position.set(0, 0 0); // position the mesh
scene.add(mesh); // add it to the scene
}
That will fix the bug. It was the for loop that was bad.
The long answer.
You seem to be a beginner so the long answer is to give you some longer term advice. (advice only as there are no rules).
Creating the shape. You had...
var Shape = new THREE.Shape();
Shape.moveTo(0,0,0);
for(var i=0;i<=point.length/2;i++)
{
Shape.lineTo(point[i],point[i+1]);
}
Now with my pedantic eye
Never name vars with a capital. Capitaitals are reserved for named objects. Though in this case you are safe, using the name Shape in a differing scopy could well overwrite the object constructor.
var Shape = new THREE.Shape(); // you had
should be
var shape = new THREE.shape();
Capitals are only for objects that you can use the new token with, Acronyms, or constants. This is not a trivial convention as all of Javascript's inbuilt naming uses it and I have yet to find a popular framework that does not use it. DON'T CAPITALIZE, it is a bad habit in javascript and will cause endless hours looking for simple syntax bugs.
The THREE.Shape object only deals with 2D paths. You had
// 3 coordinates for for a 2D path???
Shape.moveTo(0,0,0); // remove this line it is not needed
The last 0 is ignored, ( I checked the THREE.js source code) and that is not the error.
You error is here in the following.
for(var i=0;i<=point.length/2;i++) // Only half the points ??
{ // you then line to x,y
Shape.lineTo(point[i],point[i+1]);
// Next lineTo will be y,x then x,y messing everything up.
}
point refers the the array of numbers representing the x and y coordinates of the path. It is organised with the x coord, then y then x then y.
The number of items in the array is the number of 2D points * 2. The * 2 is because there is a X and a ``Y for each point.
So need to iterate the point array correctly.
Step by step.
var i, len; // always put your vars declarations at the top
len = point.length; // I like to get the length before the loop.
The for loop needs to step by 2 as the are two entries for each point.
for(i = 0; i < len; i += 2) { //Put the { at the end. Saves space and is easier to read.
Check for the first point as you need to moveTo (note answer is slightly different)
if(i === 0) {
Add the point to the path (shape).
shape.moveTo(point[i], point[i + 1]);
Then the other points
} else {
shape.lineTo(point[i], point[i + 1]);
}
This will create the correct shape that you can then use to extrude.
Put all together as I would do it.
// where do you define scene. It should be lowercase
var i, len, mesh;
len = point.length;
if(len > 1) { // check if there are points (2 or more.
shape.moveTo(point[0], point[1]); // do the first point outside the for loop
// this saves having to do the if statement
// for each point
for(i = 2; i < len; i += 2) { // iterate points starting at the second
shape.moveTo(point[i], point[i + 1]); // add the line.
}
You had
// Such a long name for a one of abd just a mess
// Your code
//var ExtrusionSettings = {
// curveSegments: 3,
// bevelThickness:0, bevelSize: 0, bevelEnabled: false,
// material: 0, extrudeMaterial: 1,amount: 10
//};
// unless it will be used again put it inline
// Bad naming for the rest
// Your code
//var Geometry = new THREE.ExtrudeGeometry( Shape, ExtrusionSettings );
//var Material = new THREE.MeshLambertMaterial({color: 0xff8800});
//Material.side = THREE.DoubleSide;
//Mesh = new THREE.Mesh(Geometry,Material);
//Mesh.position.set(0,0,0);
//Scene.add(Mesh);
Replace it all with
// Material is used once so no need to create var for it
// Removed Material.side = THREE.DoubleSide; // assuming this is debug code only
// you had Mesh without var. That made it global scope. Never use a var without defining it first with the var token
var mesh = new THREE.Mesh( // define and assign mesh
new THREE.ExtrudeGeometry( // Create geom// indent arguments for readability
shape,
{ // extrusion settings.
curveSegments : 3, // line it all up so you can read it quickly
bevelThickness : 0,
bevelSize : 0,
bevelEnabled : false,
material : 0,
extrudeMaterial : 1,
amount : 10
}
),
new THREE.MeshLambertMaterial({color: 0xff8800})
);
mesh.position.set(0,0,0); // position the mesh
scene.add(mesh); // add it to the scene
// note the lowercase scene for the object instance scene. Need to chage that where you create it.
} // end of if(len > 1){
There is a lot of pedantic stuff there but you are clearly new to programming and bad habits are hard to break so start with good ones. Bugs and debugging are the worst part of programming. Debugging is the single most time consuming part of all programming (even for experienced professionals). The single biggest cause of bugs in all programing languages is bad style and or messy code. Writing clean consistent code makes your code easier to read and hence easier to debug. Try finding a missing { in 5000 lines of `{''s or a capital where a lowercase character should be (Hours debugging code while the simple error is right in front of you hidden in a mess can make or break being a coder)
Hope this helped..

What is the most efficient way to display 4 million 2D squares in a browser?

My display has a resolution of 7680x4320 pixels. I want to display up to 4 million different colored squares. And I want to change the number of squares with a slider. If have currently two versions. One with canvas-fillRect which looks somethink like this:
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
for (var i = 0; i < num_squares; i ++) {
ctx.fillStyle = someColor;
ctx.fillRect(pos_x, pos_y, pos_x + square_width, pos_y + square_height);
// set pos_x and pos_y for next square
}
And one with webGL and three.js. Same loop, but I create a box geometry and a mesh for every square:
var geometry = new THREE.BoxGeometry( width_height, width_height, 0);
for (var i = 0; i < num_squares; i ++) {
var material = new THREE.MeshLambertMaterial( { color: Math.random() * 0xffffff } );
material.emissive = new THREE.Color( Math.random(), Math.random(), Math.random() );
var object = new THREE.Mesh( geometry, material );
}
They both work quite fine for a few thousand squares. The first version can do up to one million squares, but everything over a million is just awful slow. I want to update the color and the number of squares dynamically.
Does anyone has tips on how to be more efficient with three.js/ WebGL/ Canvas?
EDIT1: Second version: This is what I do at the beginning and when the slider has changed:
// Remove all objects from scene
var obj, i;
for ( i = scene.children.length - 1; i >= 0 ; i -- ) {
obj = scene.children[ i ];
if ( obj !== camera) {
scene.remove(obj);
}
}
// Fill scene with new objects
num_squares = gui_dat.squareNum;
var window_pixel = window.innerWidth * window.innerHeight;
var pixel_per_square = window_pixel / num_squares;
var width_height = Math.floor(Math.sqrt(pixel_per_square));
var geometry = new THREE.BoxGeometry( width_height, width_height, 0);
var pos_x = width_height/2;
var pos_y = width_height/2;
for (var i = 0; i < num_squares; i ++) {
//var object = new THREE.Mesh( geometry, );
var material = new THREE.Material()( { color: Math.random() * 0xffffff } );
material.emissive = new THREE.Color( Math.random(), Math.random(), Math.random() );
var object = new THREE.Mesh( geometry, material );
object.position.x = pos_x;
object.position.y = pos_y;
pos_x += width_height;
if (pos_x > window.innerWidth) {
pos_x = width_height/2;
pos_y += width_height;
}
scene.add( object );
}
The fastest way to draw squares is to use the gl.POINTS primitive and then setting gl_PointSize to the pixel size.
In three.js, gl.POINTS is wrapped inside the THREE.PointCloud object.
You'll have to create a geometry object with one position for each point and pass that to the PointCloud constructor.
Here is an example of THREE.PointCloud in action:
http://codepen.io/seanseansean/pen/EaBZEY
geometry = new THREE.Geometry();
for (i = 0; i < particleCount; i++) {
var vertex = new THREE.Vector3();
vertex.x = Math.random() * 2000 - 1000;
vertex.y = Math.random() * 2000 - 1000;
vertex.z = Math.random() * 2000 - 1000;
geometry.vertices.push(vertex);
}
...
materials[i] = new THREE.PointCloudMaterial({size:size});
particles = new THREE.PointCloud(geometry, materials[i]);
I didn't dig through all the code but I've set the particle count to 2m and from my understanding, 5 point clouds are generated so 2m*5 = 10m particles and I'm getting around 30fps.
The highest number of individual points I've seen so far was with potree.
http://potree.org/, https://github.com/potree
Try some demo, I was able to observe 5 millions of points in 3D at 20-30fps. I believe this is also current technological limit.
I didn't test potree on my own, so I cant say much about this tech. But there is data convertor and viewer (threejs based) so should only figure out how to convert the data.
Briefly about your question
The best way handle large data is group them as quad-tree (2d) or oct-tree (3d). This will allow you to not bother program with part that is too far from camera or not visible at all.
On the other hand, program doesnt like when you do too many webgl calls. Try to understand it like this, you want to do create ~60 images each second. But each time you set some parameter for GPU, program must do some sync. Spliting data means you will need to do more setup so tree must not be too detialed.
Last thing, someone said:
You'll probably want to pass an array of values as one of the shader uniforms
I dont suggest it, bad idea. Texture lookup is quite fast, but attributes are always faster. If we are talking about 4M points, you cant afford reading data from uniforms.
Sorry I cant help you with the code, I could do it without threejs, Im not threejs expert :)
I would recommend trying pixi framework( as mentioned in above comments ).
It has webgl renderer and some benchmarks are very promising.
http://www.goodboydigital.com/pixijs/bunnymark_v3/
It can handle allot of animated sprites.
If your app only displays the squares, and doesnt animate, and they are very simple sprites( only one color ) then it would give better performance than the demo link above.

Categories

Resources