• Editor
  • Viewport Pixel Grid Gotchas

  • تم التحرير
Related Discussions
...

Can you send a project so we can see the problem firsthand? Does this only happen when using pixel grid scaling?

Nate wrote

Can you send a project so we can see the problem firsthand? Does this only happen when using pixel grid scaling?

It only happens with pixel grid scaling...and then I suspect it only happens in the editor. I need a bit to revert to the broken state so you can see it. Contact "at" esoteric works?

Yep! Thanks! You might find a version of your project with the problem by looking in the Spine backup folder (a button in the settings dialog will open the folder for you). Of course if you resized your images that only helps with part of it.

Nate wrote

Yep! Thanks! You might find a version of your project with the problem by looking in the Spine backup folder (a button in the settings dialog will open the folder for you). Of course if you resized your images that only helps with part of it.

Okay I've sent it to you. I reverted some of the images to have odd sized dimensions. Others have even dimensions but experience judder due to having non-integer positions.

Great, thanks! I'm not back in full force yet, but I found a moment to take a closer look. It appears everything is actually working properly, as unintuitive as that may seem!

A region attachment's position is the center of the texture region. Eg, at 0,0 the image is centered on the bone. If the region size is odd, this places it half a pixel off. To get the pixel grid scaling effect, we render the skeleton to an FBO at 1:1, then draw the FBO. When rendering to the FBO, if the region is half a pixel off compared to the FBO pixels, the nearest filtering can cause pixels to be lost.

The solution is to move the attachment half a unit when it has an odd dimension. Eg, instead of offsetting it 9 pixels on X, if the width is odd, offset it 9.5 or 8.5. This allows the region pixels to match the FBO pixels 1:1 and no pixels will be lost.

Note the same problem can occur when the attachment dimensions are even and the attachment translation is off by half a pixel.

It's a bit of a tricky gotcha. Maybe we could automatically nudge attachments so their pixels match up 1:1 and filtering won't kick in, though that kind of magic can also be very confusing, depending what you are doing.

10 أيام لاحقا

I was thinking something along the lines of your nudging idea...but only at render time (in case you switch back from pixel grid mode you don't want it to retain the offset).

I think overall though there is something a bit confusing about the positioning of images/slots, etc... especially when you have a whole sequence on a single slot. Maybe having the region attachment position displayed somewhere so that you can be like, "oh yeah, it's at an odd offset, so the translation should compensate." And then a button to make all attachments on that slot line up (so you don't need to use the dummy bone + reparenting trick).




Another thing that came up...if you use the photoshop exporter, it won't correct layers that have uneven dimensions. So you either need to change the art so that it can export them with even dimensions, or open the exported file and increase the canvas size to make it even.

FWIW, with a region attachment selected and Parent axes chosen, in setup mode the translation shown is the center of the region attachment position relative to the bone. World axes can tell you where it is relative to screen pixels (assuming 1:1 mapping of world units to screen pixels). Remember, because the region attachment position is the center of the region image, you'll want even dimension region attachments on x.0 world coordinates and odd dimension region attachments on x.5 world coordinates.

The Photoshop script places the region attachment in the right place. Eg, if the width is odd, it is placed at x.5. We could add a setting to the Photoshop script so output images have even dimensions, but if using the script it should already be handling it for you by adjusting odd dimension positions by 0.5.

I had the same issue some time ago when creating this animation (the logo finishes on the left on purpose :p):

Image removed due to the lack of support for HTTPS. | Show Anyway


The GIF format butchers gradients and framerate of course, but it was important for filtering not to kick in for most of the animation. Avoiding filtering required fiddling with 0.5 attachment translation for odd dimensions and making sure bone translations stop on integer coordinates.

I agree it's a little tricky. Ideally you use the Photoshop script, your regions are placed at x.0 or x.5 automatically, and then you just have to be careful when translating bones that you end on integer coordinates. Have you found something in this workflow that causes unnecessary pain? If placing the images yourself there is a little more pain because you need to nudge region attachments with odd dimensions by 0.5.

I'd say the biggest frustration is actually that image sequences need to be parented to a dummy bone to get them all lined up properly... (and if they are off by 0.5f you need to do it for all of them). My image sequences come out of GraphicsGale so no script can help with that (that I know of?). For example today I was placing a sequence animation for a character's head; at first I had 3 frames, but as I worked on it it grew to 7 frames. Every time I made a change, either the image dimensions would change or the sequence count would change, so I needed to repeatedly drag the first one onto the dummy bone to create a slot, drag the other images onto the same slot, drag the dummy so that it matched up with the previous position of my image, drag the images from the dummy onto the actual bone I wanted them on, delete the old, bad slot, rename the new slot. Ideally it would just auto detect that I had added new images to the sequence, and have all the images in the sequence follow whatever one I'm currently repositioning (perhaps as an option in case somebody wants to have some images transformed and some not)

We've wanted a "region sequence" attachment since the first version of Spine (and still want it!). This would show a number of regions at a given framerate so you don't have to key each image change.

It's not clear why you'd need a dummy bone/slot for those actions?

Maybe we could nudge the odd dimensioned images by 0.5 when you add them. We could do this only when pixel grid scaling is enabled, though I wonder if it would make sense to always do it? It's easier to zero the translation of all the images than it is to find the odd dimensions and nudge them 0.5.

  • تم التحرير
Nate wrote

It's not clear why you'd need a dummy bone/slot for those actions?

Okay, for example, I have a foot sprite with 10 "FootWalk" frames. Today I added 24 new "FootRun" frames. The first frame of each is identical. Shown here, the foot slot is at position -56, 17.

If I were a new user, I would probably think "time to drag the new frames on top of the foot in the viewport". But if you do this, you end up with 24 separate slots showing up in a kind of grid. So that's not going to help .

The next thing you might try is to drag the frames on top of the foot slot in the hierarchy view. If I do this, the new frames all come in together, but are located at -63, 21. This is because they are centering themselves on the parent bone, rather than on the current position of the slot. So I would need to adjust all 24 new frames to be -56, 17.

So your next thought might be to get them positioned correctly globally, then parent them later. So if I try to drag the first frame of "FootRun" over to where the current foot is, it creates a new slot at -55.379, 17.41 (which is as close as I can get it). So I type in -56, 17 because I want it to sync up with everything else whenever possible.

But that only takes care of the first frame. So I drag over the other frames in the hierarchy view. But these all appear at 0,0 (off the edge of my screenshot). So to reposition them all, I would need to manually enter -56, 17 to get them in the correct spot.

The last resort is to then make a dummy bone. I always leave one in my projects at 0,0. I name it "zdummy" so that it sorts to the bottom of the hierarchy, making it less of a distance to drag the frames in. I use the method where I first drag in one frame, rather than all 24, since I know doing the latter will create 24 slots.

Then I move zdummy to -56, 17, so it matches exactly the existing "FootWalk" frames. Only now can I drag all the frames over to the existing foot slot to get them matching up.

Ah, I've increase the attachment limit. http://imgur.com/ or similar might be a better way to show many pics.

AxiomVerge wrote

This is because they are centering themselves on the parent bone, rather than on the current position of the slot.

I understand, though technically a slot doesn't have a position, only bones and attachments have positions.

AxiomVerge wrote

I name it "zdummy" so that it sorts to the bottom of the hierarchy, making it less of a distance to drag the frames in.

Note you can click Set Parent or press P rather than dragging.

I understand your dummy bone now, thanks. I guess most of the frustration is that since a slot can only have one attachment visible, it's hard to manipulate multiple attachments under the same slot. The dummy bone is a pretty OK workaround. You could put it in a separate skeleton so it is sure not to show up in your exports.

Another way to do it is bring all the attachments in as a grid, position them, parent them to the right slot, the delete all the empty slots. There are a couple better ways though. Using copy and paste:

1) Drop all your attachments on the same slot.
2) Select an attachment that is where you want the others to be.
3) Press ctrl+c (cmd+c on Mac) to copy its transform.
4) Select the other attachments in the tree and press ctrl+v (cmd+v on Mac) to apply the copied transform. This modifies the selected attachments, even though they are not visible.

When dragging an image file (from the Images node) on top of another image file, it will replace it. However, when dragging an attachment on top of another attachment, it will copy the transform. Knowing that, the second way is:

1) Drop all your attachments on the same slot.
2) Select the attachments you want to position.
3) Drag and drop them on an attachment that is in the position you want. This modifies the selected attachments, even though they are not visible.

Sorry this wasn't more intuitive!

You may still have an issue if your attachments are not all even or odd dimensioned, since even should be at x.0 and odd at 0.5 and the above will put all attachments at the same coordinates.

Nate wrote

1) Drop all your attachments on the same slot.
2) Select an attachment that is where you want the others to be.
3) Press ctrl+c (cmd+c on Mac) to copy its transform.
4) Select the other attachments in the tree and press ctrl+v (cmd+v on Mac) to apply the copied transform. This modifies the selected attachments, even though they are not visible.

Nate wrote

1) Drop all your attachments on the same slot.
2) Select the attachments you want to position.
3) Drag and drop them on an attachment that is in the position you want. This modifies the selected attachments, even though they are not visible.

Oh wow, either of these makes it a LOT easier. I never tried copy/paste because I was thinking it would try to duplicate the attachment rather than copy the transform.

Copy/paste is more magick than I like. It's context sensitive, it isn't discoverable, and it isn't super clear what it will do, or if it will do anything at all. Still, it's an easy way to add this sort of functionality and it's not completely foreign to users.

You can also copy/paste bone transforms. It remembers the hierarchy, so you can select different bones with the same hierarchy and apply the transforms. Also which axes are selected matters, which can be useful.

Probably the place where copy/paste is the most intuitive is in the dopesheet (for keys). However, even there you need to have last clicked in the dopesheet so it knows that is where you want to paste (rather than in the viewport).