Lesson 20 advanced GLSL

Built in variable

Known

gl_ The clipping space output position vector of the position vertex shader
The chip output color value of the FragColor chip shader

unknown

Vertex shader variable

gl_PointSize

GLSL defines a called gl_PointSize output variable, which is a float variable. You can use it to set the width and height (pixels) of the point.
The function of modifying point size in vertex shader is disabled by default. Enabling it requires:

glEnable(GL_PROGRAM_POINT_SIZE);

We can set the size of rendered points through the glPointSize function of OpenGL

void glPointSize(	GLfloat size);//The default value is 1

But we can also modify this value in the vertex shader.

vertexshader: 
	gl_PointSize = Given value( float (variable);    

gl_VertexID

gl_Position and gl_PointSize is an output variable,
gl_VertexID is an input variable (integer variable).

gl_VertexID stores the current ID of the vertex being drawn.
When index rendering (using glDrawElements), this variable stores the current index of the vertex being drawn.
When drawing (using glDrawArrays) without an index, this variable stores the number of vertices processed from the rendering call.
Simply put, it's a data buffered counter.

Clip shader variable

gl_FragCoord

gl_ The x and y components of fragcoord are the window space coordinates of the fragment, and its origin is the lower left corner of the window.
gl_ The z component of fragcoord is equal to the depth value of the corresponding fragment.
Usage example: different rendering methods are used for different screen areas, which can be used to compare different rendering effects.

 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);        

gl_FrontFacing

gl_FrontFacing will tell us whether the current clip belongs to a part of the forward face or a part of the back face.
gl_ The frontfacing variable is a bool type. The front returns true and the back returns false.
Use example: use different texture attributes on the front and back, which can be used to render objects with different internal and external textures (when the interior of the object is also visible).

if(gl_FrontFacing)
    FragColor = texture(frontTexture, TexCoords);
else
    FragColor = texture(backTexture, TexCoords);

Premise: do not open face culling.

gl_FragDepth

gl_FragCoord allows us to get its depth value,
gl_FragDepth can be used to set the depth value of a clip within a shader.
However, setting the depth value by ourselves has a big disadvantage, as long as we set GL in the fragment shader_ When fragdepth is written, OpenGL will disable all early depth testing.
It is disabled because OpenGL cannot know the depth value that the clip will have before the clip shader runs, because the clip shader may completely modify this depth value.
However, starting from OpenGL 4.2, we can still reconcile the two, and redeclare GL using depth condition at the top of the fragment shader_ Fragdepth variable:
layout (depth_) out float gl_FragDepth;
condition can be the following values:

conditiondescribe
anyDefault value. Advanced depth testing is disabled, and you will lose a lot of performance
greaterYou can only make the depth value greater than gl_FragCoord.z is larger
lessYou can only make the depth value greater than gl_FragCoord.z smaller
unchangedIf you want to write gl_FragDepth, you can only write GL_ Value of fragcoord. Z

Then use
gl_FragDepth = depth value. To rewrite.

Where to use it is unknown.

Interface block

out VS_OUT
{
    vec2 TexCoords;
} vs_out;

All output variables sent to the next shader.

in VS_OUT
{
    vec2 TexCoords;
} fs_in;

As long as two interface blocks have the same name, their corresponding inputs and outputs will match. The instance name (vs.out – > FS. In) can be arbitrary.

Uniform buffer object

It allows us to define a series of global uniform variables that are the same in multiple shaders. When using the uniform buffer object, we only need to set the relevant uniform once. Of course, we still need to manually set a different uniform in each shader. And creating and configuring uniform buffer objects can be a little cumbersome.

Create a Uniform buffer object

unsigned int uboExampleBlock;
glGenBuffers(1, &uboExampleBlock);
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);
glBufferData(GL_UNIFORM_BUFFER, 152, NULL, GL_STATIC_DRAW); // Allocate 152 bytes of memory
glBindBuffer(GL_UNIFORM_BUFFER, 0);

Uniform block

layout (std140) uniform Matrices
{
    mat4 projection;
    mat4 view;
};

Memory layout

OpenGL - GLSL advanced chapter & dynamic Superman
This article introduces various forms of memory layout in detail

Shared layout

The offset is defined by hardware, but we don't know how to fill our Uniform buffer accurately.
So to get a specific offset, you need to

  • glGetUniformIndices gets the indexes of all uniform variables
  • glGetActiveUniformsiv obtains the corresponding offset value, size, type and other information through the index of the uniform variable
  • glGetActiveUniformBlockiv gets the index of the uniform cache and gets the size of the entire block

I don't know how to use it..... First of all, I know there is such a thing ~ ~ [vegetable dog. jpg]~~

std140

The memory allocation rules are the same as those of c language struct.

According to the layout rules of std140, we can use functions like glBufferSubData to fill the variable data into the buffer according to the offset.

Binding point

Just like the binding of sampler

lightShader.setInt("material.sampler", 0);//material.  samlper accepts the texture of binding point 0
glActiveTexture(GL_TEXTURE0);//Activate binding point 0
glBindTexture(GL_TEXTURE_2D, texture1);//Load texture to binding point

There are in the Uniform buffer object
1. Link the Lights Uniform block in the figure to the binding point 2:

unsigned int lights_index = glGetUniformBlockIndex(shaderA.ID, "Lights");
glUniformBlockBinding(shaderA.ID, lights_index, 2);

From OpenGL 4.2, you can also add a layout identifier to explicitly store the binding point of the Uniform block in the shader, so that you don't have to call glGetUniformBlockIndex and glUniformBlockBinding.

layout(std140, binding = 2) uniform Lights { ... };

2. Bind the Uniform buffer object to the same binding point

glBindBufferBase(GL_UNIFORM_BUFFER, 2, uboExampleBlock); 
// or
glBindBufferRange(GL_UNIFORM_BUFFER, 2, uboExampleBlock, 0, 152);

glBindbufferBase (target, a binding point index, a Uniform buffer object);

glBindBufferRange (target, a binding point index, a Uniform buffer object, additional offset, size parameter);
glBindBufferRange can bind a specific part of the Uniform buffer to the binding point.

Add data to the Uniform buffer

//The cache must be bound before adding data to the cache
glBindBuffer(GL_UNIFORM_BUFFER, uboExampleBlock);

int b = true; // The bool in GLSL is 4 bytes, so we save it as an integer

glBufferSubData(GL_UNIFORM_BUFFER, 144, 4, &b); 
//Glbuffersubdata (cache type, offset, replacement space size, content pointer); 

glBindBuffer(GL_UNIFORM_BUFFER, 0);

A simple example

  1. Change first
uniform mat4 projection;
uniform  mat4 view;

by

layout(std140) uniform Matrices {
    mat4 projection;
    mat4 view;
};

When using projection and view, it is still called directly (not Matrices.projection, but directly using projection).

  1. Set the global binding cache of binding points and store the projection and view in the cache
//Uniform Binding Object stores projection and viewport change matrix
    unsigned int ubo;
    glGenBuffers(1, &ubo);
    glBindBuffer(GL_UNIFORM_BUFFER, ubo);
    glBufferData(GL_UNIFORM_BUFFER, 2 * sizeof(glm::mat4), NULL, GL_STATIC_DRAW);//Set ubo to two mat4 sized memories
    glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(glm::mat4), glm::value_ptr(projection));//Save the projection to the first location
    //glm::value_ptr passes in a matrix and returns an array.
    glBindBuffer(GL_UNIFORM_BUFFER, 0);
    glBindBufferRange(GL_UNIFORM_BUFFER, 0, ubo, 0, 2 * sizeof(glm::mat4));//Set ubo all memory to binding point 0
view = maincamera.getViewMetrix();
glBindBuffer(GL_UNIFORM_BUFFER, ubo);
glBufferSubData(GL_UNIFORM_BUFFER, sizeof(glm::mat4), sizeof(glm::mat4), glm::value_ptr(view));
glBindBuffer(GL_UNIFORM_BUFFER, 0);
  1. Bind Matrices to binding point 0.

    If you do not use the points defined in the shader for uniform binding * * (binding = 0),
    We have two ways

  • The first method
 unsigned int uniformBlockIndexRed = glGetUniformBlockIndex(lightShader.ID, "Matrices");
 glUniformBlockBinding(lightShader.ID, uniformBlockIndexRed, 0);
  • The second method
Shader Class:

void Shader::setUniformBlockBinding(const std::string& name, int value) const {
    glUniformBlockBinding(ID, glGetUniformBlockIndex(ID, name.c_str()), value);
}

It is easy to add with Shader class methods.

main->while In circulation

	lightShader.setUniformBlockBinding("Matrices", 0);
  • The third method
    Use the points in the shader that define uniform binding (binding = 0), as follows
layout(std140, binding = 0) uniform Matrices {
    mat4 projection;
    mat4 view;
};

The third method is limited to OpenGL version 4.2.

Keywords: OpenGL

Added by kkibak on Thu, 04 Nov 2021 01:15:42 +0200