soylomass Posted July 23, 2018 Share Posted July 23, 2018 Hi, I have a problem with all my games related to optimization, and it's about how to draw huge sprites that form background/terrain. Examples: 1. deeeep.io This was my first one, it used Phaser, which used Pixi 2.x as renderer. It runs on canvas mode because in webgl mode it's much slower. In this game, the floor is created serverside as polygons, then the polygon points are sent to the client. In the client, I draw a squared tilesprite with the terrain design, then I write the polygon to a graphics object, and apply the graphics as a mask to the tilesprite. 2. raaaaft.io This game is made using pure Pixi v4, it runs on webgl by default. Something similar happens here. The islands are circles, with a pattern filling, so I create a square tilesprite, then I create a graphics, draw a circle on it, and then apply it as a mask to the tilesprite. When drawing huge islands, it uses a lot of resorces. -------------------- Is there a better way to do these? I'm sure there is, but I've never been able to think of one. I've tried for example drawing a small vesion of these and then scaling them, but both the patterns and the borders look blurred. I'd be extremely thankful if anyone could help me think of a solution. Thanks! Quote Link to comment Share on other sites More sharing options...
jonforum Posted July 24, 2018 Share Posted July 24, 2018 you can split you huge BG sprites in multi textures. Take a look to texturePacker The maximum texture size for mobile devices should not exceed 2048. Bigger textures might not be displayed on some devices or might cause jittering sprites. For pc version, don't worry about memory if your pc are not a old dinosaure. And for "canvas mode because in webgl mode it's much slower" !!! hum no i don't think so , canva mode are very slow vs webGl thencologie. My game, on my side, run at 12 fps in canvas mode vs 60fps in webGl! If am not wrong , only cool feature for use canvas mode it for allow all blendmodes. http://pixijs.download/dev/docs/PIXI.html#.BLEND_MODES Also Pixi 2.x it obsolete and very old ! You will maybe have a lot of performance issue with this verison. Recommande you to use last versions. I can not give more help sorry, because i don't know the api Phaser. Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 24, 2018 Author Share Posted July 24, 2018 1 hour ago, jonforum said: you can split you huge BG sprites in multi textures. Take a look to texturePacker The maximum texture size for mobile devices should not exceed 2048. Bigger textures might not be displayed on some devices or might cause jittering sprites. For pc version, don't worry about memory if your pc are not a old dinosaure. And for "canvas mode because in webgl mode it's much slower" !!! hum no i don't think so , canva mode are very slow vs webGl thencologie. My game, on my side, run at 12 fps in canvas mode vs 60fps in webGl! If am not wrong , only cool feature for use canvas mode it for allow all blendmodes. http://pixijs.download/dev/docs/PIXI.html#.BLEND_MODES Also Pixi 2.x it obsolete and very old ! You will maybe have a lot of performance issue with this verison. Recommande you to use last versions. I can not give more help sorry, because i don't know the api Phaser. I changed the title because it may lead to misunderstandings. The sprites use small images, but they are repeated using big tilesprites. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 24, 2018 Share Posted July 24, 2018 If your textures are pow2 and not in atlas (wrapMode=REPEAT), you can creae mesh with certain UV's corresponding to vertices. its possible to convert graphics to such mesh. I'll try to dig out code from one guy who uses it. Quote Link to comment Share on other sites More sharing options...
unrealnl Posted July 24, 2018 Share Posted July 24, 2018 Hey, Ivan made me aware of the question. he pushed me in the right direction and ill share the code. Masks are slow, its better to convert a graphic shape to a mesh and draw the shape using its vertices. // In the case of my editor, somewhere i set the body.mySprite.data.tileTexture to the lookup name of the tileTexture, e.g. 'grass.jpg' this.updateBodyTileSprite = function (body) { const tileTexture = body.mySprite.data.tileTexture; if (tileTexture && tileTexture != "") { let tex = PIXI.Texture.fromImage(tileTexture); tex.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT; if (!body.myTileSprite) { //body.originalGraphic is the shape we want to get the mesh from game.app.renderer.plugins.graphics.updateGraphics(body.originalGraphic); const verticesColor = body.originalGraphic._webGL[game.app.renderer.CONTEXT_UID].data[0].glPoints; let vertices = new Float32Array(verticesColor.length / 3); let i; let j = 0; for (i = 0; i < verticesColor.length; i += 6) { vertices[j] = verticesColor[i]; vertices[j + 1] = verticesColor[i + 1]; j += 2; } const indices = body.originalGraphic._webGL[game.app.renderer.CONTEXT_UID].data[0].glIndices; let uvs = new Float32Array(vertices.length); for (i = 0; i < vertices.length; i++) uvs[i] = vertices[i] * 2.0 / tex.width; const mesh = new PIXI.mesh.Mesh(tex, vertices, uvs, indices); body.mySprite.addChild(mesh); body.myTileSprite = mesh; } body.myTileSprite.texture = tex; } else if (body.myTileSprite) { body.myTileSprite.mask = null; body.myTileSprite.parent.removeChild(body.myTileSprite); body.myTileSprite = undefined; } } ivan.popelyshev and soylomass 1 1 Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 24, 2018 Author Share Posted July 24, 2018 4 hours ago, unrealnl said: Hey, Ivan made me aware of the question. he pushed me in the right direction and ill share the code. Masks are slow, its better to convert a graphic shape to a mesh and draw the shape using its vertices. ... Wow! Thanks for sharing this! You gave me a good reason to migrate Deeeep to pure Pixi, as phaser 2 doesn't have Mesh. Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 25, 2018 Author Share Posted July 25, 2018 Hi, could it be that a mesh with a repeating texture only works in WebGL mode? In canvas the meshes are invisible, unless I configure the uvs so as they draw a stretched texture, in that case it works on both Canvas and WebGL. In all cases baseTexture.wrapMode is set as PIXI.WRAP_MODES.REPEAT, I only change de uvs values: I've triangulated all the polygons so the meshes are triangles, drawn as : let mesh = new PIXI.mesh.Mesh(tex, vertices, indices, DRAW_MODES.TRIANGLES) (with and without the last argument) 0 and 1 uvss in Canvas: 0 and 1 uvss in WebGL: Bigger uvs in WebGL: Bigger uvs in Canvas: Meshes aren't visible, but no error shown. Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 25, 2018 Share Posted July 25, 2018 Yep, that hack is only for webgl. If you need canvas, you can enhance pixi graphics CanvasRenderer so it accepts a texture and creates a CanvasPattern like TilingSprite does. Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 26, 2018 Author Share Posted July 26, 2018 59 minutes ago, ivan.popelyshev said: Yep, that hack is only for webgl. If you need canvas, you can enhance pixi graphics CanvasRenderer so it accepts a texture and creates a CanvasPattern like TilingSprite does. When I thought all my problems were solved ? I don't think that's at the reach of my capabilities, but what part of CanvasRenderer should I look at? CanvasMeshRenderer? Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 26, 2018 Share Posted July 26, 2018 No, you should look how TilingSprite works and move that behaviour on Graphics, add a secret 'texture" and use it to create pattern Pixi is not friendly to canvas2d but the architecture is good enough to put there better implementations. Good Luck with it! soylomass 1 Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 26, 2018 Author Share Posted July 26, 2018 3 hours ago, ivan.popelyshev said: No, you should look how TilingSprite works and move that behaviour on Graphics, add a secret 'texture" and use it to create pattern Pixi is not friendly to canvas2d but the architecture is good enough to put there better implementations. Good Luck with it! I've achieved a result using the method used by @george here: http://www.html5gamedevs.com/topic/15223-piximesh-textured-polygon-from-box2d-a-question-of-triangles-uvs/?tab=comments#comment-86335 Basically, editing MeshSpriteRenderer.prototype._renderDrawTriangle and replacing the drawImage at the end with the canvasPatter from tilingsprite. It looks pretty good, but the performance is awfull, and degrades over time until the game crashes (without drawing anything else). I know that culling will help with this, but is there any kind of optimization I could add to this? Thanks in advance EDIT: I just noticed that that draw function is constantly called, that's why the fps degrade over time. I'll implement some state storing the pattern on the mesh, and will try to reutilise the canvas pattern to see if it improves performance. Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 26, 2018 Author Share Posted July 26, 2018 The above solution with the constant canvasPattern creation fixed, storing it in the mesh object, works at 60fps, but with frequent fps drops that cause micro-stuttering. I'll try to see what else I can do to improve the performance. When I'm done, I'll post the result here. ivan.popelyshev 1 Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 26, 2018 Share Posted July 26, 2018 You have my respect soylomass 1 Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 26, 2018 Author Share Posted July 26, 2018 Update: Reutilising canvas patterns that share the same texture, finally I got constant 60fps! Drawing all the hundreds of triangles that form the whole map! Thats a 30x improvement from using tilesprites and masks in the way I was using them in Phaser ? Thanks to all of you for your support, now I'll continue with rewriting the Deeeep's client. PD: The solution was to edit lib/mesh/canvas/CanvasMeshRenderer.js's MeshSpriteRenderer.prototype._renderDrawTriangle function, replacing: context.drawImage( textureSource, 0, 0, textureWidth * base.resolution, textureHeight * base.resolution, 0, 0, textureWidth, textureHeight ); with: // create a nice shiny pattern! // TODO this needs to be refreshed if texture changes.. var imageUrl = texture.baseTexture.imageUrl; if(!_canvasPattern[imageUrl]) { var baseTexture = texture.baseTexture; const baseTextureResolution = baseTexture.resolution; // cut an object from a spritesheet.. const tempCanvas = new core.CanvasRenderTarget(texture._frame.width, texture._frame.height, baseTextureResolution); // Tint the tiling sprite /*if (this.tint !== 0xFFFFFF) { var tintedTexture = CanvasTinter.getTintedTexture(mesh, mesh.tint); tempCanvas.context.drawImage(tintedTexture, 0, 0); } else { tempCanvas.context.drawImage(baseTexture.source, -texture._frame.x * baseTextureResolution, -texture._frame.y * baseTextureResolution); } this.cachedTint = this.tint;*/ tempCanvas.context.drawImage(baseTexture.source, -texture._frame.x * baseTextureResolution, -texture._frame.y * baseTextureResolution); _canvasPattern[imageUrl] = tempCanvas.context.createPattern(tempCanvas.canvas, 'repeat'); } context.fillStyle = _canvasPattern[imageUrl]; context.fill(); As you see, I'm storing the canvasPatterns in a variable on that file, I'll try to make that cleaner. Also, I've commented the tint section because I'm not using tint right now. Now, the only thing that's left is figuring out why in Canvas there's a separation between all triangles, while in WebGL there isn't, but this isn't that important. (note: not talking about the big separation on the left, but the micro separations between all triangles, look at the center) Thanks again for all your help! Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 26, 2018 Share Posted July 26, 2018 you dont have to use Mesh for canvas, Graphics will be faster because its mapped into natural vector format (moveTo,lineTo), add a texture to graphics and use the pattern inside GraphicsCanvasRenderer. May be that'll be faster because it doesnt need extra "cull" calls. In v5 Graphics will support both webgl and canvas texture fills. EDIT: or you can use moveTo/lineTo in your extension of Mesh class, instead of culling. Better to make new class that extends Mesh than changing Mesh itself - that can be made into v4 plugin! soylomass 1 Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 26, 2018 Author Share Posted July 26, 2018 17 minutes ago, ivan.popelyshev said: you dont have to use Mesh for canvas, Graphics will be faster because its mapped into natural vector format (moveTo,lineTo), add a texture to graphics and use the pattern inside GraphicsCanvasRenderer. May be that'll be faster because it doesnt need extra "cull" calls. In v5 Graphics will support both webgl and canvas texture fills. EDIT: or you can use moveTo/lineTo in your extension of Mesh class, instead of culling. Better to make new class that extends Mesh than changing Mesh itself - that can be made into v4 plugin! Hi, I'll try one of those solutions once I get back home. About Pixi 5, will the migration be straightforward? (That it will be easier than migrating from phaser 2 to Pixi 4 Is out of doubt ?) Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 26, 2018 Share Posted July 26, 2018 the internals of Mesh and Graphics are different. Yep, you can build your own phaser on pixi-v4, and, when the time comes, migrate to v5. Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 29, 2018 Author Share Posted July 29, 2018 On 7/26/2018 at 3:47 PM, ivan.popelyshev said: the internals of Mesh and Graphics are different. Yep, you can build your own phaser on pixi-v4, and, when the time comes, migrate to v5. I have a question, if I want to create a simple object like a parallelogram with a plain color background, what's the most performant way? Using a Graphics object with drawPolygon, or using a Mesh? Considering both WebGL and Canvas. I've looked for the performance differences between Graphic and Mesh but didn't find an answer. Thanks Quote Link to comment Share on other sites More sharing options...
ivan.popelyshev Posted July 29, 2018 Share Posted July 29, 2018 i guess both will work the same way. parallelogram can be just a sprite with skew transform and tinted color, "PIXI.Texture.WHITE" that way you can batch them , if you need it, of course soylomass 1 Quote Link to comment Share on other sites More sharing options...
soylomass Posted July 29, 2018 Author Share Posted July 29, 2018 2 hours ago, ivan.popelyshev said: i guess both will work the same way. parallelogram can be just a sprite with skew transform and tinted color, "PIXI.Texture.WHITE" that way you can batch them , if you need it, of course Wow, just find out there are those kind of transforms. Wish I had read more before starting to code games. Thanks again for your extremely helpful support! 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.