In OpenGL or d3d, scissoring by API performs the per fragment operation before fragment is written to the frame buffer. The sequence of operations in OpenGL is as follows:
- Scissor Test
- Alpha test
- Stecil Test
- Depth Test
- Blend
- Dither
- Logic Operation
To perform scissor test, we can
Glenable (gl_scissor_test); glscissor (left, bottom, with, height );
By default, scissor test is disabled, and the size of scissor is the entire window. In d3d, we can
G_pd3device-> setrenderstate (d3drs_scissortestenable, true); g_pd3device-> setscissorrect (& rect );
Scissoring by projection matrix we can also modify projection matrix to achieve the same purpose. When the engine does not provide related APIs to directly set scissor rect, such as unity3d. Note that to render only part of the world in a certain area of the screen, we should first modify the viewport to make it consistent with scissor rect. Because we have no way to render only one part of NDC, our only choice is to scale/pan the part we need to render so that it occupies the entire NDC area. In this way, only scissor rect is rendered. Here, the blue rectangle (NDC) is the part we need to actually display, and the White Rectangle is the original NDC coordinate system. We only need to coordinate the coordinates in the NDC coordinate system to NDC, so that vertex outside NDC will be clipping, and finally achieve scissor.
Note that after the coordinates are projected, they are actually in the homogeneous coordinate space, however, because the transformation in the Euclidean space after pivot division and the transformation in the homogeneous coordinate space do not affect the final result, we choose to do it in NDC, otherwise, we need to know the W component of the homogeneous coordinates, because
-W <= x <= W
-W <= Y <= W
For homogeneous coordinates [x y z w], the coordinates of the corresponding Euclidean space are [x/w y/w z/W]. Assume that scissor test is specified with normalized screen coordinate, which is (L, t, W, H ). The coordinates in NDC are [x y z]. Considering that the transformation only affects X and Y, we will not discuss the transformation of Z in the future. In normalized screen space, for a known point P, the following equations are true: the coordinate system [O, U0, u1] represents the original NDC in normalized screen space, the coordinate system [o', V0, V1] represents the transformed NDC in normalized screen space. We know [x y], and then we can obtain the transformation matrix by finding the coordinates of [O, U0, u1] in [O ', V0, V1.
Yes
O = (1/2, 1/2)
U0 = (1/2, 0) U1 = (0,-1/2)
O' = (L + W/2, T + H/2) V0 = (W/2, 0) V1 = (0,-H/2)
So we can get
M00 = 1/wm01 = 0m10 = 0m11 = 1/hm20 = (1-2l-w)/wm21 =-(1-2t-h)/h
So we will multiply the original projection matrix by the following transformation matrix to achieve the goal of scissor.
In unity3d, we can
// set the viewport to the scissor rectcamera. main. rect = rcscissor; // transform so that the scissor rect occupies the ndcmatrix4x4 MAT = new matrix4x4 (); mat. setcolumn (0, new vector4 (1/rcscissor. width, 0, 0, 0); mat. setcolumn (1, new vector4 (0, 1/rcscissor. height, 0, 0); mat. setcolumn (2, new vector4 (0, 0, 1, 0); float Tx = (1.0f-(2 * rcscissor. X + rcscissor. width)/rcscissor. width; float ty = (-1.0f + (2 * rcscissor. Y + rcscissor. height)/rcscissor. height; mat. setcolumn (3, new vector4 (TX, Ty, 0, 1);