본문 바로가기
전공/컴퓨터 그래픽스

OpenGL Shading Language (셰이딩) GLSL_(3)

by 임 낭 만 2023. 6. 18.

OpenGL Shading Language

Transformation of Surface Normals

  • The modelview matrix transforms vertices from the local coordinate system to the camera coordinate system
  • A later application of illumination models requires that the surface normal of each vertex is also transformed from the local coordinate system to the camera coordinate system
  • So far, the fixed-function pipeline has taken care of the transformation of normal. With shaders, this is now also a task of the programmer
  • When transforming surface normal, it should be considered that a normal is a unit vector that is neither translated nor scaled during a transformation with the modelview matrix Tmodelview. It is only rotated.
  • Problem: How can the transformation matrix Tnormal of the normal be calculated from the modelview matrix Tmodelview ?

  • Observation: In the local coordinate system the normal $n=(n_{x},n_{y},n_{z},0)^{\top} $ is orthogonal to the tangent $m=(m_{x},m_{y},m_{z},0)^{\top} $. Because of the transformation with Tmodelview the normal is mapped wrongly, but the tangent is still pointing in the right direction
  • Approach: Before the transformation, it holds that $n^{\top}m=0$ and this relationship should be maintained after the transformation, therefore:

  • Thus, for $\left (T_{normal}  \right )^{\top}T_{modelview}=I_{4\times 4}$ the condition is satisfied and it follows


Example: Transformation of Surface Normals

  • Vertex Shader
#version 140
in vec3 inputPosition;
in vec2 inputTexCoord;
in vec3 inputNormal;
uniform mat4 projection,modelview, normalMat;
uniform int mode;
out vec4 forFragColor;
void main() {
    gl_Position = projection * modelview * vec4(inputPosition, 1.0);
    vec4 normal = normalMat * vec4(inputNormal,0.0);
    if (mode == 1) forFragColor = normal;
    if (mode == 2) forFragColor = vec4(inputNormal, 1.0);
    if (mode == 3) forFragColor = gl_Position;
    if (mode == 4) forFragColor = vec4(inputPosition, 1.0);
    if (mode == 5) forFragColor = vec4(inputTexCoord, 0.0, 1.0);
}
  • Vertex Shader
#version 140
in vec4 forFragColor;
out vec4 outputColor;
void main() {
    outputColor = forFragColor;
}

Accesing Textures in the Shader

  • Textures can be accessed both in vertex and fragment shaders
  • To this end, a uniform variable of the type sampler must be defined: For example, in case of 2D texture:
uniform sampler2D myTexture;
  • With the function texture(…) the color value at the texture coordinate (s, t) is read:
texture(myTexture, vec2(s, t))

Providing Textures

  • Textures are generated in the application with glGenTexture and glBindTexture, parameters are set with glTexParameter, and the texture data is passed with glTexImage
  • To provide the texture in the shader, the location identifier of the sampler variable must be queried
texLoc = glGenUniformLocation(progID, "myTexture");
  • Then a texture unit is selected (e.g. here the zeroth unit), the texture is activated, and the number of the selected texture unit is passed to the sample variable:
glActiveTexture(GL_TEXTURE0);	//activate texture unit 0
glBindTexture(GL_TEXTURE_2D, texID);	//bind texture
glUniform1i(texLoc, 0);	//inform the shader to use texture unit 0

Example: Accessing Textures in the Shader

  • Vertex Shader
#version 140
in vec3 inputPosition;
in vec4 inputColor;
in vec2 inputTexCoord;
in vec3 inputNormal;
uniform mat4 projection, modelview;
out vec3 forFragColor;
out vec2 forFragTexCoord;
void main() {
    forFragColor = inputColor.rgb;
    forFragTexCoord = inputTexCoord;
    gl_Position = projection * modelview * vec4(inputPosition, 1.0);
}
  • Fragment Shader
#version 140
in vec3 forFragColor;
in vec2 forFragTexCoord;
out vec4 outputColor;
uniform sampler2D myTexture;
void main() {
    vec3 textureColor = vec3( texture(myTexture, forFragTexCoord) );
    outputColor = vec4(forFragColor*textureColor, 1.0);
}
  • Fragment shader alternative:
#version 140
in vec3 forFragColor;
in vec2 forFragTexCoord;
out vec4 outputColor;
uniform sampler2D myTexture;
void main() {
    vec3 textureColor = vec3( texture(myTexture, forFragTexCoord) );
    outputColor = vec4(forFragColor*textureColor, 1.0);
    if (forFragTexCoord.x > 0.5) outputColor = vec4(1.0, 0.0, 0.0, 1.0);
}
  • Fragment shader alternative 2:
#version 140
in vec3 forFragColor;
in vec2 forFragTexCoord;
out vec4 outputColor;
uniform sampler2D myTexture;
const vec2 texSize = vec2(256.0, 256.0);
void main() {
    vec3 tC= vec3( texture(myTexture, forFragTexCoord) );
    vec3 tC2 = vec3( texture(myTexture, forFragTexCoord + vec2(1.0/texSize.x, 0.0) );
    vec3 tC3 = vec3( texture(myTexture, forFragTexCoord + vec2(0.0, 1.0/texSize.y) );
    if (abs(tC.x - tC2.x) > 0.01) {
    	outputColor = vec4(1.0, 1.0, 1.0, 1.0);
    } else {
    	if (abs(tC.x - tC3.x) > 0.01) {
            outputColor = vec4(1.0, 1.0, 0.0, 1.0);
        } else {
            outputColor = vec4(forFragColor*tC, 1.0);
        }
    }
}

Early Fragment Tests

  • A fragment needs to pass a series of tests before it is written to the framebuffer
  • According to the OpenGL standard, these tests are executed after the fragment shader
  • For optimization, GPUs may perform the tests before the fragment shader if this does not change the behavior of the pipeline
  • For example, if the depth value gl_FragDepth is changed by the fragment shader, the depth test cannot be performed early
  • As of GLSL version 4.2, Early Fragment Tests can be enforced with:
#version 420
layout(early_fragment_tests) in;

댓글