Open qinxgee opened 7 years ago
Congratulations! You found the case we havent cover yet.
1.
Please look at https://github.com/pixijs/pixi-spine/blob/master/src/loaders.ts . As you see, "imageLoaderAdapter" is fixed, but i think we can add custom function in "imageOptions" that will be used instead. Would you to do that and rebuild and test pixi-spine? Or do you want me to do it?
Please specify your target system. If its desktop WebGL, you can use gzipped dds instead of png, and then https://github.com/pixijs/pixi-compressed-textures will help you. You can even use crunch compression if you arent afraid of extra time for unpacking on js side. However, that way alpha wont work like before, we have to add "non-premultiplied" blendmodes into pixi first. Also, texture has to be "prepared" for it, we need to extrude colors from opaque pixels to alpha pixels.
OK, try latest pixi-spine from "bin" folder, and this thing: https://github.com/pixijs/pixi-spine/blob/master/examples/preload_atlas_image.md
If it works for you, I re-publish pixi-spine in npm
Wow that was fast... I'm going to need more time to try that out. Thanks!
1) I can certainly have a go at adding this functionality, but I have not used type script before. No better time to start than the present, but maybe not when it is affecting so many people ;-)
2) Target is both mobile and desktop, but mainly mobile. I will still have a look at your suggestion because we are using different resources depending on platform, and there is nothing wrong with limiting the download size on desktop. So we can still try and use gzip there.
OK, then do 2., that'll work better than png+jpg. And for 1. you can try that thing i've already made in previous comment.
how to use this in https://github.com/pixijs/pixi-spine/blob/master/examples/preloaded_json.md
@lucap86 line 5
callback(myAweSomeBaseTextureThatWasGeneratedOrPreloaded)
You dont need latest version for that.
you made my day :)
@qinxgee Im working on better solution, I want to add your algorithm (png+jpg) to pixi loader itself.
OK, try latest pixi-spine from "bin" folder, and this thing: https://github.com/pixijs/pixi-spine/blob/master/examples/preload_atlas_image.md
Hi!
i have just done this but I'm thinking that I'm maybe not understanding what is going on exactly when I do this. This is now my advancedImageLoader:
advancedImageLoader : function(loader, namePrefix, baseUrl, imageOptions) {
if (baseUrl && baseUrl.lastIndexOf("/") !== (baseUrl.length - 1)) {
baseUrl += "/";
}
return function(line, callback) {
var lineAlpha = line.replace('.jpg', '.png');
var name = namePrefix + line;
var url = baseUrl + line;
var urlAlpha = baseUrl + lineAlpha;
loader.add(name, url, imageOptions, function(resource) {
var container = new PIXI.Container(),
alphaSprite = new PIXI.Sprite.fromImage(urlAlpha),
textureSprite = new PIXI.Sprite.fromImage(url),
renderTexture;
textureSprite.blendMode = PIXI.BLEND_MODES.ADD;
container.addChild(alphaSprite);
container.addChild(textureSprite);
renderTexture = PIXI.RenderTexture.create(container.width, container.height);
renderer.render(container, renderTexture);
callback(renderTexture.baseTexture);
})
}
}
(renderer is defined elsewhere in my code).
I create two new sprites, one with the alpha values, one with the textures, put them in a container and render the container back to a texture. Instead of now returning the resource's texture's baseTexture, I return the baseTexture of the rendered one.
As far as I can tell, the animation ends up using the original texture. I have switched the two sprites in the container in which case I'd expect to see a black screen (the silhouettes from the PNG on top, and the black background from the JPG showing through the transparent parts). But instead I'm seeing the original picture.
Do you use latest "pixi-spine.js" from "bin" folder? Make sure this line exist: https://github.com/pixijs/pixi-spine/blob/master/bin/pixi-spine.js#L5363 . It takes different fields from metadata and tries to create a loader out of them.
I didn't test it yet, I did add "metadata.imageLoader" there
I downloaded pixi-spine.js from master. The code is identical. I should have more time in a bit, I'll add a means for me to verify that the rendered texture is actually what I expect it to be.
then put breakpoint in your advancedImageLoader. If its not called, then i screwed up somewhere.
advancedImageLoader is called, so I need to check my (rendered) texture.
Are you sure its ADD and not multiply? I think you need different blendMode. Im adding support for gl.blendFuncSeparate to pixi in https://github.com/pixijs/pixi.js/pull/4033
I don't think it is your code, it is something with my pixi renderer: if I display the container with the two sprites it looks as I would expect: like the JPG, but with the transparency from the PNG. When I create a sprite from the renderTexture, the image is back to being opaque.
Try "render(container, renderTexture, false)". Pixi clears renderTexture with the "backgroundColor" of your renderer by default, but if we specify clear=false, it might work.
I tried both true and false, but it does not seem to make a difference. The 'transparent' option when setting up the renderer also does not seem to change anything, but I must admit that I am not sure what that setting is supposed to do.
I'm sure ADD cant combine alpha=1 and alpha=1 to alpha=0. How exactly that png looks, can you give me it?
I tried m=both ADD and MULTIPLY, but MULTIPLY made the picture pretty much disappear (since the texture contains a lot of black as well: multiply by 0, means 0.
Now I'm not a graphics guy by any stretch of the word, but how it was explained is that you add 0 from the JPG to transparency from the PNG, you should end up with transparency. When you add any colour (0 - FF) from the JPG to the solid black of the PNG, you end up with whatever colour was in the JPG.
I cannot give you the actual artwork (my boss would not be happy), but I can provide a similar idea (just a wallpaper that I downloaded from the internet and messed about with). The idea is similar: just add both sprites to a container, put an ADD mode on the JPG, and you should end up with a transparency of the JPG. When I change the blend mode to MULTIPLY, I end up with a solid black container.
No, unfortunately that's not how blendmodes work. When you ADD alpha=0 and alpha=1 it will end with alpha=1. I dont even think that multiply can take alpha out. There are no blendmodes in curernt version of pixi that will work on that.
I have few ideas in my mind, but they are all too hacky for your case - they are using pure webgl, I wont be able to explain that. You can ask me to implement them right away if you need it working right now/
Otherwise, I'll add special blendmode after https://github.com/pixijs/pixi.js/pull/4033 gets approved, hope it will be tomorrow.
That is a shame... it's odd that it would work with plain containers (see those work on my screen right now), but maybe the renderer just isn't able to keep the transparency when rendering a DisplayObject? I have left a question about that at the pixi.js hub, in a thread that someone started there with seemingly a similar issue.
Anyway, as a fallback we always have the original PNGs to work with. It'll be a hefty download, but we'll make it work. And I'm keeping an eye our for your work. We still have a some time before feature complete to work on this :-) (not to mention future projects)
Thanks a ton for all your help!
It cant work with plain containers. Unless you are using something like VoidFilter on it. Do you? I know how to make that solution with less memory, for mobiles, but I said that its very hacky in current version of pixi, I'm trying to introduce some changes right now :)
Ehhm... no... here's the entire code that I use to display it on top of my game:
var container = new PIXI.Container(),
alphaSprite = new PIXI.Sprite.fromImage(urlAlpha),
textureSprite = new PIXI.Sprite.fromImage(url);
textureSprite.blendMode = PIXI.BLEND_MODES.ADD;
container.addChild(alphaSprite);
container.addChild(textureSprite);
layer.addChild(sprite);
"layer" is our top rootcontainer that gets rendered to the screen. I attached a screen shot. The white that you see is an underlying pixi graphics rectangle, the rest is a combination of the jpg and the png...
Make it green and not white.
Would that help? The white (or green) is not part of the container. If I make it part of the container and try to render it, the resulting texture is solid white (or solid green).
Ah, suddenly I understand how it works. First png draws black on the place where flower will be drawn, and then you paste jpg on it with ADD. It won't work for alpha=0.5 properly. And its not associative operation, it cant be just put into renderTexture, it needs something below it. I'll think about how to help you tomorrow.
Yes, that is how it works. I was hoping to create a full texture, and let the animation deal with that, just as it would deal with a texture that was loaded directly from a png. I'm a little bit worried about the "it will not work for alpha = 0.5". The pasting of two animations on top of each other also doesn't work for alpha different than 0 or 1, and I was hoping to solve that by rendering the combined texture first, then use that in an animation.
We can solve it. It just requires a bit of changes in pixi, or huge hacks from my side, and I'm kinda tired after working day. Anyway, you shown me a good trick i totally forgot about.
@lucap86 line 5
callback(myAweSomeBaseTextureThatWasGeneratedOrPreloaded)
You dont need latest version for that.
sorry for the necro, how do i add multiple images like in this example? it has two .png files, and i would like to do similar thing but with preloaded textures. i'm pretty new to pixi (perhaps js too), i'm not sure how the iteration works inside the loader
i'm pretty new to pixi (perhaps js too), i'm not sure how the iteration works inside the loader
Looks like this is your case: https://github.com/pixijs/pixi-spine/blob/master/examples/preload_atlas_image.md
There are too many ways to load things in pixi-spine and we moved it to examples
folder. When someone adds one more good way I accept his changes and add his example to the folder.
Also prepare to debug https://github.com/pixijs/pixi-spine/blob/master/src/loaders.ts if something goes wrong.
Its also the reason why PixiJS doesnt grow to framework, we dont have enough resources to maintain code like that and it'll be like 90% of framework code ;)
Looks like this is your case: https://github.com/pixijs/pixi-spine/blob/master/examples/preload_atlas_image.md
There are too many ways to load things in pixi-spine and we moved it to
examples
folder. When someone adds one more good way I accept his changes and add his example to the folder.
I can't seem to produce the result I'm looking for, the console still said it tried loading from the filename provided inside the atlas file.
Perhaps I should've mentioned this before. I'm trying to load an atlas, which provided with two placeholder images, and I want to link it to the correct texture URLs, outside the base URL.
Thanks in advance.
It should work.
Try again, debug the loader.
Sorry, my telepathy doesn't work in this case anymore :( Reproduce your bug in the demo so I can help you.
I tried it as such
let atlasLoaderOptions = { metadata: {
images: {
"page_0": PIXI.BaseTexture.fromImage(textureLinkOne),
"page_1": PIXI.BaseTexture.fromImage(textureLinkTwo)
}
}};
PIXI.loader
.add('skeleton', spriteJsonLink)
.add('atlas', spriteAtlasLink, atlasLoaderOptions)
.load(onAssetsLoaded);
After that, in the renderer, I tried adding an atlas loader via spine.core.AtlasAttachmentLoader and SkeletonJson as in this example. Am I getting the flow wrong? I'm also unsure how to pass the image inside the TextureAtlas function since there are two images that I want to include inside the atlas (not to mention the atlas already has placeholder image names so I'm afraid it looked up into that as priority as well).
You didnt reproduce the example, you've added one more resource into loader,
There's line
parameter in the function you pass to TextureAtlas. Can you please try to place breakpoint there and see what value has that parameter? ;)
Yes, because it's what I originally wanted to do since all four files (.json, .atlas, and two .pngs) are scattered around folders (specifically in my case, URLs). That's why I load them separately, and I think adding line
parameter inside the renderer doesn't work? The error happens right after I loaded the JSON file. Which is why I thought the order of my code is wrong. Here's the rest of the code.
let atlasLoaderOptions = { metadata: {
images: {
"page_0": PIXI.BaseTexture.fromImage(spriteTextureLink),
"page_1": PIXI.BaseTexture.fromImage(spriteWeaponLink)
}
}};
// load spine data
PIXI.loader
.add('skeleton', spriteJsonLink)
.add('atlas', spriteAtlasLink, atlasLoaderOptions)
.load(onAssetsLoaded);
let sprite = null;
function onAssetsLoaded(loader, res) {
let rawSkeletonData = JSON.parse('skeleton');
let rawAtlasData = 'atlas';
let spineAtlas = new PIXI.spine.core.TextureAtlas(rawAtlasData, function(line, callback) {
// pass the image here.
callback(PIXI.BaseTexture.fromImage(line));
}); // specify path, image.png will be added automatically
let spineAtlasLoader = new PIXI.spine.core.AtlasAttachmentLoader(spineAtlas)
let spineJsonParser = new PIXI.spine.core.SkeletonJson(spineAtlasLoader);
// in case if you want everything scaled up two times
spineJsonParser.scale = 2.0;
let spineData = spineJsonParser.readSkeletonData(rawSkeletonData);
console.log(spineData);
// now we can create spine instance
sprite = new PIXI.spine.Spine(res.skeleton.spineData);
app.start();
}
Again, I'm sorry because my brain is failing me, I'm quite new to this.
another atlas will be loaded from skeleton.json
file because you didnt specify anything that helps the code to connect first json file to that atlas you load.
Also
let rawSkeletonData = JSON.parse('skeleton');
let rawAtlasData = 'atlas';
You should put raw text here, but that means you dont hae to load json files.
It looks like you are just copy-pasting the code without trying to debug it. You have long way ahead before you make it work.
PixiJS has low threshold for newbies, but to get something non-standard you have to know how to debug async functions, its not a gamemaker.
If you really put JSON.parse('skeleton')
in your code then you don't know javascript, is that the case?
What's your background? Maybe I can use terms from things that you used before :)
OK, so, right now there are 10 things that can go wrong when you try to combine pixi-spine hacks. Usually users solve 8-9 on their own using devtools debugger and i fill up 1-2 with my telepathy skills :)
In case you cant solve it, there's a general list of how to unstuck something that you dont understand:
While you wait, you can work on other things for your projects, things that I hope are less difficult than pixi-spine-hacky-community-collection.
If you think that you require more help from PixiJS community, I can invite you to PixiJS slack where many people can help you. Of course, every time you feel like you dont understand what are they saying you'll have to use the "how to unstuck" list I provided you :)
Also necroing threads is usually fine if it ends in several comments, so dont worry about it.
This is my actual code (I tried JSON.parse before but seems like there was a synchronizing conflict of sort), I don't know if I'm putting the res.atlas correctly, because I'm not sure how to parse it. The error says it can't split the text.
$.ajax({
url: spriteJsonLink,
async: false,
dataType: 'json',
success: function(data){
let rawSkeletonData = data;
}
})
let rawAtlasData = res.atlas;
var spineAtlas = new PIXI.spine.core.TextureAtlas(rawAtlasData, function(line, callback) {
// pass the image here.
callback(PIXI.BaseTexture.fromImage(line));
});
And yes, I'm still learning about JS too because I've only worked with easier game engines so far (such as Phaser) and english isn't my native tounge.
Also it would be my pleasure to get an invite to a PixiJS slack.
Using jquery to load raw data for both atlas and skeleton, then passing it to https://github.com/pixijs/pixi-spine/blob/master/examples/preloaded_json.md can work too. owever your code isn't clear for me, I dont understand whether you wanted to make rawSkeletonData
and where do you get res.atlas
. Please make a demo in separate issue, otherwise we'll spend 10 more posts ping-ponging like that.
And yes, I'm still learning about JS too because I've only worked with easier game engines so far (such as Phaser) and english isn't my native tounge.
Invite sent to your email.
Hi!
I would like to use a spine animation with a sprite sheet texture that has been loaded earlier. I have an atlas file, but the image referenced in it is not the sprite sheet that I want to use. Can I load the atlas, but use the texture instead of the referenced file? I have read the docs on how to load a spine animation without an atlas, but I'd still need the regions that are defined in the atlas. Can I add those somehow? Or can I load the spine with atlas and then change the sprite sheet?
Little bit of background: the original animation uses a PNG, but it is very big. JPG would be more suitable, but I need transparency. So instead I want to load the transparencies in one image (PNG) and the textures in another (JPG). This would reduce the download size to about 1/3rd. With additive blending, the resulting texture is exactly what I want. In the past I've just put two animations on top of each other, so that the result is correct, but that only seems to work when the animation does not use any fading (alpha has to be either 0 or 1).