How to import Textures and Images from a sprite sheet?

We can import Sprites from a sprite sheet using SpritePackedManager. But I could not find any clear-cut way to import Texture or HTMLImageElement from a sprite sheet. Is it even possible?

If not, is there any way to convert Sprite to Texture or HTMLImageElement?

Also, how do I use AssetsManager in combination with SpritePackedManager?

For textures you have to use UV mapping or uOffset/vOffset/uScale/vScale.

For HTMLImageElement I’m not sure it’s possible to do it in any performance-efficient way. You’d have to have a hidden canvas to blit the sprite to and then assign it like this: https://stackoverflow.com/a/18008563. But that’s really hacky and probably slow.

I think I’ll need to define width and height of the Texture too, along with offsets/scales.

How can I complete the following tasks?

  1. Load a sprite sheet using AssetsManager or any other loading technique
  2. Use individual sprites from the sprite sheet in GUI controls like Buttons and Images
  3. Use individual sprites from the sprite sheet as Textures like diffuse maps or normal maps for models

If it is not possible at the moment, can I post a feature request?

You’d use the whole spritesheet as the image for the texture, and adjust the offsets/scalings on the fly. You can calculate the scaling by dividing the width (or height, whatever is significant) of the whole sheet by the desired width of the single sprite. The offset you get by dividing the offset of the sprite in x/y pixels by the width/height of the whole sheet.

Of course if you need multiple sprites at once, you need multiple texture objects. You can just call .clone on them.

If I’m not mistaken there used to be an example/PG of that in the docs, but I can’t find it any more.

The only way you could do this (that I can think of) is taking a screenshot of a canvas (doesn’t have to be a babylon canvas, can be Pixi or vanilla JS) and then making an HTMLImageElement from that (see the StackOverflow link). Maybe someone else has a better idea…

Actually if you set it all up in the beginning, the performance won’t be half bad. Only if you want to change the sprites you traverse half the browser’s lines of C++ each time. Another option is to cache all the HTMLImageElements. Do you just want to load everything beforehand in one big file, or do you want to do animations etc.?

For GUI icons this would be a great feature actually. I think I would use it too.

Thanks for the replies.

This can be helpful: CSS Image Sprites

I want to set it all up in the beginning, and cache all the HTMLImageElements as well as Textures.

Basically all images used in GUI will be kept in a single PNG file, and all diffuse maps will be kept in another PNG file. I’ll load them once at game launch, and keep them in cache to reuse them as needed.

This is what came to my mind at first, but unfortunately you can’t apply CSS to image data in Javascript. “Styling” an element and taking a screenshot of it is only possible with <canvas>, see jquery - How to take screenshot of a div with JavaScript? - Stack Overflow

The idea is to have a canvas that is the exact size of the sprite and then do:

        var ctx = document.getElementById("myCanvas").getContext("2d");  
        var img = new Image():  
        img.src = "/images/example_sheet.png";  

        ctx.drawImage(img,-xSpriteCoord,-ySpriteCoord);  

        // then screenshot the canvas
       dataUrl = canvas.toDataURL(),
       imageFoo = document.createElement('img');
       imageFoo.src = dataUrl;

imageFoo is now an HTMLImageElement that you can use for the GUI.

2 Likes

Just found a codepen showing the image splitting technique: http://codepen.io/anon/pen/iLdCf

1 Like

@earthendev

Noticed that Texture can take HTMLImageElement as buffer in its constructor, and the file url can be null.

https://doc.babylonjs.com/api/classes/babylon.texture#constructor

Can I assume that I’ll be able to use the split HTMLImageElements as Textures too?

Created this small example in playground, suggestions are welcome. https://www.babylonjs-playground.com/#XCPP9Y#2409

By the way, the same thing can be done by manipulating the sourceLeft, sourceTop, sourceWidth and sourceHeight properties of the Image class. Use the Babylon GUI - Babylon.js Documentation

More on this topic: