raytracing.github.io icon indicating copy to clipboard operation
raytracing.github.io copied to clipboard

Camera UV coordinates — handle images with width or height of one

Open ghost opened this issue 3 years ago • 4 comments

I'm not quite sure how the current equation was derived. But the case clearly fails for the case that the width and height are both equal to one, for example.

int x = 0;
int y = 0;
int width = 1;
int height = 1;
float u = (x / (width - 1)); // 0 / (1 - 1) = 0 / 0 = NaN
float v = (y / (height - 1));

Should be changed to:

float u = (x + 0.5f) / width;
float v = (y + 0.5f) / height;

The result can be seen clearly when you can a 2x2 image as an example.

The UV coordinates previously would be:

(0, 0) (1, 0)
(0, 1) (1, 1)

The correct result would be:

(0.25, 0.25) (0.75, 0.25)
(0.25, 0.75) (0.75, 0.75)

ghost avatar Jul 27 '20 22:07 ghost

Will add a special case to handle single-pixel images. I definitely do not want to promote the idea that a pixel is little square, or has any specific shape, or indeed even that it has a finite kernel.

I'll also revisit the text to ensure that we at least hint that square pixels are a poor (but cheap) model.

hollasch avatar Oct 29 '20 19:10 hollasch

I forget where I read it, but the correct uv should be:

float u = floor((x + 0.5f) / width);
float v = floor((y + 0.5f) / height);

trevordblack avatar Dec 16 '20 06:12 trevordblack

@hollasch

This was my issue from a previous account. I wasn't proposing to tell readers that a pixel is a square, just offering a more simpler and commonly used expression of UV coordinates that does not require any special corner cases. You're free to reject it, that's totally fine.

tay10r avatar Mar 15 '21 01:03 tay10r

@trevordblack

Thanks for the suggestion! This:

float u = floor((x + 0.5f) / width);
float v = floor((y + 0.5f) / height);

Is not right because it will round to either 0 or 1 for all UV coordinates. So unless you have a 2x2 image, then you would get incorrect results. Using floor is more likely to be useful when converting from UV coordinates to image coordinates. For example:

int x = floor(uv_x * width);
int y = floor(uv_y * height);

But you can just use native floating-point to integer conversion instructions, which performs the truncation along with the conversion.

int x = uv_x * width;
int y = uv_y * height;

tay10r avatar Mar 15 '21 01:03 tay10r

Fixed in code in PR #1154 (text update pending).

hollasch avatar Jun 29 '23 21:06 hollasch