unfoldedtorus Posted June 28, 2018 Share Posted June 28, 2018 (edited) Hi everybody, I'm struggling with performance issues using pixijs. I just have to slide few rectangles using a mask and animating borders and tinting after sliding animation. It should be simple and easy to reach high FPS even on mobile, in fact it easily slows down this is the profiler result during an animation: It seems the call ticker.update() is eating up a lot. I've changed my code, stopped ticker and called only when needed but the results is that on mobile devices it slows down even under 15fps I'm managing fps my self trying to complete the slide in 200ms and animations in the following 200ms. so I start calling requestAnimationFrame 12 times and reducing if it takes longer than 200ms. during each step I change position of all tiles on one column/row and call ticker.update() (I believe is something really basics that should not slow down at all) I use a mask to hide some tiles in some places of the board, could be the mask an issue? Someone can give me some hint? the following video shows how the animation works (I'm not going to advertise here, I've already posted my game in the right section) the game is already playable online: http://unfoldedtorus.com (in case a live sample would be better) thanks in advance Michele Edited June 28, 2018 by unfoldedtorus mispelling Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted June 29, 2018 Share Posted June 29, 2018 Game rqeuires me to login before i play. Also kasperksy doesn't like your hosting and is blocking it. I can't say anything pixi-related about the profiler dump you gave, i just see that your "update" method is slow. Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted June 29, 2018 Author Share Posted June 29, 2018 (edited) Hi Ivan, thanks for your quick reply. you can play even without login, just dismiss login form and click single player. probably kaspersky doesnt like non https sites. the server is from ovh in france I dont think this is an issue. I can post here part of the code I use for animating: (the whle file is 900 lines I hope the following is enough to understand whan am I doing wrong) /*the following is the code I call in each requestAnimationFrame to animate text and borders of each tile. then I call ticker.update() as shown in the function below similarly I animate position and tint*/ const animateTileBorderAndText = (tileObj, steps, _color, radius, textSize, strokeThickness, _config) => { let pixiTile = tileObj.tile; let graphicsData = pixiTile.graphicsData[0]; let shape = graphicsData.shape; let textStyle = pixiTile.children[0].style; let textInc = (textSize - textStyle.fontSize) / steps; let strokeInc = (strokeThickness - textStyle.strokeThickness) / steps; let prevColor = graphicsData.fillColor; let color = _color !== null ? _color : prevColor; let alpha = pixiTile.alpha; let h = shape.height; let w = shape.width; let rad = shape.radius; let radiusInc = (radius - rad) / steps; let r = (prevColor & 0xFF0000) >> 16; let g = (prevColor & 0x00FF00) >> 8; let b = prevColor & 0x0000FF; let rc = (color & 0xFF0000) >> 16; let rg = (color & 0x00FF00) >> 8; let rb = color & 0x0000FF; let redStep = (rc - r) / steps; let greenStep = (rg - g) / steps; let blueStep = (rb - b) / steps; let paintColor = prevColor; let goPaint = color !== prevColor; let animate = (s) => { if (s === steps) { textStyle.fontSize = textSize; textStyle.strokeThickness = strokeThickness; //pixiTile.tint = color; return true; } if (goPaint) { r += redStep; g += greenStep; b += blueStep; paintColor = (r << 16) + (g << 8) + b; } textStyle.fontSize += textInc; textStyle.strokeThickness += strokeInc; pixiTile.clear() pixiTile.beginFill(paintColor, alpha) pixiTile.drawRoundedRect(0, 0, h, w, rad + radiusInc * (s + 1)) pixiTile.endFill(); }; return animate; }; /*i've tested this code calling console.time() and I'm sure this is not the source of slowness, maybe the way it changes pixi object could be the cause of slowness in ticker.update()*/ /*here the code that calls the above one for each tile and then calls ticker.update inside requestAnimationFrame*/ const slideRow = (direction, conf, tilesMap, pointerDown, pointerUp, SEM) => { let moveOf = conf.tileFullSize; let moveOfAbs = 1; let rowIdx = getRowToSlide(pointerDown.y, pointerUp.y, conf.tileFullSize); if (direction === SLIDE_LEFT) { moveOf = -moveOf; moveOfAbs = -1; conf.torusModel.slideRowLeft(rowIdx); //slide the underling model } else { conf.torusModel.slideRowRight(rowIdx); //slide the underling model } conf.torusModel.valuate(); /**set number value of hidden tiles */ beforeSlideSetRow(rowIdx, direction, tilesMap, conf); let slideFns = []; let postSlideFns = []; let rowToSlide = tilesMap[rowIdx]; for (let i = -1; i <= conf.cols; ++i) { rowToSlide[i].col += moveOfAbs; /**push function to change position of tiles in given steps */ slideFns.push(slideSingleTile(rowToSlide[i], moveOf, 'x', conf, SEM, tilesMap)); } let steps = conf.animationSteps; let s = 1; let startTime = performance.now(); const postSlideAnimations = (time) => { if (s < steps) { for (let i = 0; i < postSlideFns.length; ++i) { postSlideFns[i](s); } s++; /**update pixi ticker when all position are updated */ conf.ticker.update(); } else { //update internal configuration data conf.updateSlideTimeDelta(time - startTime); PUBSUB.publish(conf.SLIDE_CODE, conf.torusModel.getData()); conf.updateSlideSteps(); conf.SEMAPHORES.slide = true; return 0; } return requestAnimationFrame(postSlideAnimations); }; const animateSlideRow = (time) => { if (s < steps) { for (let j = 0; j < slideFns.length; ++j) { slideFns[j](s); } s++; conf.ticker.update(); } else { conf.updateSlideTimeDelta(time - startTime); /**generate function to animate background borders and text */ slideFns.forEach(f => postSlideFns.push(...f(s))); console.log(postSlideFns); conf.ticker.update(); /*run borders-text-background animations*/ steps = conf.animationSteps; s = 0; startTime = performance.now(); return postSlideAnimations(startTime); } return requestAnimationFrame(animateSlideRow); }; animateSlideRow(startTime); }; if it comes out to be time consuming for you but you think there's a way to make it run faster I can pay for your consultancy thanks a lot Michele Edited June 29, 2018 by unfoldedtorus no js highlight Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted June 29, 2018 Share Posted June 29, 2018 Well, first i see that postSlideAnimations is calling pixi update and the function that calls it also calls pixi ticker update. Pixi ticker calls render() each time, so, multiple times in a frame. Text resize can be extremely slow, because it causes resize of temporary canvas. First switch off the text and look at results, if its text, then you probably have to specify text canvas size before you start animation, I cant recommend anything except reading "PIXI.Text" code. However, it will still call one "texImage2d" to upload that text to videomemory, that can be slow too. If you prerender all the characters ytou need or use bitmap text or try pixi-sdf plugin, it can save performance. But first you test if the text is actual problem. For each tile you have one graphics and one text - that's two drawcalls with a shader switch - extremely not effective. How many tiles are there? For PC its fine to have up to 200DC, for mobile its 50DC. So, 25 tiles max on mobiles. Dumping all the texts and graphics borders in prepared atlas (with photoshop or whatever you can use) will drop it down to 1 shader switch and 1 drawcall total. I know its difficult to understand because i use terms not from Pixi API but from low-level Webgl/2d context, but every html5 coder have to research that as soon as they get their first "2FPS" issue PixiJS has good architecture and collection of general things that you can use fast. Its highly likely that you'll deal by using sprites and stuff, or patching Text to suit your needs. There are many settings you can try when you read the code and understand how it actually works with webgl. And if pixi cant give you something,c certain plugins can. Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted June 30, 2018 Author Share Posted June 30, 2018 I'm going to try all the methods you said. and let you know in this post. thanks a lot Quote Link to comment Share on other sites More sharing options...
jonforum Posted July 1, 2018 Share Posted July 1, 2018 on my side your update are perfect at (~~16ms) the fps meter are not ok on your game, because you not have a constant update. You maybe stop the game update between click. Try to add a constante update, and look your fps, you will alway keep 60. But if you stop update and start again each time click called , the fps meter will go crazy, but it not the reel frame rate, he will need time to be stabilize. So on my side , it not seem to lag! . Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 3, 2018 Author Share Posted July 3, 2018 Hi Jonforum, yes the ticker is stopped at the beginning, and is updated only when a slide gesture is catched just to complete the slide animation. So you suggest to start the ticker and let it go even if the player is looking at the ranking? or just thinking? When there are few tiles on desktops no problems occurs. the issue is on mobile where using pixi the way I used is slower than making this animation with pure html dom element+css. Btw I'm going to try your advice too as well as test cahcingAsBitmap and texturifying tiles, so animating using filters or mask instead of changing textsize and border radius at each update. I'll let you know my results as soon as I complete the test. thanks Quote Link to comment Share on other sites More sharing options...
jonforum Posted July 3, 2018 Share Posted July 3, 2018 11 minutes ago, unfoldedtorus said: Hi Jonforum, yes the ticker is stopped at the beginning, and is updated only when a slide gesture is catched just to complete the slide animation. So you suggest to start the ticker and let it go even if the player is looking at the ranking? or just thinking? When there are few tiles on desktops no problems occurs. the issue is on mobile where using pixi the way I used is slower than making this animation with pure html dom element+css. Btw I'm going to try your advice too as well as test cahcingAsBitmap and texturifying tiles, so animating using filters or mask instead of changing textsize and border radius at each update. I'll let you know my results as soon as I complete the test. thanks yes i suggest this only for help you debugging , but keep your idea to update only when the player slide gesture for your final deployed project. Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 4, 2018 Author Share Posted July 4, 2018 So I did some testing, using ticker.update() where necessary or letting it go does not affect performance. While Creating textures starting from rectangles and animating them improves a lot. Baiscally its twice as fast moving 100 tiles, increasing to 300 tiles in case of sprites affects just a little bit the performance while slows down twice using Graphics objects with text. I've created a little repo to show these results https://github.com/MikBin/pixi-tiles here there are screeenshots of Chrome DevTools: 100 tiles comparison (left using GRAPHICS right using SPRITES) 300 tiles left using GRAPHICS right using SPRITES Now my issue is how to animate rounded borders and numbers if I have Sprites? Is there any way to "blend" two textures gradually step by step where at the beginning and ending of animation just one of the two have to be visible? I hope its clear what I mean. I've been looking on pixijs examples and searching a way using mask or filters but I'm getting a little lost. maybe is something easy to reach and one of you already know best practice to do it. thanks for your help Quote Link to comment Share on other sites More sharing options...
jonforum Posted July 5, 2018 Share Posted July 5, 2018 The only easy way to animate sprite it use pixi spriteAnimations , you can make a animation on afterEffect and make a spriteSheet with texturePacker. Or also another pro way, it use Spine2d. The hard way, if you not have software to create your animations, it to use pixi graphics and rendering textures. Example: Create multiple graphics square with multiple round border value + (pre Rendering as a textures). https://codepen.io/staff0rd/pen/eByzQm?editors=0010 And add all textures to a spriteAnimations or create your own animations rendering. https://pixijs.io/examples/#/basics/spritesheet.js or you can also try use only PIXI.Sprite.from(renderTextures); And use sprite.renderable = false, or merge texture sprite in a update and change the sprite._texture = MyTextureListe[i++].. and use _texture._updateUvs() for update. You have a lot of way. Maybe another guy will have a better idea, unfortunately this is the only idea that can come to my mind to help you. Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 5, 2018 Author Share Posted July 5, 2018 Hi jonforum thanks for your help. Actually you gave me a lot of ideas. Do you know which one could be better for performance? if you don't I'm going to test them. and thanks a lot again! Quote Link to comment Share on other sites More sharing options...
jonforum Posted July 5, 2018 Share Posted July 5, 2018 hard to say, maybe you should better test on your side with your specific Setup and code. Here my performance test with spine2d animation (x350 complexe very high resolution) And this one with SpriteAnimation , it very more fast than the spine2d aniamtion. But maybe if you juste hack the texture update, it will very more fast. if you make your own test, keep us informed it is always useful to have statistics in different context. Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 5, 2018 Author Share Posted July 5, 2018 Great. Many Thanks Jonforum. I'll post my results as I did before thanks again Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 5, 2018 Author Share Posted July 5, 2018 Tests done by animatin using a sequence of precomputed textures; Performance is very good, here some screenshots: (100 sprites on left, 500 on right) just on question about rendered textures it seems are not antialised, here a sample: Is there any workaround? Quote Link to comment Share on other sites More sharing options...
jonforum Posted July 5, 2018 Share Posted July 5, 2018 try look in PIXI.settings.RENDER_OPTIONS.antialias or PIXI.settings.RENDER_OPTIONS.forceFXAA Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 5, 2018 Author Share Posted July 5, 2018 I'm going to test both. many thanks Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 5, 2018 Share Posted July 5, 2018 I dont think it'll help. forceFXAA doesnt even work in pixi-v4. "antialias" can fix only straight lines if they are edges of your texture, and for insides there are filtering modes, like `PIXI.SCALE_MODES.LINEAR` and NEAREST. By default its linear so its ok, make sure that you didnt enable NEAREST somewhere. Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 6, 2018 Author Share Posted July 6, 2018 NEAREST is not set. while antialiasing is in main render. so there are no ways to create antialiased textures? Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 7, 2018 Share Posted July 7, 2018 search generateCanvasTexture through the docs, it might help. Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 9, 2018 Author Share Posted July 9, 2018 ok. I'm going to try this. thanks Quote Link to comment Share on other sites More sharing options...
unfoldedtorus Posted July 9, 2018 Author Share Posted July 9, 2018 great it works! thanks a lot Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.