Fedor

Taxing textures: any ideas to speed up DynamicTextures

Recommended Posts

Still working on my sculpting tool, I am now testing basic texture paint functions.

I am using a single dynamictexture that is only updated just before rendering IF anything has been painted. When I keep the texture small - say 1024^2 -, the speed is reasonable, when increasing it - to 4096^2 - performance drops dramatically.

I am pretty sure it is not the drawing functions or the canvas, I have created applications in the past that draw much more in a single frame then I do now. (see http://www.traxeditor.com if you like)

It looks like it is the Dynamictexture update() method. Does anyone have any ideas how to speed it up or work around it? Is there an other way to paint the texture?

 

Share this post


Link to post
Share on other sites

Sorry I don't have any insights into DynamicTexture update() but could you use smaller texture tiles (like in Google Maps for instance) where each small texture is only copied to the correct location on the larger texture on pen up or when pen down moves into next tile? Or possibly the larger texture only needs to be created on save. I suspect using many smaller tiles like this would increase performance.

Share this post


Link to post
Share on other sites

Actually when you use a 4096² dynamicTexture, you use also an underlying canvas 2d sized at 4096² from the html5 context 2d canvas API. 

If you update this texture each frame, you clear and redraw this underlying 2d canvas each frame. This operation may be not that fast depending on the canvas 2d implementation of your browser. Anyway it's always far more slower than the identical operation in genuine webGL.

Maybe should you either not redraw the canvas each frame, etiher use a small canvas, etiher ... both :-)

Share this post


Link to post
Share on other sites

@jerome and @NasimiAsl my application does not clean the canvas or redraws a lot - it just ad the last brush strokes on the canvas. This involves drawing the brush image 30 times on average per frame. This is nothing to the canvas element performance wise. The size of the canvas does not really affect performance while drawing.

I did test 'stop drawing each frame', now using update() at certain intervals. Here are some benchmarks:

Action: continuous drawing by holding down the mouse button and moving it over the mesh, measured on Firefox

  1. Drawing on 1024 texture, update every frame (provided something has been drawn): around 20FPS, allmost smooth
  2. Drawing on 4096 texture, update every frame (provided something has been drawn): around 5FPS, drawing stutters
  3. Drawing on 4096 texture, update only every 100ms: 3FPS (15FPS on Chrome), drawing stutters heavily
  4. Drawing on 4096 texture, update only every 200ms: 5FPS, drawing stutters heavily
  5. Drawing on 4096 texture, update only every 500ms: 8FPS, drawing stutters heavily
  6. Drawing on 4096 texture, not updating at all: 20FPS, but we don't see any results 
  7. Drawing on 4096 texture, not updating and drawing commented out in the onMouseMove: ALSO 20FPS (same on Chrome), but we don't see any results  

I took the frame rate from the debuging layer. It looks like texture update is not the only problem. Holding the mouse button down somehow also eats a lot of time. But it could also be the scene.pick(scene.pointerX, scene.pointerY)-function which I had not commented out. Tested that:

8. Drawing on 4096 texture, not updating and drawing commented AND picking out in the onMouseMove: 45FPS (55FPS on Chrome) --- WOW!!!!

Tested it a second and third time. Looks like Picking is even more time consuming! I'm now trying to mock up a demo in Playground to proof it and allow further investigation.

 

 

Share this post


Link to post
Share on other sites

this is a good start to investigate (althoug your PG doesn't fit the usual standard with the function createScene() to be sure to be rightly evaluated by the PG engine). As you can see in this example (sps + rollover) :  http://www.babylonjs-playground.com/#2FPT1A#68 

the pickInfo obejct, what emit a ray, can be called each frame in the render loop without a significative FPS loss. So I suppose all this will need some profiling to get where the time is spent.

Share this post


Link to post
Share on other sites

Do you base that conclusion, that Picking can be called every frame, on this example? There is a difference: this scene has a lot of objects with each just a few faces. My scene only has one object with a lot of faces. That may be significant.

I tested it and put the picking function in the draw function so it is now executed every frame. Frame rate when doing nothing drops from 60FPS to around 40FPS. 

http://www.babylonjs-playground.com/#460BZJ#13

But in a sence you are right, it is not the only problem... I tried switching of the texture.update() (which fired every 10th second) and the FPS went back to 60:

http://www.babylonjs-playground.com/#460BZJ#14

 

 

Share this post


Link to post
Share on other sites

Stopping the default render loop (Line 63) speeds this up quite a bit for me, from about 25fps when moving mouse over the sphere to 60fps. 

http://www.babylonjs-playground.com/#460BZJ#15

Edit:

Actually that just caused the fps to stop updating. But the double render prob isn't helping anyway.

Looks like you're right regarding faces being the issue, as if fastcheck is not enabled, it will loop over every single one ( see https://github.com/BabylonJS/Babylon.js/blob/master/src/Mesh/babylon.subMesh.ts#L218), which is over a million in your pg.

Share this post


Link to post
Share on other sites

Ok, but in fact I am doing the same: the texture.update is my example is also in it's own loop...

And you leave out Picking here, which seems to be the biggest problem...

 

Share this post


Link to post
Share on other sites

@sable, Fastcheck does not help me here. I need accuracy when picking UV coordinates. Fastcheck does picking using only the bounding box.

And what do you mean with the double render - I have one scene.render() in the code...

 

Share this post


Link to post
Share on other sites

The PG engine already calls scene.render() for you.

The PG engine only expects that you create a function called createScene() returning a Scene object. All the rest is done, run, managed by the PG engine.

var createScene = function() {  // stuff; return scene; }

 

Please have a look as the basic PG code skeleton : http://playground.babylonjs.com/

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.