Jump to content

dynamic texture feedback


jerome
 Share

Recommended Posts

Hello guys/gals,

 

Here's a short feedback about dynamicTexture usage.

The soft I'm coding intends to display live network monitoring :

  • data -bandwith, nb of unicast/multicast/tcp/udp packets, etc - are collected (snmp) server-side at a regular frequency from many switches down the local company network and written in a json file published on the web server,
  • the client (the browser) displays a 3D graph representing this network and sends periodical xhr requests to the web server to get the fresh data,
  • it then updates graphically (animated particles ? not yet implemented) this graph and displays textual data,
  • between two collects, textual data (numeric values) evolve according to some simple tween to give the user the feeling of a continuous variation, and thus the understanding of how they vary (increasing/decreasing, slowly/fast) instead of snapshot-like display.

So, I use dynamicTexture objects.

Assuming I have, say, 40 measures to display, I create 40 sprites at fixed position on my graph.

Before any updates in the render loop, all my browsers display and animate the graph with arcRotateCamera at 60 fps.

 

first case :

each measure to be displayed has got its own spriteManager and its lone sprite.

each spriteManager is textured with a different dynamicTexture.

each frame, every dynamicTexture is updated ( drawText() ) with new text values.

 

=> performance falls down dramatically to 30 fps with Chromium and about 8-9 fps with FF (Linux user : I don't have IE but I guess it will compete with chrome)

 

second case :

a global dynamicTexture is created.

each measure to be displayed has got its own spriteManager and its lone sprite.

each spriteManager is textured with  the global dynamicTexture (to be then offsetted).

each frame, the global dynamicTexture is update once with new text values concatened as I know the canvas2D fillText() is a very costly operation.

 

=> quite good improvment : Chromium at 60 fps and FF now at 30 fps !

 

third case :

a global dynamicTexture is created.

a global spriteManager is created.

each measure to be displayed hos got the same global spriteManager but its own sprite.

the global spriteManager is textured with the global dynamicTexture.

each frame, the global dynamicTexture is update once with new text values concatened.

 

=> exactly the same results than the second case.

 

So ...

BJS is quite optimized (who could think different here ?) as it can manage as well 1 or 40 spriteManagers with no performance drop.

DynamicTexture is a powerful but dangerous tool.

It's not a pure BJS problem (I had the same results with threejs and a home made dynamicTexture-like implementation) but a well known among html5 2D game coders canvas2D problem.

The canvas2D fillText() method is really really costly in terms of performance and should then be used as little as possible in animations.

As moreover it can't handle automatic new lines, changing colors, fonts, size in the same text line (you need a call with new parameters each time to do this), it could be fast a mess to display many different text values.

 

 

Hope it will help you guys stuck in the same text updating problems ;-)

 

 

 

 

Link to comment
Share on other sites

I just made a last test to refine what was really the cause of the performance drop as I knew fillText() is expensive but not that expensive : we update score values, infos, etc each frame in 2D games.

 

So my last test was to not use dynamicTexture.drawText() and still write many text values each frame (not only once) in one global texture (dataTexture var).

 

the content of my render loop looks like :

var  i = 1;var dataHeight = 50;dataTexture.drawText("", 0, 0, null, null, "transparent");  // lazy way to clear the former textctx.font = "36px arial";     // ctx = dataTexture.getContext(); set once beforectx.fillStyle = "#000000";for (var mes in metrics) {  var text = someFunction(metrics[mes]);  ctx.fillText(text, 5, i * dataHeight);  i++; // dataTexture.update(false);  // if uncommented here, performance drops !}dataTexture.update(false);

=> FF at 30 fps and Chromium at 60 fps

 

Here we are between first and second case :

I use only one global texture for my sprites but I still call fillText(), as many times as the number of sprites, per frame.

I just call the dynamicTexture.update() once each frame.

 

So it seems the real bottleneck, though the relative cost of canvas 2D fillText(), is the dynamicTexture.update() :-(

If the update() method is called after each fillText(), so many times per frame, the performance drops dramatically (state machine ?),

If it's only called once after all the fillText(), so only once per frame, performance keeps good.

 

Maybe would it be pertinent not to call update() method within the dynamicTexture.drawText() method and explicity call it to have then the text passed to the texture somewhere else in the code when the developer needs it ?

 

line 79 : https://github.com/BabylonJS/Babylon.js/blob/master/Babylon/Materials/Textures/babylon.dynamicTexture.ts#L79

 

don't know ...

Link to comment
Share on other sites

Another thing about dynamicTexture :

 

The clearColor parameter is used to fill a rectangle background before the text is written onto this colored rectangle.

This color can be obviously set to "transparent" or to "rgba(0, 0, 0, 0)" if you need a transparent background.

Therefore if you use such a transparent background, you should know that the texture won't be cleared if you update an existing texture : a transparent background is filled above the former one and your text is written... above the former one.

If you use some colored background with no transparency, the clearColor parameter will do the job as the former content is repainted with your plain color.

 

If you really need to clear the texture content (so, mandatory only on transparent backgrounds) you have to explicity use the canvas2D clearRect() method.

 

example : a blue text on a transparent background, this can be updated in the render loop (incremental var i)

var texture = new BABYLON.DynamicTexture("DynamicTexture", 512, scene, true); // instanciated before render loop...// in the render loopvar text = "My nice text #"+i;var ctx = texture.getContext();ctx.clearRect(0, 0, 512, 512);  // sized to the dynamic texture. This actually really clears the canvas !texture.drawText(text, 5, 200, "normal bold 48px Arial", "blue", null, false);

Maybe a dynamicTexture.clear() method would be useful so ?

I wish I could code it but I haven't learnt enough typescript to do it right so far :-(

Link to comment
Share on other sites

I'm afraid that you would have coded, tested, pushed it, then have some holidays to hawaii again before I just could compile a simple hello-world-script in typescript here.

So please do it if you don't mind.

 

But I promise I'll get into TS (and then submit PR) soon !

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...