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

mipmap / ripmap question #679

Closed
darkyellow opened this issue Mar 3, 2020 · 7 comments
Closed

mipmap / ripmap question #679

darkyellow opened this issue Mar 3, 2020 · 7 comments
Labels
Needs Discussion To be discussed in the technical steering committee
Milestone

Comments

@darkyellow
Copy link

Hi

I'm looking to load a mipmap / ripmap image in to a pixelbuffer with all levels loaded. I can see how to load all the pixel data by iterating through all the levels but I have some questions on the data window and display window because openexr seems to not scale these (tilerange minx/miny/maxx/maxy seem to be the same regardless of level)

how should the data and display window min/max values scale down per level?
is it valid to have a display window with a different size to the data window for mipmaps?
is it valid to have the windows start in the negative range?

If the windows are forced to be the same and to start from 0 then scaling things is fairly easy but if they aren't it would be good to know the scaling logic to be applied to the ranges.

@cary-ilm cary-ilm added the Needs Discussion To be discussed in the technical steering committee label Mar 5, 2020
@peterhillman
Copy link
Contributor

dataWindowForLevel computes the scaled coordinates of the dataWindow. dataWindowForTile is also helpful here. These take into account the original dataWindow and the rounding mode in use.

Yes, it is valid to have a dataWindow which is different from the displayWindow, including one that has some or all of its coordinates in the negative range. The dataWindow.min coordinate stays the same no matter which level, but the dataWindow.max changes.

It may be helpful to look at how exrmaketiled generates mipmap/ripmap levels with peculiar dataWindows. My understanding is that the lower resolution images are created by offsetting the image so the dataWindow min coordinate is at the origin (0,0), scaling the images, then offsetting the result back to the original position.

@darkyellow
Copy link
Author

Thanks that's makes sense, its how I was assuming they would work. For the display window where it's different how is this scaled? If I have a data window (0,0,500,500) and a display window (250,250,500,500) the next level for data window would be (0,0,250,250). Would I be correct in assuming that you scale the width and height of the display window but also scale the distance between data window mins to display window mins so your new display window will be (125,125,250,250)?

@lgritz
Copy link
Contributor

lgritz commented Mar 6, 2020

To be honest, having non-matching display and data windows, or for either to not be the full size of the image, is really difficult for MIP maps and I don't recommend it if you can possibly avoid it.

It's hard to fully explain without being able to sit next to you and draw pictures, but the crux of the problem is that neither of the windows can be fractional, the window corner coordinates are integers. So as you resize down from the top level of the original image, you will eventually hit a level in which all the coordinates are not even numbers, and then what do you do? You could round up or down, but without floating point window coordinates, it will actually slightly change the alignment of the windows relative to each other and relative to the pixel values.

I'm also the author of OpenImageIO, whose texture system is used in quite a few of the high-end renderers. Often we have situations where people want overscanned textures -- that is, where the display window indicates the 0-1 range of texture coordinates as indexed by the shader, but they want valid pixel values to exist outside this range. I have to do some bending over backwards here, in particular to use the windows of the top level of the MIP map to understand the actual coordinate mapping, because you can't really trust the fidelity of the display window coordinates of the lower levels because of the requirement for integer values.

@darkyellow
Copy link
Author

Openexr defines the rounding rules, so that's not an issue (although graphic renders all seem to like round down rather than round up)

I'm not writing exr files, I reading and not in control of what could be passed. The spec doesn't control the data window or display window so it allows the possibility of them being different even for mipmaps.

@peterhillman
Copy link
Contributor

I think there are different expectations here about what mipmaps are supposed to represent.
It might help to give a little more background about why you are loading these images?

The display window is a property of the image as a whole, not the mipmap level: an image only has one display window. The mipmaps provide filtered, subsampled representations of the same image data, not different images.

Imagine an image viewer which can zoom the image it displays. The displayed image dimensions are those of the displayWindow attribute, scaled by the current zoom factor. As the image zooms out, the displayed image size scales accordingly, and is filled with pixels from the data window in their appropriate position. When displaying a mipmapped image, level 0 will be used for displaying the image at 1:1 resolution. Once the zoom factor reaches 1:2, so the displayed image is half the size of the original image, the viewer can switch to displaying the level 1 mipmap; at 1:4, it can switch to level 2. Those level jumps should not be particularly noticeable to the viewer: the image shouldn't appear to move when changing levels.
In this scenario, the size of the image as displayed is always the image displayWindow, scaled by the viewer zoom factor, regardless of which mipmap level is displayed.

This is very close to how mipmaps are used when texturing: different mipmap levels are used depending on how big the source texture will appear in the output image. It should never be apparent which level was read to produce the output image.

The challenge here, that @lgritz touches on is: if pixel (x,y) was being displayed at level 0, which is the corresponding pixel to display instead from level 1? My understanding is:

  • Pixel (x,y) at level 0 should be read from level 0's data at position (x-dataWindow.min,x,y-dataWindow.min.y)
  • Pixel (x,y) at level 1 should be read from level 1's data at position (x-dataWindow.min.x)/2 , y-dataWindow.min.y)/2

I believe dataWindow.min is always the same for every level, regardless of rounding mode, but dataWindow.max changes (and dataWindowForLevel gives you that information)
However, that assumes that the division is exact. If x or y is odd, it's not clear exactly what should happen, and I expect mipmapped images are generated differently, with different assumptions about how they are going to be read.

@peterhillman
Copy link
Contributor

Also, display Windows with minimum coordinates set to anything other than (0,0) are unusual. I'm not really sure what that means. I've never seen a case for doing that, nor seen any expectations about how such images should be displayed.

@darkyellow
Copy link
Author

The plan is to use the images for 3d rendering, I fully understand what mipmaps are and how they are used so that's not the issue.

You say there is only one display window, I totally understand that but that is also the issue. The data window needs to be recalculated every level and the tile description describes the rounding mode to do this regardless whether the image has even dimensions or not. But the display window doesn't, as an image format it leaves it up to the person reading the image to decide as it is undefined rather than having it defined in the spec. Why someone would want to have display and day set up differently for mipmaps I don't know, but it is possible and someone who is processing the image I need to either reject scenarios I am not interested in or find a way to handle them.

The way presented seems the most sensible and is what I came up with in my head so I think I will implement that. Thanks for all the help and conversations on this.

@cary-ilm cary-ilm added this to the v2.5.0 milestone Apr 27, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Discussion To be discussed in the technical steering committee
Projects
None yet
Development

No branches or pull requests

4 participants