OpenGLFragmentShader
(2023-05-30 15:03:51)
标签:
it |
分类: 技术 |
A Fragment Shader is the Shader stage that will process a
Fragment generated by the Rasterization into a set of colors and a
single depth value.
The fragment shader is the OpenGL pipeline stage after a
primitive is rasterized. For each sample of the pixels covered by a
primitive, a "fragment" is generated. Each fragment has a Window
Space position, a few other values, and it contains all of the
interpolated per-vertex output values from the last Vertex
Processing stage.
The output of a fragment shader is a depth value, a possible
stencil value (unmodified by the fragment shader), and zero or more
color values to be potentially written to the buffers in the
current framebuffers.
Fragment shaders take a single fragment as input and produce a
single fragment as output.
Contents
1 Optional
2 Special operations
3 Inputs
3.1 System inputs
4 Outputs
4.1 Output buffers
4.2 Dual-source blending
4.3 Other outputs
5 See also
Optional
Fragment shaders are technically an optional shader stage. If
no fragment shader is used, then the color values of the output
Fragment have undefined values. However, the depth and stencil
values for the output fragment have the same values as the
inputs.
This is useful for doing rendering where the only useful
output is the fragment's depth, and you want to use the depth
computed by the system, rather than some other depth. Such
depth-only rendering is used for shadow mapping operations as well
as depth pre-pass optimizations.
Special operations
Unlike every other shader stage, fragment shaders have
implicit derivatives generated. As such, they can use the majority
of the texturing functions. You still need to watch out for
non-uniform flow control.
Fragment shaders also have access to the discard command. When
executed, this command causes the fragment's output values to be
discarded. Thus, the fragment does not proceed on to the next
pipeline stages, and any fragment shader outputs are lost. Though
execution of the fragment shader is technically stopped by discard,
on actual systems, it may continue. Such systems are required to
prevent image store, Atomic Counter, and Shader Storage Buffer
Object writes issued after the discard from working (such
operations performed before the discard work as expected).
Normally, most of the Per-Sample Processing steps happen after
the fragment shader. However, with OpenGL 4.2 or
ARB_shader_image_load_store, the shader can enforce Early Fragment
Testing, which ensures that the conditional per-sample tests that
discard fragments happen before the fragment shader executes. To do
this, the following syntax is used in the shader:
layout(early_fragment_tests) in;
This is useful to ensure that you only perform expensive
load/store operations if the fragment is visible.
Warning: This does not mean that you can subvert the meaning
of the Depth Test. You cannot, for example, perform the depth test
with one value and then write a different value to the depth buffer
than the one you tested. If you attempt to write to gl_FragDepth
when you force early-fragment tests, then the value written will be
ignored. The value written to the depth buffer will always be the
value tested against the depth buffer. Similarly, if you discard a
fragment, the Stencil Test will still result in updating the
stencil buffer if the appropriate operations are set.
Inputs
The inputs to the fragment shader are either generated by the
system or passed from prior fixed-function operations and
potentially interpolated across the surface of the primitive.
The user-defined inputs received by this fragment shader will
be interpolated according to the interpolation qualifiers declared
on the input variables declared by this fragment shader. The
fragment shader's input variables must be declared in accord with
the interface matching rules between shader stages. Specifically,
between this stage and the last Vertex Processing shader stage in
the program or pipeline object.
System inputs
Fragment Shaders have the following built-in input
variables.
in vec4 gl_FragCoord;
in bool gl_FrontFacing;
in vec2 gl_PointCoord;
gl_FragCoord
The location of the fragment in window space. The X, Y and Z
components are the window-space position of the fragment. The Z
value will be written to the depth buffer if gl_FragDepth is not
written to by this shader stage. The W component of gl_FragCoord is
1/Wclip, where Wclip is the interpolated W component of the
clip-space vertex position output to gl_Position from the last
Vertex Processing stage.
The space of gl_FragCoord can be modified by redeclaring
gl_FragCoord with special input layout qualifiers:
layout(origin_upper_left) in vec4 gl_FragCoord;
This means that the origin for gl_FragCoord's window-space
will be the upper-left of the screen, rather than the usual
lower-left.
layout(pixel_center_integer) in vec4 gl_FragCoord;
OpenGL window space is defined such that pixel centers are on
half-integer boundaries. So the center of the lower-left pixel is
(0.5, 0.5). Using pixel_center_integer adjust gl_FragCoord such
that whole integer values represent pixel centers.
Both of these exist to be compatible with D3D's window space.
Unless you need your shaders to have this compatibility, you are
advised not to use these features.
gl_FrontFacing
This is false if the fragment was generated by the back-face
of the primitive; it is true in all other cases (including
Primitives that have no back face).
gl_PointCoord
The location within a point primitive that defines the
position of the fragment relative to the side of the point. Points
are effectively rasterized as window-space squares of a certain
pixel size. Since points are defined by a single vertex, the only
way to tell where in that square a particular fragment is is with
gl_PointCoord.
The values of gl_PointCoord's coordinates range from [0, 1].
OpenGL uses a upper-left origin for point-coordinates by default,
so (0, 0) is the upper-left. However, the origin can be switched to
a bottom-left origin by calling
glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN,
GL_LOWER_LEFT);
OpenGL 4.0 and above define additional system-generated input
values:
in int gl_SampleID;
in vec2 gl_SamplePosition;
in int gl_SampleMaskIn[];
gl_SampleID
This is an integer identifier for the current sample that this
fragment is rasterized for.
Warning: Any use of this variable at all will force this
shader to be evaluated per-sample. Since much of the point of
multisampling is to avoid that, you should use it only when you
must.
gl_SamplePosition
This is the location of the current sample for the fragment
within the pixel's area, with values on the range [0, 1]. The
origin is the bottom-left of the pixel area.
Warning: Any use of this variable at all will force this
shader to be evaluated per-sample. Since much of the point of
multisampling is to avoid that, you should use it only when you
must.
gl_SampleMaskIn
When using multisampling, this variable contains a bitfield
for the sample mask of the fragment being generated. The array is
as long as needed to fill in the number of samples supported by the
GL implementation.
Some Fragment shader built-in inputs will take values
specified by OpenGL, but these values can be overridden by user
control.
in float gl_ClipDistance[];
in int gl_PrimitiveID;
gl_ClipDistance
This array contains the interpolated clipping plane
half-spaces, as output for vertices from the last Vertex Processing
stage.
gl_PrimitiveID
This value is the index of the current primitive being
rendered by this drawing command. This includes any Tessellation
applied to the mesh, so each individual primitive will have a
unique index.
However, if a Geometry Shader is active, then the
gl_PrimitiveID is exactly and only what the GS provided as output.
Normally, gl_PrimitiveID is guaranteed to be unique, so if two FS
invocations have the same primitive ID, they come from the same
primitive. But if a GS is active and outputs non-unique values,
then different fragment shader invocations for different primitives
will get the same value. If the GS did not output a value for
gl_PrimitiveID, then the fragment shader gets an undefined
value.
Warning: The above discussion of gl_PrimitiveID is based on a
particular reading of the OpenGL 4.6 specification. However, the
specification itself is somewhat inconsistent with this view,
suggesting that the primitive ID may only get incremented based on
data fed to the system, not data generated by, for example, the
tessellator. And the Vulkan specification seems to concur with this
interpretation, and at least one implementation is known to agree
with that as well. Until there is some clarification on the issue,
you should consider the above to be questionable.
GL 4.3 provides the following additional inputs:
in int gl_Layer;
in int gl_ViewportIndex;
gl_Layer
This is either 0 or the layer number for this primitive output
by the Geometry Shader.
gl_ViewportIndex
This is either 0 or the viewport index for this primitive
output by the Geometry Shader.
前一篇:应届生调岗沟通

加载中…