In my current project Im using Threejs for buildin a level with meshes. All the graphical stuff with camera, scene, projector, renderer and so on is done in one object. For test purposes I want to reset the whole scene with different parameters, for example different level sizes.
Because I want measure time of an algorithm I want a "full" reset. So my current approach is deleting the div-box containing the scene/canvas and deleting the whole object which has the threejs code. After this I instantiate a new object for the graphical level. Unfortunately doing this like 10 times in a row results in drastical performance loss.
I also tried deleting all meshes in the scene with scene.delete() and deleting things like scene, renderer and so on before deleting the whole object. But still performance issues.
So how can I achieve a whole reset of all graphical webgl components without performance loss?
Thanks in advance.
Deleting everything to do with three won't solve the problem, because even as your WebGLRenderer is deleted, it never releases it's WebGL context, so you end up with multiple WebGL contexts running simultaneously. Performance will degrade for each additional live context. Eventually, a limit will be hit.
Refer to this question for a hacked way to release the context.
Releasing the context is not supported by three.js since you really shouldn't need to recreate the context. In my case, using Angular with multiple application phases where some use WebGL and some don't, I simply persist an instance of the renderer in the page-level controller, such that I can access it in subcontrollers and so never need to recreate the WebGLRenderer nor, thus, the context.
Two functions that may increase your performance resetting: for each object obj in your scene, try both:
scene.remove( obj );
renderer.deallocateObject( obj );
Related
This is a question about javascript and three.js coding style conventions. I prefer to use the latest ES-whatever conventions.
I'm wondering if instead of doing the usual:
var scene = new THREE.Scene();
var cube = new THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshBasicMaterial(0xffffff))
scene.add(cube)
it would be ok to store the mesh object (and other objects, maybe lights and even camera) as properties of the scene object:
const scene = new THREE.Scene(); // or var, but that's not my question
scene.cube = THREE.Mesh(new THREE.BoxGeometry(1,1,1), new THREE.MeshBasicMaterial(0xffffff))
scene.add(scene.cube)
I like the idea of having references to all the three.js objects underneath the scene namespace -- makes it easier for me to access them later. I know I could use this with .name and .getObjectByName but that takes more code and seems messier to me.
There is a field on Object3D derived objects called .userData that you can store stuff that should get saved/serialized. But as far as storing props directly on objects.. It works.. but kinda has potential for problems if you end up overwriting something or later revs of three make use of your property name...
Edit: after reading the other posts here, they raise some good point, and I also wanted to throw out there that you can subclass the built-in three objects and make your own custom type that has your stuff. That might be tidier.
As far as separation of concern goes, you don't want to use Three's objects as data holders. It might seem like an easy way out, but will greatly reduce maintainability of your code. There is nothing preventing you from doing it today, though. Just consider, that you will have
scene.cube
scene.children[0] //same cube
scene.getObjectById(... cube id ...) //same cube
//... byName, ...byProperty etc. all pointing to the same cube
Remember, Scene extends Object3D with all its methods and properties, so, in the example scene below all objects are Object3D with each having children[] property.
[scene]
+----^-----------------------------+
[chairGroup] [light]
+--^--+-----+-----+-----+------+
[leg] [leg] [leg] [leg] [back] [seat]
Doesn't each node above look similar to DOM's Element?
I would encourage you to think about your scene as a tree. In fact, any UI is an n-tree of elements: web, mobile, X11 etc., and every UI framework is a tool to manipulate such tree. All approaches you use to manipulate DOM tree effectively work here.
Hence, below are various ways you can organize your code, from simple to more complex:
hello world rotating cube example is fine, 15-20 lines of code are ok as-is
rendering context: move scene, camera and renderer into some context object you can pass around your layers. Think of it as an equivalent of document in the browser.
high-level "Shadow DOM": organize a tree of your own components that each handle a group of 3d objects, make them react to events - external from UI clicks etc., or from Three, like visitor pattern during rendering. You can either keep references to 3d objects on these components, or recursively pass your structure to a function to adjust scene's hierarchy. Examples of such components in your tree could be Chair, Building, Planet, Starship etc.
data model: it might be tempting to store some data inside your components, but you should have a distinction between external data, usually a bit global, like numeberOfPlanets, timeOfDay etc., and internal data, like current rotation speed of a planet. Latter can be kept as part of your scene domain components.
full MVC: as with any UI, model-view-controller is applicable here. E.g. you can follow this intro into three.js MVC.
mediators, observers and usual workflows. See, e.g. my answer here.
... all the way to Redux-like immutable state management system
I hope, this answer will help people do some tactical architecture around Three.js that suits their project best.
I have a cool project with three.js, and everything work as intended. It displays some mesh in different canvas, and there is my issue.
The project aimed to display many, many canvas, and each one have his own context, and it reach the deadly limit of 16 live webGL contexts. Since it's wanted to display more than that in a page, I'm searching to turn around this restriction, by disabling a context when it's not actually displayed on seen page. When the user will scroll, context will be disabled/enabled so I can put as many context as I want.
I've found this function : renderer.forceContextLoss() and with this one I can force the context disabling. But I didn't found anything to relaunch it. I manage to detect a loss of context, but not its restauration
If you got any idea of how I can achieve that, feel free to give me some tips.
Thanks in advance !
This has been covered elsewhere but the easiest way to make it appear like there are multiple canvases is to just use one instance of three.js, make it cover the entire window, put place holder divs where you want to draw things, and then use element.getClientBoundingRect to set the scissor and viewport for each scene you want to draw in each element
There's an example here.
Here's the answer in StackOverflow from which that sample originates
https://stackoverflow.com/a/30633132/128511
This will use far less memory than using multiple canvases, each of which would need it's own data, it's own shaders, etc...
I'm working with ChemDoodle library for rendering complex chemical structures. Everything works fine, but with big molecules (about 20k atoms) it's working quite slow. I don't have much experience in graphics, but I think it might me because each atom is rendering independently - every time it's rerendering, it has to iterate over array of atoms (it should be buffered).
My idea was to create some structure, that would be calculated on init time and when render, only camera would change it's position. I don't need to manipulate with atoms, only use mouse to rotate/move whole molecule. Is something like this even possible and would it improve performance?
I would appreciate info if it's possible (or some other suggestions), ideally in pure WebGL, without ThreeJS..
I'm learning JavaScript canvas recently, and I came up two ways of making animations. I searched google for a while but cannot determine which way is correct.
Say I have want to render different objects doing different things on the canvas with 30 fps. There're 2 ways to achieve this.
For both 2 ways, there should be a main setInterval function that draw all objects in 30fps.
Every object has a nextframe(user_response) method, which changes the 'status' of this object according to user response, and is called by a main setInterval 30 times ps. The main setInterval need to pass user responses into each nextframe(...) in some way, and it calls draw for each object.
--The problem with this approach is that all nextframe for all objects are called per frame, taking system resources.
Objects implement their own animation methods withsetInterval. These methos get called according to user response, changing the object 'status' 30 times per second. And the main setInterval function only calls draw for each object in 30fps, behaving like 'taking pictures' of each object's status. The object statuses change independently in other threads. So there's always one main thread of 30fps running, and if there're m objects animated and n object not animated at the moment, there're (m+1) threads in total --The problem with this that when many objects are animated I have many threads running, which also takes system resources.
So, which one is a more appropriate method? or are they both wrong? :>
thank you in advance!
The second one is the good one. Except you should user requestNextAnimationFrame instead of setInterval.
To solve your problem of resources, you can add conditions in the draw() methods to avoid redrawing if it is not necessary. But I think you need to redraw for each frames because you must clear your stage in order to draw the moving objects.
Context :
I'm working on a pretty simple THREE.JS project, and it is, I believe, optimized in a pretty good way.
I'm using a WebGLRenderer to display lot's of Bode plot extracted from an audio signal every 50ms. This is pretty cool, but obviously, the more Bode I display, the more laggy it is. In addition, Bodes are moving at constant speed, letting new ones some space to be displayed.
I'm now at a point where I implemented every "basic" optimization I found on Internet, and I managed to get a 30 fps constantly at about 10.000.000 lines displayed, with such a bad computer (nVidia GT 210 and Core i3 2100...).
Note also i'm not using any lights,reflections... Only basic lines =)
As it is a working project, i'm not allowed to show some screenshots/code, sorry ...
Current implementation :
I'm using an array to store all my Bodes, which are each displayed via a THREE.Line.
FYI, actually 2000 THREE.Line are used.
When a Bode has been displayed and moved for 40s, it is then deleted and the THREE.Line is re-used with another one. Note that to move these, I'm modifying THREE.Line.position property.
Note also that I already disabled my scene and object matrix autoUpdate, as I'm doing it manually. (Thx for pointing that Volune).
My Question :
Do the THREE.Line.position modification induces some heavy
calculations the renderer has already done ? Or is three.js aware that my object did not change and
avoid these ?
In other words, I'd like to know if rendering/updating the same object which was just translated is heavier in the rendering process than just leaving it alone, without updating his matrix etc...
Is there any sort of low-level optimization, either in ThreeJS about rendering the same objects many times ? Is this optimization cancelled when I move my object ?
If so, I've in mind an other way to do this : using only two big Mesh, which are folowing each other, but this induces merging/deleting parts of their geometries each frames... Might it be better ?
Thanks in advance.
I found in the sources (here and here) that the meshes matrices are updated each frame no matter the position changed or not.
This means that the position modification does not induce heavy calculation itself. This also means that a lot of matrices are updated and a lot of uniforms are sent to the GC each frame.
I would suggest trying your idea with one or two big meshes. This should reduce javascript computations internal to THREE.js, and the only big communications with the GC will be relative to the big buffers.
Also note that there exists a WebGL function bufferSubData (MSDN documentation) to update parts of a buffer, but it seems not yet usable in THREE.js