https://learnopengl.com/Advanced-OpenGL/Advanced-GLSL
this tutorial will not really show u super advanced cool new features that give an enormous boost to your scene’s visual quality. this tutorial goes more or less into some interesting aspects of glsl and some nice tricks that might help u in your future endeavours. basically some good to knows and features that might make your life easier when creating opengl applications in combination with glsl.
we will dicuss some interesting built-in variables, new ways to organize shader’s input and output and a very useful tool called uniform buffer objects.
glsl’s built-in variables
shaders are minimal, if we need data from any other source outside the current shader we will have to pass data around. we learned to do this via vertex attributes, uniforms and samplers. there are however a few extra variables defined by glsl. prefixed with gl_ that give us an extra means to gather and/or write data. 读写 we have already seen two of them in the tutorials so far: gl_Position that is the output vector of the vertex shader and the fragment shader’s gl_FragCoord.
we will dicuss a few interesting built-in input and output variables that are built-in in glsl and explain how they might benefit us. note that will not discuss all built-in variables that exist in glsl so if u want to see all built-in variables u can check opengl’s wiki.
https://www.khronos.org/opengl/wiki/Built-in_Variable_(GLSL)
vertex shader variables
we have already seen gl_Position which is the clip-space output position vector of the vertex shader. setting gl_Position in the vertex shader is a strict requirement if u want to render anything on the screen. nothing we have not seen before.
gl_PointSize
one of the render primitives we are able to choose from is GL_POINTS in which case each single vertex is a primitive and rendered as a point. it is possible to set the size of the points being rendered via opengl’s glPointSize function, but we can also influence this value in the vertex shader.
an output variable defined by glsl is called gl_PointSize that is a float variable where u can set the point’s width and height in pixels. by describing the point’s size in the vertex shader u can influence this point value per vertex.
influencing the point size in the vertex shader is disabled by default, but if u want to enable this u will have to enable opengl’s GL_PROGRAM_POITN_SIZE:
glEnable(GL_PROGRAM_POINT_SIZE);
a simple example of influencing the point size is by setting the point size equal to the clip-space position’s z value which is equal to the vertex’s distance to the viewer. the point size should then increase the further we are from the vertices as the viewer.
void main()
{
gl_Position = projection * view * model * vec4(aPos, 1.0);
gl_PointSize = gl_Position.z;
}
the result is that the points we have drawn are rendered larger the more we move awaw from them:
u can imagine that varying the point size per vertex is interesting for techniques like particle generation.
gl_VertexID
the gl_Position and gl_PointSize are output variables since their value is read as output from the vertex shader; we can influence the result by writing to them. the vertex shader also gives us an interesting input variable, that we can only read from, called gl_VertexID.
the integer variable gl_VertexID holds the current ID of the vertex we are drawing. when doing indexed rendering (with glDrawElements) this variable holds the current index of the vertex we are drawing. when drawing without indices (via glDrawArrays) this variable holds the number of the currently processed vertex since the start of the render call.
although not particularly useful right now, it is good to know that we have access to info like this.
fragment shader variables
within the fragment shader we also have access to some interesting variables. glsl gives us two interesting input variables called gl_FragCoord and gl_FrontFacing.
gl_FragCoord
we have seen the gl_FragCoord is couple of times during the discussion of depth testing, because the z component of the gl_FragCoord vector is equal to the depth value of that particular fragment. however, we can also use the x and y component of the vector for some interesting effects.
the gl_FragCoord’s x and y component are the window-space coordinates of the fragment, originating from the bottom-left of the window. we have specified a window of 800x600 with glViewport so the window-space coordinates of the fragment will have x values between 0 and 800, and y values between 0 and 600.
using the fragment shader w can calcualte a different color value based on the window coordinate of the fragment. a common usage for the gl_FragCoord variable is for comparing visual output of different fragment calculations, as usually seen in tech demos. we would for example split the screen in two by rendering one output to the left size of the window and another output to the right side of the window. an example fragment shader that outputs a different color based on the fragment’s window coordinates is given below:
void main()
{
if(gl_FragCoord.x < 400)
FragColor = vec4(1.0, 0.0, 0.0, 1.0);
else
FragColor = vec4(0.0, 1.0, 0.0, 1.0);
}
Because the width of the window is equal to 800, whenever a pixel’s x-coordinate is less than 400 it must be at the left side of the window and thus we give the object a different color.
we can now calcualte two completely different fragment shader results and display each of them on a different side of the window. this is great for testing out different lighting techniques for example.
gl_FrontFacing