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
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);
}
댓글