Delete multiple items with the same name? - javascript

I am adding "n" number of circles on the scene.
var radius = 1;
var segments = 32;
var circleGeometry = new THREE.CircleGeometry( radius, segments);
function generateCircles(){
//scene.remove(circle);
var count=0;
while (1000> count) {
circle = new THREE.Mesh (circleGeometry, material);
scene.add (circle);
count ++;
}
}
Is it effective to do it this way?.
In my code I call this function, and every time you call it, it all goes back slower, I guess it's because there are more objects in the scene. What can I do?
Each time the function is called, I need to completely erase from the memory stage the circles that were generated.
http://jsfiddle.net/v8oxsxtc/

If you don't need to move or change the circles after adding them to the scene, it would be more efficient to merge them all into one Mesh and add them to the scene as one Mesh. Then, you can simply remove that one Mesh from the scene before generating more circles:
var radius = 1;
var segments = 32;
var circleGeometry = new THREE.CircleGeometry(radius, segments);
var circlesMesh;
function generateCircles() {
if (circlesMesh) { scene.remove(circlesMesh); }
circlesMesh = new THREE.Mesh(circleGeometry, material);
var count = 0;
while (count++ < 999) {
THREE.GeometryUtils.merge(circlesMesh, new THREE.Mesh(circleGeometry, material));
}
scene.add(circlesMesh);
}

Related

How to remove corner indices of 2D array?

Working on forward ray tracing algorithm using Three.js. Just created this example by using a 2D array. Notice that the Spotlight is not involved here except the parsing of its location.
So in order to shoot lines I declared:
startPoint = position of SpotLight
endPoint = hard code for the first value
Then I create a nested for loop (17x17) and I create a ray every iteration with the usual way as shown below:
forward_RT(){
//Declare the start and end points of the first ray (startPoint never changes )
var f_ray_startPoint = new THREE.Vector3(spotLight.position.x, spotLight.position.y, spotLight.position.z);
var f_ray_endPoint = new THREE.Vector3(-490, 0, 495); //Hard Coding for 1st position of ray endPoint
//Declare material of rays
var ray_material_red = new THREE.LineBasicMaterial( { color: 0xff0000, opacity: 10} );
var ray_material_yellow = new THREE.LineBasicMaterial( { color: 0xffff00 } );
var ray_material_green = new THREE.LineBasicMaterial( { color: 0x00ff00 } );
//Declare ray geometry
var ray_geometry = new THREE.Geometry();
ray_geometry.vertices.push( f_ray_startPoint );
ray_geometry.vertices.push( f_ray_endPoint );
//Declare values for 2d array grid
var rows = 17;
var cols = 17;
var rayOffset = 60; //Offset of ray every X iteration
for(var x=0; x<rows; x++){
for(var z=0; z<cols; z++){
//Declare a ray
var f_ray = new THREE.Line(ray_geometry.clone(), ray_material_red);
f_ray.geometry.vertices[1].x = f_ray_endPoint.x;
scene_Main.add(f_ray); //Add ray into the scene
f_ray_endPoint.x += rayOffset; //Add offset every new ray
if(f_ray_endPoint.x >= 490){
f_ray_endPoint.x -= (cols * rayOffset);
}
}
f_ray_endPoint.z -= rayOffset;
}
}
For the graphics folks, I have noticed that opacity doesn't work on the material of the Three.Line.
Is There a way to add transparency on the line?
Main Question
How to block the iteration so that the corners of the SpotLight will not be drawn? In other words, I want access only to rays that are inside the white circle (SpotLights).
If you want to maintain a discreet grid of X, Y rays and discard those outside the circle, you could use the built-in method Vector2.distanceTo(). Simply keep your loop as it is, but do a distance calculation to the center of the circle, if the distance is larger than the radius, skip to the next loop:
// Find the center of your circle
var center = new THREE.Vector2(centerX, centerZ);
// Assign radius of your circle
var radius = 17 / 2;
// Temp vector to calculate distance per iteration
var rayEnd = new THREE.Vector2();
// Result of distance
var distance = 0;
for (var x = 0; x < rows; x++) {
for (var z = 0; z < cols; z++) {
// Set this ray's end position
rayEnd.set(x, z);
// Calculate distance to center
distance = rayEnd.distanceTo(center);
// Skip loop if distance to center is bigger than radius
if (distance > radius) {
continue;
} else {
// Draw ray to x, z
}
}
}
A few recommendations:
I would use a single LineSegments object, instead of multiple Line objects for faster rendering (Three.js is faster at rendering one object with many vertices than many objects with few vertices).
You could generate the geometry around the origin (from -8 to 8), and calculate the distance to (0, 0), and then displace it by 60 units with position.x = 60, for simplicity.

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

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.

Create 50000+ Text Particles in THREE.js

Im trying to create a character particlesystem with more than 50000 single letters.
Found something similar but written with XG here.
Problem with creating this is the performance of the application.
Here some short pseudo code:
var field = new THREE.Object3D();
for (var i = 0; i < 50000; i++) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.fillText(char);
var texture = new THREE.Texture(canvas)
texture.needsUpdate = true;
var spriteMaterial = new THREE.SpriteMaterial({map: texture});
var sprite = new THREE.Sprite(spriteMaterial);
sprite .position.set(x, y, z);
field.add(textSprite);
}
scene.add(field);
So my question is now, is there some example or something where i can see the best way to create this number of textsprites?!
I've also tried this example without a good result.
As vals noted, you are creating material and a texture for every letter. The fact that you are creating a canvas too is beside the point, that's just a one-off overhead.
Every texture you create will have to take up graphics memory. After the fact of texture, every material is computed separately in every render pass, so for 50000 materials you have a lot of computation.
A simple way to speed what you have up would be to use look-up tables:
var materialLUT = {};
function getMaterialForLetter(c){
var m = materialLUT[c];
if(m === void 0){
//material doesn't exist, lets create it
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
context.fillText(c);
var texture = new THREE.Texture(canvas)
texture.needsUpdate = true;
m = materialLUT[c] = new THREE.SpriteMaterial({map: texture});
}
return m;
}
var field = new THREE.Object3D();
for (var i = 0; i < 50000; i++) {
var spriteMaterial = getMaterialForLetter(char);
var sprite = new THREE.Sprite(spriteMaterial);
sprite.position.set(x, y, z);
field.add(textSprite);
}
scene.add(field);
Another thing i see that should be improved here is use of PointCloud. And lastly - I think it would be best to use a single texture and get relevant characters via UV.

How to rotate each particle on its axis in a Particle system in THREE.js?

I am making a space scene in which I am using a particle system to make group of asteroids,
I want to rotate each asteroids on its axis. I am using following code for making a particle system.
var asteroidGeometry = new THREE.Geometry();
for(var i=0;i<=10000;i++)
{
asteroidGeometry.vertices.push( new THREE.Vector3( Math.random()*10000-5000, Math.random()*10000-5000, Math.random()*10000-5000 ) );
}
var asteroidtexture= THREE.ImageUtils.loadTexture("images/asteroids.png");
var asteroidMaterial = new THREE.ParticleBasicMaterial({color: 'white',size:500,map:asteroidtexture,alphaTest: 0.8});
asteroids = new THREE.ParticleSystem(asteroidGeometry,astroidMaterial);
scene.add(asteroids);
If I will do something like
asteroid.position.x +=0.1;
then this will rotate whole system. Is it possible to rotate each particle on its on axis?
Individual vertices in a THREE.Geometry instance are accessible via its vertices array.
I found a tutorial that explains how to animate particles in a particle system independently. Here's the relevant section of the update animation loop with some minor modifications.
function update() {
var pCount = particleCount;
while (pCount--) {
var particle = particles.vertices[pCount];
if (particle.position.y < -200) {
particle.position.y = 200;
particle.velocity.y = 0;
}
particle.velocity.y -= Math.random() * .1;
particle.position.addSelf(particle.velocity);
}
particleSystem.geometry.__dirtyVertices = true;
renderer.render(scene, camera);
requestAnimFrame(update);
}

Categories

Resources