I know that it is more efficient than stencil test, but am I right assuming that the same functionality could be achieved using projection transformations with viewport?
They are more complementary than alternatives to each other. You almost always want to set the scissor rectangle to the same values as the viewport.
glViewport() specifies a transformation from normalized projection space to screen space. Polygons are clipped to the edge of projection space, but other draw operations like glClear() are not. So, you use glViewport() to determine the location and size of the screen space viewport region, but the rasterizer can still occasionally render pixels outside that region.
That's where scissor in comes in. glScissor() defines a screen space rectangle beyond which nothing is drawn (if the scissor test is enabled).
So for example, the following code will clear the whole screen, even though the viewport is set to a small portion of the larger window:
Adding glScissor() and enabling the scissor test (which is disabled by default) restricts the clear.
glViewport(200,200,100,100); glScissor(200,200,100,100); glEnable(GL_SCISSOR_TEST); glClear(GL_COLOR_BUFFER_BIT);
Occasionally you come across an implementation that automatically scissors to the viewport region, but that violates the GL specification.
Beyond that, the scissor rectangle can be used to temporarily restrict drawing to a sub-rectangle of the viewport, for special effects, UI elements, etc.
They operate at two completely different parts of the graphics pipeline.
glViewport actually specifies a transformation, and it's a transformation that happens after the vertex shader but before the fragment shader. If it helps to see where it conceptually fits in, think in terms of it being part of the transforms that are used to get your vertex data from world space to screen space (i.e. it's relatively closely related to modelview and projection).
Scissor test happens after the fragment shader, together with all of the other per-fragment operations that happen at that time, such as blending, depth/stencil, etc. When a fragment is tested by the scissor test, it has therefore already been through the viewport transformation.
Yes, scissor test can be faster can stencil because it's a simple accept/reject based on a fragment's screen space coords, whereas stencil needs to compare with the current value in the stencil buffer, possibly increment or decrement that current value, also take into account the results of the depth test, and so on.
So putting all of that together you can see why scissor test exists. It gives you the ability to constrain per-fragment ops to a rectangular portion of the screen, but without actually modifying the current viewport transform.
I like this kind of things explained visually.
In OnpenGL we have 2D coordinates that go from -1 to +1 for both the X and Y axis.
Then this image needs to be mapped to window coordinates.
Let's imagine that we have window that has a dark color as back ground, and we have white as the clear color.
The most common case is having viewport and scissor cover the whole screen.
But we can set them to be a smaller region of the screen.
These regions can be different. In the following example the viewport covers the whole screen, while scissor is the smaller box.
And in this last case scissor covers the whole screen, while viewport is the smaller box. Notice that
glClear affects the whole screen, since that's determined by scissor region.
glScissors accomplishes clipping of geometry against a portion of the screen.
You would want this, for example, if you were rendering a GUI box that had smoothly scrolling text inside it. You want to clip all geometry outside the portion of the screen covered the by the GUI, but keep partial text or polygons which are still inside.
glViewport maps the projection coordinates to device coordinates, but does not clip.
glStencil is used to mask individual pixels in more complex patterns, such as irregular shapes. Thus, glScissors is faster.
glScissor is more simple than projection transformations with viewport.
glScissor test specifies what pixels to be changed when rendering, while glViewport changes how gl should map from device coordinates to window coordinates.
Then what's the difference with setting the viewport to the rectangle you want to render to and adjusting the projection matrix to undo the scaling done by the viewport.