OpenGL’s glViewport vs Metal’s setViewport

As mentioned in the previous post, clipping happens after the vertex gets transformed into NDC space, and in OpenGL this is defined as 2x2x2 cube, while in Metal this is defined as a 2x2x1 cube.

I had some trouble with enabling depth test due to my setting with setViewport in Metal. Going back to OpenGL, this used to be glViewport, which is defined by this method signature:

void glViewport(
    GLint x,
    GLint y,
    GLsizei width,
    GLsizei height);

glViewport transforms your vertices from NDC space to windows coordinate space, so that your resulting image matches the size of your viewport/render target. According to the OpenGL specification:

glViewport specifies the affine transformation of x_nd and y_nd from normalized device coordinates to window coordinates. Let x and y be normalized device coordinates. Then the window coordinates x_w and y_w are computed as follows:

x_w = (x_nd + 1) * (width / 2) + x
y_w = (y_nd + 1) * (height / 2) + y

This allows us to transform NDC coordinates to Windows coordinate in x and y direction, while the NDC depth value (-1 to 1) remains untouched.

While on Apple’s website, the Metal specification states this for setViewport:

Fragments that lie outside of the viewport along the x and y dimensions are clipped. Fragments that lie outside of the z-dimension near and far clipping planes are clipped.

The x/y rectangle of the viewport must lie entirely within the current attachment size. The values for znear and zfar must be between 0.0 and 1.0, respectively. Flipping is allowed.

The default values for the viewport are originX = 0.0; originY = 0.0; width = w; height = h; znear = 0.0; and zfar = 1.0, where w and h are the x and y dimensions of the attachment, respectively.

So it seems like there is extra transformation work done to the z coordinates of NDC space, and also extra clipping work done after the last clipping in NDC coordinate space, and specifically it mentioned it’s also clipping in all 3 dimensions. This is something new introduced in Metal that was not available in OpenGL.

More over, the MTLViewport structure contains x, y, width, height, and also z-near, and z-far. My mistake was simply used the same z-near and z-far values from my projection matrix, but that means my NDC z coordinates were fallen out of the range [0.0, 1.0] after transforming to windows coordinate, and hence everything was clipped and nothing was being drawn.

Leave a Reply

Your email address will not be published. Required fields are marked *