recently I'm doing a project showing a spectrum.
Here is the official demo of dynamic update chart:
http://www.hcharts.cn/demo/highstock/dynamic-update
Now i wish to see if i could update 1000 points per second on the chart, specifically, execute addPoint() 1000 times over 1s. I wrote a chunk of code like this:
for(var i = 0; i < 1000; i++){
var x = (new Date()).getTime(), // current time
y = Math.round(Math.random() * 100);
series.addPoint([x, y], true, true);
console.log(count++);
}
soon i found it is unable to render on the web page. Then i console.log a variable, which started from 0 to 1000, after 200 it became very slow. Anyone who could give me a solution? thanks
Related
Let’s say I want to make 100 objects - for example cars, like the one you see here:
This car is currently comprised of 5 meshes: one yellow Cube and four blue Spheres
What I’d like to know is what would be the most efficient/correct way to make 100 of these cars - or maybe 500 - in terms of memory management/ CPU performance, etc.
The way I’m currently going about doing this is as follows:
Make an empty THREE.Group called “newCarGroup” -
Create the yellow rectangular Mesh for the body of the car - called “carBodyMesh”
Create four blue Sphere Meshes for the Tires called “tire1Mesh”, “tire2Mesh”, “tire3Mesh”, and “tire4Mesh”
Add the Body and the four Tires to the “newCarGroup”
And finally, in a FOR loop, create/instantiate 100 “newCarGroup” objects, adding each one to the SCENE at a random position
The code is below.
It's working perfectly well right now, but I’d like to know if this is the “proper”/best way to do this?
Consider it’s possible I might end up needing 1,000 cars - or 5,000 cars. So will this scale properly?
Also, I need to add more objects to the car: like 4 windows - actually make that 6 windows, to also include the front and back windshields, then four headlights, etc.
So the final Car Object alone may end up being comprised of 20 meshes - or more.
Being that I’m kinda new to THREE.JS I wanna make sure I develop good habits and go about this sort of thing the right way.
Here’s my code:
function makeOneCar() {
var newCarGroup = new THREE.Group();
// 1. CAR-Body:
const bodyGeometry = new THREE.BoxGeometry(30, 10, 10);
const bodyMaterial = new THREE.MeshPhongMaterial({ color: "yellow" } );
const carBodyMesh = new THREE.Mesh(bodyGeometry, bodyMaterial);
// 2. TIRES:
const tireGeometry = new THREE.SphereGeometry(2, 16, 16);;
const tireMaterial = new THREE.MeshPhongMaterial( { color: "blue" } );
const tire1Mesh = new THREE.Mesh(tireGeometry, tireMaterial);
const tire2Mesh = new THREE.Mesh(tireGeometry, tireMaterial);
const tire3Mesh = new THREE.Mesh(tireGeometry, tireMaterial);
const tire4Mesh = new THREE.Mesh(tireGeometry, tireMaterial);
// TIRE 1 Position:
tire1Mesh.position.x = carBodyMesh.position.x - 11;
tire1Mesh.position.y = carBodyMesh.position.y - 4.15;
tire1Mesh.position.z = carBodyMesh.position.z + 4.5;
// TIRE 2 Position:
tire2Mesh.position.x = carBodyMesh.position.x + 11;
tire2Mesh.position.y = carBodyMesh.position.y - 4.15;
tire2Mesh.position.z = carBodyMesh.position.z + 4.5;
// TIRE 3 Position:
tire3Mesh.position.x = carBodyMesh.position.x - 11;
tire3Mesh.position.y = carBodyMesh.position.y - 4.15;
tire3Mesh.position.z = carBodyMesh.position.z - 4.5;
// TIRE 4 Position:
tire4Mesh.position.x = carBodyMesh.position.x + 11;
tire4Mesh.position.y = carBodyMesh.position.y - 4.15;
tire4Mesh.position.z = carBodyMesh.position.z - 4.5;
// Putting it all together:
newCarGroup.add(carBodyMesh);
newCarGroup.add(tire1Mesh);
newCarGroup.add(tire2Mesh);
newCarGroup.add(tire3Mesh);
newCarGroup.add(tire4Mesh);
// Setting (x, y, z) Coordinates - RANDOMLY
let randy = Math.floor(Math.random() * 10);
let newCarGroupX = randy % 2 == 0 ? Math.random() * 250 : Math.random() * -250;
let newCarGroupY = 0.0;
let newCarGroupZ = randy % 2 == 0 ? Math.random() * 250 : Math.random() * -250;
newCarGroup.position.set(newCarGroupX, newCarGroupY, newCarGroupZ)
scene.add(newCarGroup);
}
function makeCars() {
for(var carCount = 0; carCount < 100; carCount ++) {
makeOneCar();
}
}
I’d like to know if this is the “proper”/best way to do this?
This is subjective. You say the method works great for your current use-case, so for that use-case, it is fine.
So will this scale properly?
The simple answer is: No. The more complex answer is: ...not really.
You're re-using the geometry and materials, which is good. But every Mesh you create has meta information surrounding it, which adds to your overall memory footprint.
Also, every standard Mesh you add incurs what is known as a "draw call", which is the GPU drawing that particular shape. Instead, take a look at InstancedMesh. This allows the GPU to be given instructions on how to draw the shape throughout the scene once. Yes, rather than drawing each cube individually, the GPU can draw all the cubes at the same time, and they can even have different colors and transformations. There are limitations to this class, but it's a good starting point to understanding how instancing works.
So i've been stuck for a while because i've been having trouble dynamically changing the shape of the vertices in a place geometry according to the frequency data of an mp3, I've been having 2 main problems:
1)The array generated by the mp3 has too many values and it is impossible to render out the vertices that fast and accordingly, i am getting the frequency data with this code.
var frequencyData = new Uint8Array(analyser.frequencyBinCount);
2) Re-Rendering the plane everytime frequencyData changes causes extreme performance issues to the point it does not render out anymore
I've been using simplex noise to cause the vertices to morph, and it does work until obviously i pass in frequency data and everything breaks, this is the code i'm trying to use to morph the vertices of the plane according to the music.
function adjustVertices() {
for (var i = 0; i < 100; i++) {
for (var j = 0; j < 100; j++) {
var ex = 0.5;
pgeom.vertices[i + j * 100].z =
(noise.simplex2(i / 100, j / 100) +
noise.simplex2((i + 500) / 50, j / 50) * Math.pow(ex, frequencyData[2]) +
noise.simplex2((i + 400) / 25, j / 25) * Math.pow(ex, frequencyData[2]) +
noise.simplex2((i + 600) / 12.5, j / 12.5) * Math.pow(ex, frequencyData[2]) +
+(noise.simplex2((i + 800) / 6.25, j / 6.25) * Math.pow(ex, frequencyData[2]))) /
2;
pgeom.verticesNeedUpdate = true;
pgeom.computeVertexNormals();
}
}
}
This is my plane object:
var pgeom = new THREE.PlaneGeometry(5, 5, 99, 99);
var plane = THREE.SceneUtils.createMultiMaterialObject(pgeom, [
new THREE.MeshPhongMaterial({
color: 0x33ff33,
specular: 0x773300,
side: THREE.DoubleSide,
shading: THREE.FlatShading,
shininess: 3,
}),
]);
scene.add(plane);
I am very grateful for the help, I am just doing my best in mastering three.js :)
I would check if the computeVertexNormals is what is taking the most time in that render loop, and then look into optimizing it, if you still require it.
You can optimize the normal calculation by building the mesh topology once at startup, since it doesn't change at runtime, making the recalc run in constant time.
Then reduce the vertex count until things become manageable. :)
The first answer is correct. Most likely computing vertex normals is causing the hit, and it's most likely happening because the Geometry method which you seem to be using creates a lot of new THREE.Vector3. If you profile this i imagine you'd see a lot of GC activity and not so much of computation time.
One more thing to consider since you only map one variable, is to move this computation in the shader. You could write your values to a texture and only update that. You would not have to refresh the vertex and normal buffers which are much larger than the texture you'd need to store just the input variable. You would also be able to do this computation in parallel.
So i just wanted to make a generator that generates a random value every 10 seconds. And instead it generates a random value every frame after 10 seconds of waiting. Please correct me.
var imgs = [];
var a = 0
function randomizea() {
a = int(random(5));
}
function setup() {
createCanvas(1400, 850);
// for (var i=0; i<5; i++) {
// imgs[i] = loadImage("data/img"+i+".png");
// }
}
function draw() {
background(150, 100, 150);
setInterval(randomizea, 1000);
// image(imgs[a], 0, 0);
text(a, 0, 50);
}
You should generally not use setInterval() with P5.js. Instead, rely on the timing mechanisms that P5.js already gives you.
Here's a simple example that would print something to the console every 10 seconds:
function draw(){
if(frameCount % 600 == 0){
console.log("here");
}
}
Since 60 frames fire per second, then 600 frames is 10 seconds. We use the % modulus operator to check that the frameCount variable is a multiple of 600, which means that we're at a multiple of 10 seconds.
You could also use the millis() function and check whether a certain time has elapsed.
Related posts:
How to make a delay in processing project?
How can I draw only every x frames?
Removing element from ArrayList every 500 frames
Timing based events in Processing
How to add +1 to variable every 10 seconds in Processing?
How to create something happen when time = x
making a “poke back” program in processing
Processing: How do i create an object every “x” time
Timer using frameRate and frame counter reliable?
Adding delay in Processing
Please also consult the P5.js reference for more information.
I'm trying to make a loop in p5.js that will draw small ellipses across the canvas. I've done something like this before, but the code was different.
There, when I wanted to try a loop, all I had to type was:
for (var i = 0; i < 200; i++) {}
The manual I'm using (Make: Getting Started with p5.js) tells me that the code to do this is similiar. This was an example it gave for drawing a bunch of lines:
for (var i = 20; i < 400; i += 8) {
line(i,40,i+60,80)
}
However, when I enter this code to even test it, it doesn't work. Can someone explain how to draw multiple small ellipses on the screen (I have variables set in place for the x and y coordinates of the ellipses so that they will be random)?
EDIT: This is a more full version of the code:
function draw() {
noStroke();
fill(fishCr,fishCg,fishCb);
arc(ellX,ellY,ellW,ellH,0,180);
arc(ellX+5,ellY-10,ellW/1.5,ellH/1.5,arcEl,50);
arc(ellX-45,ellY+20,ellW/1.5,ellH*1.5,340,110);
arc(ellX-60,ellY-10,ellW/1.5,ellH*2,arcT,40);
fill(0,200,255,0.5); //this is the start of the code in
//question
for (var i = 0; i < 200; i++) {
ellipse(bubX,bubY,5,5);
}
}
Please try to be more specific than saying it doesn't work. What exactly happens? What do you see in the JavaScript console?
You should also read up on a tutorial on for loops. Here is one I wrote for Processing, but the basic ideas are the same.
Your first for loop starts at 0 and increases by 1 until it reaches 200. Your second for loop starts at 20 and increases by 8 until it reaches 400.
Also note that you have an extra opening curly brace { in your second for loop.
If you still can't get it figured out, please post a MCVE that shows the problem. Good luck.
Edit: Take a look at your for loop:
for (var i = 0; i < 200; i++) {
ellipse(bubX,bubY,5,5);
}
Here you're drawing 200 circles, but you're drawing all of them at the same location, based on the bubX and bubY variables. You probably want to pass in random values here instead of the same variables every time.
createCanvas(500, 500);
function setup() {
for (var i = 0; i < 200; i++) {
ellipse(random(0, width), random(0, height), 5);
}
}
This creates a Canvas and draws 200 small circles at random locations.
Is this waht you are looking for?
I've drawn a linechart with g.raphael. I've made a custom x-axis with my own values. And now I want these values to be rotated 90 degrees, so they're vertical instead of horizontal.
To do that, I'm using raphaels rotate() function. And this works perfectly in both IE (8) and Opera. But in Firefox nothing happens, and Firebug prints this error
Unexpected value rotate(90 NaN Infinity) parsing transform attribute.
I can't find anything about this error elsewhere, and I can't see how it isn't correct. And even more so, I find it extremely weird that it works in the other browsers.
Anybody have a clue about this?
My code - where xcoor is a simple int list of values 0-30:
for (var i in xcoor) {
var dato = new Date();
dato.setDate(new Date().getDate() - i);
var xTxt = r.text(30 + (i * (725 / 30)), 315, dato.getDate() + '/' + (dato.getMonth() + 1)).rotate(90);
}
Well, after hours of googling, reading and more googling, I finally found a solution.
I still don't get why the first one doesn't work. But none the less I figured out a way that works in all the browsers:
for (var i in xcoor) {
var dato = new Date();
dato.setDate(new Date().getDate() - i);
var xTxt = blokCanvas.text(40 + (i * (725 / 30)), 315, dato.getDate() + '/' + (dato.getMonth() + 1))
xTxt.rotate(90, (40 + (i * (725 / 30))), 315);
}
The rotate-function comes in more different version. One of them is this
rotate(degrees, x, y)
Where degrees represents the number of degrees the item should rotate and x, y represents the coordinates of the point around which the item should be rotated.
Setting the x,y values to the same as the ones placing the item in the first place gives me the wanted result.
Yay!