what is the recommended way, in three js, to render (mostly) static scene - three.js

I have a scene that is mostly static, i.e. without user interaction it doesn't change (animations).
The user interacts with the scene. For example:
when the user clicks on certain location in a map, another image opens in another pane
the user may move the camera by moving the mouse
etc...
Originally I implemented the rendering via animate(), which calls:
function animate() {
requestAnimationFrame( animate );
render();
controls.update();
}
This works fine (in terms of response) except that
the rendering happens constantly, which is not necessary.
for one of the admin pages, which does not show the scene, I'm getting runtime errors when the scene does not exist, but the rendering still goes on...
So I re-implemented the rendering by calling, explicitly, after user action which change the scene
render();
controls.update();
This requires more work, because I have to cover all the cases where the scene changes.
In one of the cases, the behaviour is not as expected (the rendered scene is black and explicit call to render does not fix the problem).
The link here says that if your scene is static, there is no reason for an animation loop.
The link here suggests to use animate().
My questions:
Is explicit render, a good pattern to use in three js for static scenes?
Are there pros to render only when needed, instead of calling animate which renders constantly, when this is not needed?
In terms of resource load in general

The link here says that if your scene is static, there is no reason for an animation loop.
The answer of the respective stackoverflow question is also the correct one. The second link is unrelated to question whether to use on-demand rendering or not.
In general, having an animation loop requires more resources since you constantly render no matter if the scene changes or not. However, certain application like 3D viewers (without animation playback) do not need to do this. It's sufficient to render only when certain events happen (e.g. user interaction).
Is explicit render, a good pattern to use in three js for static scenes?
Yes, it is. It is a good pattern for 3D applications in general.
Are there pros to render only when needed, instead of calling animate which renders constantly, when this is not needed? In terms of resource load in general
The app requires less resources which is always a good thing. E.g. mobile device will save a lot of battery and laptops or desktops will be more quiet.

Related

Suggested architecture to re-render scene only if scene has changed?

I have a complex web application, with several sub-views / widgets that add objects to the main scene.
Most simple THREE.js examples have a continous render loop, that re-renders the scene periodically.
This seems like a waste of ressources to me.
Therfore, I only want to re-render the scene if something has changed.
However, the sub-views / widgets do change things (like position of objects) in the scene on their own.
Is there something like a "scene.hasChanged" flag, that I can use to deceide if the scene needs to be rerendered? Or do I have to implement a parallel flag or notification structure myself?
Or is there another common solution to this?
Based on what you have written so far, it seems you have to implement a custom solution. Certain three.js examples like webgl_loader_gltf do not use an animation loop but utilize change events from the controls. The relevant line of code is
controls.addEventListener( 'change', render );
However, if more factors than just the user interaction trigger renderings, it's necessary to build some sort of notification/event system by yourself.
three.js R113

Microsoft Edge WebGL lose context

I m creating a THREE.js (latest version, r71) app, and sometimes I need to manually delete the 3D scene to display classic 2D content. So, what I do is clearing all variables like scene or renderer, and killing the WebGL context using renderer.forceContextLoss()
This method works fine on Firefox or Chrome, but it is not supported on Interner Explorer or Microsoft Edge, which cause multiple lags on my web page. I can't find a workaround to do this properly as I do in Firefox or Chrome.
If someone has a tip, feel free to tell me :)
Thanks
Try using two canvas tags and put one over the other as suggested here,
put them in a parent div tag then use the following css.
position:absolute;
left:0px;
top:0px;
EDIT:
In response to your comment, allow me to clarify my understanding.
You want to draw 2d and 3d.
You are resetting the webGL context.
You can't have 2 contexts to the same canvas simultaneously and I assume you want to use a a different context for your 2d content.
If this assumption is correct:
I am suggesting that you have 2 canvases and contexts simultaneously, one with your webGL context and 3d content, and another with the context you want to use for 2d content. Then you overlay these canvases by using absolute position, such that it looks like there is one canvas.
This means you never have to reload assets to switch contexts, just make sure you so the above canvas is transparent.
Also if you wrap the canvas in a div tag, it will not be at the top left of the page.
But If my assumption is wrong:
perhaps you don't want to use another context and just wish to clear the screen, in which case you should not call forceContextLoss()
If you wish to continue to use the webGL context, but clear the screen you should use clear()

Threejs objmtlloader black model

I'm new to ThreeJS and I made this example which shows one of our model.
http://petrie3dtesting.museums.ucl.ac.uk/3DFootCover/index.html
I created a Petrie3Dviewer and in the HTML page created a viewer object which takes as input an .obj and .mtl file. Strangely tho, the objects shows up BLACK and then when I start interacting the texture comes up. I tried everything I think: different browsers, making the texture smaller, different computers, nothing I get a random behaviour all the time.
I tried on FIrefox, Chrome mainly.
It seems that I need to force the rendering once the obj file is loaded but the OBJMTLLoader.js does not provide any event for it.
Really many thanks for the help.
Best,
GC
You should call this.DoRender in your Animate function to render the frame.
this.Animate = function() {
this.orbitControls.update();
this.Animate();
requestAnimationFrame(this.Animate.bind(this));
}
At the moment you call your render function only when the user changes the perspective with the OrbitControls. And because your texture is loaded asynchronously it is not ready the first time when you render the frame.

EaselJS and multi layered canvas system: performance tuning, game developing, event handling

I'm an engineer and we are currently porting our Red5 + Flash game into a Node.js + Easeljs html5 application.
Basicly: it's a board game, not an rpg. The layer system means we have multiple canvasses, based on functionally. For example there is a static background stage, with images. There is a layer for just the timers.
At default, all canvas size is 1920x1080, if needed we downscale to fit to the resolution.
The first approach used kinetic.js, but the performance fallen when the game got complex. Then we switched to easel, because it's abstraction level is lower, so we can decide how to implement some more function, not just use the provided robust one.
I was optimistic, but now it's starting to show slowness again, that's why I want to look deeper inside and do fine performance tuning. (Of course everything is fine in Chrome, Firefox is the problem, but the game must run smoothly on all modern browser).
The main layer (stage) is the map, contains ~30 containers, in each there is a complex custom shape, ~10 images. The containers are listening to mouse events, like mouseover, out, click. Currently, for example on mouseover I refill the shape with gradient.
Somehow, when I use cache, like the way in the tuts the performance get even worse, so I assume I'm messing up something.
I collected some advanced questions:
In the described situation when can I use cache and how? I've already tried cache on init, cacheUpdate after fill with other color or gradient, then stage.update(). No impact.
If I have a static, never changing stage cache doesn't make sense on that layer, right?
What stage.update() exactly do? Triggering the full layer redraw? The doc mentions some kind of intelligent if changed then redraw effect.
If I want to refill a custom shape with new color or gradient I have to completely redraw its graphics, not just use a setFill method, right?
In easel there is no possibility to redraw just a container for example, so how can I manage to not update the whole stage, but just the one container that changed? I thought I can achieve this with caching, cache all containers the just update the one that changed, but this way didn't work at all for me.
Does it make sense to cache bitmap images? If there are custom shapes and images in a container what is better? Cache the container or just the shape in container.
I found a strange bug, or at least an interesting clue. My canvas layers totally overlapping. On the inferior layers the mouseover listening is working well, but the click isn't on the very same container/object.
How can I produce a click event propagation to overlapped layers those have click listeners? I've tried it with simple DOM, jquery, but the event objects were far away from what canvas listeners wanted to get.
In brief, methods and props I've already played with bare success when tried tuning: cache(), updateCache(), update(), mouseEnabled, snapToPixel, clear(), autoClear, enableMouseOver, useRAF, setFPS().
Any answer, suggestion, starting point appreciated.
UPDATE:
This free board game is a strategy game, so you are facing a world map, with ~30 territories. The custom shapes are the territories and a container holds a territory shape and the icons that should be over the territory. This container overlapping is minimal.
An example mouse event is a hover effect. The player navigate over the territory shape then the shape is getting recolored, resized, etc and a bubble showing up with details about the place.
Basically, maximum amount of 1-3 container could change at once (except the init phase -> all at this time). Not just the animations and recoloring slow in FF, but the listener delay is high too.
I wrote a change handler, so I only stage.update() up on tick the modified stages and the stages where an animation is running (tweenjs).
In my first approach I put every image to the container that could be needed at least once during the game, so I only set visible flags on images (not vectors).
Regarding caching:
There are some strange caching-issues, somehow the performance can drop with certain sizes of the caching rectangle: CreateJS / EaselJS Strange Performance with certain size shapes
(2) Depending on how often you call stage.update();
(3)
Each time the update method is called, the stage will tick any
descendants exposing a tick method (ex. BitmapAnimation) and render
its entire display list to the canvas. Any parameters passed to update
will be passed on to any onTick handlers.
=> Afaik it rerenders everything if not cached
(4) Yes.
(5) No. (I don't know of any)
(6) If the content's of the container don't change often, I'd cache the whole container, otherwise the container will be reconstructed every frame.
I have a question though: Why do you use multiple canvases? How many do you use? I could imagine that using multiple canvases might slow down the game.
How many sprites do you use in total?
2: if your layer or stage doesn't change, don't call stage.update() for that layer (so it doesn't gets rerendered, gives me a much lower cpu!)
For example, keep a global "stagechanged" variable and set this to true when something has changed:
createjs.Ticker.addEventListener("tick",
function() {
if (stagechanged)
{
stagechanged = false;
stage.update();
}
});
(or do you already use this, as stated in your "update"?)
4: I found a way to update for example the fill color :)
contaier1.shape1.graphics._fillInstructions[0].params[1] = '#FFFFFF';
(use chrome debugger to look at the _fillInstructions array to see which array position contains your color)
5: I found a way to just paint one container :)
//manual draw 1 component (!)
var a = stage.canvas.getContext("2d");
a.save();
container1.updateContext(a); //set position(x,y) on context
container1.draw(a);
a.restore();

hiding movieclip, rendering performance

I'm developing a rendering engine for a game i am currently building..
I have a main camera (rectangle) that determines what needs to be rendered (thing within it's boundaires)
I am using a bitmap rendering method for the background and that all works fine.
but for the character i am using a movieclip over the top.
when the character goes out of the camera's view is it 100% neccesary to set visible=false?
atm the game is running at 30 FPS (as intended) and everything is sweet, i just wanted to ask out of curiosity.
Is flash clever enough to not bother with movieclip outside of the scene boundaires?
Thanks in advance,
Rory
According to http://help.adobe.com/en_US/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e3e.html Flash won't render if an object is outside of Stage boundaries:
Display list
The hierarchy of display objects that will be rendered as visible
screen content by Flash Player and AIR. The Stage is the root of the
display list, and all the display objects that are attached to the
Stage or one of its children form the display list (even if the object
isn’t actually rendered, for example if it’s outside the boundaries of
the Stage).
In my experience display objects added to the stage cause a performance hit even if they are not rendered.
Setting visible to false causes a much lower performance hit, but still a small hit.
Removing unnecessary display objects from the display list is a documented performance tip from adobe as well.
Of course, if you only have a few dislay objects it might not be worth the effort, but if we talk about large amounts of display objects I strongly recommend removing them from the display list.

Resources