Jump to content

BABYLON.Texture from spritesheet


Vousk-prod.
 Share

Recommended Posts

Hello boys (and girls, maybe... I hope :P),

 

Is it possible to create a new BABYLON.Texture from a particular area of texture file instead of the whole file ?

 

In some cases, to avoid too much http requests, it would be usefull to download only a few spritesheets and be able to assign a sprite to a BABYLON.Texture instead of whole a file, is that possible ?

Link to comment
Share on other sites

Hello boys (and girls, maybe... I hope :P),

 

Is it possible to create a new BABYLON.Texture from a particular area of texture file instead of the whole file ?

 

In some cases, to avoid too much http requests, it would be usefull to download only a few spritesheets and be able to assign a sprite to a BABYLON.Texture instead of whole a file, is that possible ?

 

I've been working on this. You can do it but it's not built in or anything, you have to wrangle the uv scale and offset of each material. Also, at least in my tests I had to leave two blank pixels between sprites to avoid bleeding.

 

It would be might handy if BJS supported one of the various spritesheet formats.

Link to comment
Share on other sites

If you want to use one single texture with different u and v offsets you will have to either change the UV coordinates (suprisingly, it was discussed a few days ago here - http://www.html5gamedevs.com/topic/13420-display-one-video-on-multiple-objects-with-the-videotexture/) or "duplicate" the texture and set different offsets an scales.

The current relation between texture and ov offset and scale is 1-to-1. You can't change one without the other, but you can count on the browser's and babylon's cache mechanism to actually support that. create different textures using the same url for a single image, and it won't be downloaded multiple times. This is the safest solution I see for regular images. You can then set new u and v offsets:

http://www.babylonjs-playground.com/#1GLIH9

this is just a simplified version of the materials demo in the playground. check how many requests are sent and you will see the file is only loaded once.

Link to comment
Share on other sites

Yep I know that a single file is never downloaded multiple times, that's a big great feature of BJS !! :wub:

I'm not sure changing the materials UV is the right way to go, they're pretty complex, coming from objects unwrapping and they're finely tuned for correct lightmapping, bump, etc...

 

I think it would be interesting to simply have a method that creates a BABYLON.Texture array from a single spritesheet (supporting one of the various spritesheet formats, as fenomas suggested).

For instance, if a 1024x1024 spritesheet contains 128x128 sprites, we'll get 64 BABYLON.Texture. We then use them as usual, no material UV modification needed.

Link to comment
Share on other sites

I think it would be interesting to simply have a method that creates a BABYLON.Texture array from a single spritesheet (supporting one of the various spritesheet formats, as fenomas suggested).

For instance, if a 1024x1024 spritesheet contains 128x128 sprites, we'll get 64 BABYLON.Texture. We then use them as usual, no material UV modification needed.

 

That would be 2D canvas operations - draw the texture into a canvas and then read out subsections. BJS already does something similar to convert textures to power-of-two sizes. However, the point of using texture atlases is generally to avoid texture binds, and splitting one into separate textures would lose that benefit. 

 

I expect the ideal thing would be for BJS to grok texture atlases in such a way that the user doesn't have to wrangle all the scales and offsets, but behind the scenes the whole atlas texture stays intact.

Link to comment
Share on other sites

This is a very simple function to implement - in the case of what you just suggested:

var imageUrl = "http://www.awsomeserver.com/someSillyCat.jpg";var meshesArray = getMyMeshes(); //well, this is up to you :-)var spriteWidth = 8;var spriteHeight = 8;for(var w = 0 ; w < spriteWidth ; ++w) {    for(var h = 0 ; h < spriteHeight; ++h) {        var texture = new BABYLON.Texture(imageUrl, myScene);        texture.uScale = 1/spriteWidth;        texture.vScale = 1/spriteHeight;        texture.uOffset = w - spriteWidth/2;        texture.vOffset = h - spriteHeight/2;        meshesArray[w*spriteHeight + h].material.diffuseTexture = texture;    }}

I have to admit I haven't tested this, but it should work.

Edited by RaananW
Link to comment
Share on other sites

Thanks RaananW for this example.

 

I like the idea, but I'm not sure it's totally perfs friendly...

for(var w = 0 ; w < spriteWidth ; ++w) {   for(var h = 0 ; h < spriteHeight ; ++h) {      textures[index++] = new BABYLON.Texture("textures/earth.jpg", scene);      texture.uScale = 1/spriteWidth;      texture.vScale = 1/spriteHeight;      texture.uOffset = (w - spriteWidth/2) + 0.5;      texture.vOffset = (h - spriteHeight/2) + 0.5;   }}

The idea of creating textures from a spritesheet is to avoid too much HTTP requests. For that, your idea is great. But this will create a lots of textures in memory. That's not a big deal for a realtime engine if those textures are small (at sprite's width and height resolution), but here those textures will be really big (at spritesheet's width and height resolution).

Pretty sure that will kill memory, particularly on mobile devices.

 

Apart from that, there also are some cases where we need to change texture's UV scale or offset for a particular object, but it will be impossible here, since that won't just change the  we will not change the aspect of the texture but also its content...

 

Is it possible to take a picture and to cut it in part and then to use that parts to create Texture objects ? That would do the trick.

Link to comment
Share on other sites

Or, as fenomas suggested, since the point of using texture atlases is generally to avoid texture binds, and splitting one into separate textures would lose that benefit, maybe BJS could have a method to assign to material a spritesheet texture (specifying which sprite to use). I don't know if this would be optimised or not in terms of performances.

Link to comment
Share on other sites

Hi, sorry, just saw your last message.

You are right, this will create quite a lot of textures with the same image, but i doubt it is using more memory (haven't tested thou), as the images come from babylon's cache and not the browser's cache - https://github.com/BabylonJS/Babylon.js/blob/master/Babylon/Materials/Textures/babylon.texture.ts#L65 . It is using the cache for the texture, and it is only stored once. So the only memory used is the texture class and not the image, which is not too large.

 

Setting the uv offset and scale on your own would be possible if you provide a certain "sprite manifest", much like the css sprite definitions. This of course requires the frameworks support, but I have to admit would be a nice feature. You could also do it already at the scene's file (set all of those variables by yourself), and then no need for any framework extension at all.

 

I am not sure what will one big texture improve, this has to be tested, but it is of course possible - put all textured loaded textures onto acanvas and store as as png in the cache (for example). Or use it directly. I believe however this will create unneeded load on the GPU, as this texture will have to be sent everytime the object is being rendered. And as png/jpg are totally not GPU optimized, that would mean that the entire texture will have to be decompressed. Not so nice when it comes to large textures...

Link to comment
Share on other sites

Yes, images files are stored in cache, but once the textures are instanciated in the engine they're allocated as separate objects in GPU memory, aren't they ? I do not exactly know how the GPU works but I think each different texture object allocated take its own space in GPU memory (and for realtime engine, the higher the resolution, the -very- higher memory amount needed).

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...