Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better image sampling #722

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Better image sampling #722

wants to merge 1 commit into from

Conversation

dfrg
Copy link
Collaborator

@dfrg dfrg commented Oct 23, 2024

Constrains image sampling to the actual atlas region for a given image and adds a half pixel adjustment to sample from the pixel center.

Addresses #719 and maybe #656

Example 2x2 image with red, blue, cyan and magenta pixels:

vello_image_sampling

Constrains image sampling to the actual atlas region for a given image and adds a half pixel adjustment to sample from the pixel center.

Addresses #719 and maybe #656
Copy link
Member

@DJMcNab DJMcNab left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Three issues: My two comments, and the snapshot tests need updating.

This can be done by running cargo nextest run --workspace locally, and then following the printed instructions.

Thanks for getting such a quick fix in here.

@@ -1761,4 +1763,25 @@ mod impls {
std_dev,
);
}

pub(super) fn image_sampling(scene: &mut Scene, params: &mut SceneParams) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might as well make this a test as well.

Comment on lines 1169 to +1170
if all(atlas_uv < atlas_extents) && area[i] != 0.0 {
let uv_quad = vec4(max(floor(atlas_uv), image.atlas_offset), min(ceil(atlas_uv), atlas_extents));
let uv_quad = vec4(max(floor(atlas_uv), image.atlas_offset), min(ceil(atlas_uv), atlas_max));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something about this still feels suspicious to me. This seems like it might extend the bounds of the image, but clipped to the value on the outside. That is, imagine the point where:

atlas_extents: vec2(10, 10)
atlas_uv: vec2(9.5, 5)

Then the final uv_quad would be (9, 5). That's true for the entire section where atlas_uv is in (9, 10].

I think the fix (if my analysis is correct) would be to change atlas_extents on line 1169 with atlas_max (and possibly then inlining atlas_extents as it is otherwise unused)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does seem funky but I believe it is correct.

Think of it like accessing an array where your guard is len but you don’t want to index beyond len - 1 which is basically what’s happening here. This is slightly different because we’re dealing with floating point so you can end up with values between those two bounds but it ends up working due to the constraints and the lerps. Consider a 10x1 image where our x coordinate for this pixel is 9.5: we’ll end up sampling at x=9 twice and then lerping by 0.5 which is a nop and produces the correct color.

Note that if you implement your suggestion above (replacing extents with max in the bound), it’ll never sample from the right and bottom edges of the image. It seems like replacing the < with <= should fix this but it doesn’t work in practice because, you know, floating point :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this a bit more, the extents guard really only implements a clamping extend mode which we don’t actually support. And it only clamps on the right/bottom sides. I believe applying a brush transform with a positive translation would generate padding behavior on the left/top sides with the current code.

Since we only support pad, reflect and repeat, we should probably just remove that condition— if the user wants to avoid padding, they should apply the image to geometry that exactly matches the image size.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right. I broadly agree with that final conclusion. I think my original suggestion that it was suspicious was right, but my suggested fix was working on clamp, which doesn't currently exist.

@DJMcNab DJMcNab mentioned this pull request Oct 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants