glslチュートリアル、指向性ライト
5534 ワード
GLSL Tutorial
OpenGL Directional Lights I
The equations in here are from the chapter "The Mathematics of Lighting"from the book "OpenGL Programming Guide", aka the Red Book.//このチュートリアルはopengl紅宝書から来ています
We'll start with the diffuse term. The diffuse lighting in OpenGL assumes that the light is perceived with the same intensity regardless if the viewers position. Its intensity is proportional to both the lights diffuse intensity as well as material's diffuse reflection coefficient. The intensity is also proportional to the angle between the light direction and the normal of the surface.
The following formula is used in OpenGL to compute the diffuse term:
where I is the reflected intensity, Ld is the light's diffuse color (gl_LightSource[0].diffuse), and Md is the material's diffuse coefficient (gl_FrontMaterial.diffuse).
This is known as Lambertian Reflection. 'Lambert's cosine law' states that the brightness of a diffusely radiating plane surface is proportional to the cosine of the angle formed by the line of sight and the normal to the surface. This was more than 200 years ago (Johann Heinrich Lambert, 1728-1777)!
The vertex shader to implement this formula will use the lights properties, namely its position, and diffuse intensity. It will also use the materials diffuse setting. Hence to use this shader just set the light as usual in OpenGL. Note however that since we're not using the fixed functionality, there is no need to enable the lights.
Since we need to compute a cosine, first we're going to make sure that the normal vector and the light direction vector (gl_LightSource[0].position) are normalized, and then we'll use the dot product to get the cosine. Note that,for directional lights,OpenGL stores the light direction as the vector from the vertex to the light source,which is the opposite to what is shown in the above figure.指向光ではOPENGLはライトの方向ベクトルを保持し,頂点から光源まで
OpenGL stores the lights direction in eye space coordinates; hence we need to transform the normal to eye space in order to compute the dot product. To transform the normal to eye space we will use the pre-defined uniform variable mat3 gl_NormalMatrix. This matrix is the transpose of the inverse of the 3x3 upper left sub matrix from the modelview matrix.//Openglはライトの方向ベクトルを眼座標に格納するので、頂点のベクトルを眼座標に変換する必要があります.
The following vertex shader shows the GLSL code to achieve this.
Now in the fragment shader all there is left to do is setting the fragments color, using the varying gl_Color variable.
The following image shows this shader applied to the teapot. Note that the bottom of the teapot is too dark. This is because we're not taking into account the ambient lighting terms available in OpenGL.
Incorporating the ambient terms is also easy to do. There is a global ambient term and a light ambient term. The formula for the ambient term is as follows:
環境光は、グローバル環境光成分に材料を乗じた環境光成分に等しく、照明の環境光成分に材料を乗じた環境光成分The vertex shader needs to add a few instructions to compute the ambient term:
The following image shows the end result. Adding an ambient term washes out color, but it's a cheap workaround for the lack of a global illumination model where light bounces, and hence it affects surfaces not directly affected by the light source.
Move on to the next section for the specular component.
OpenGL Directional Lights I
The equations in here are from the chapter "The Mathematics of Lighting"from the book "OpenGL Programming Guide", aka the Red Book.//このチュートリアルはopengl紅宝書から来ています
We'll start with the diffuse term. The diffuse lighting in OpenGL assumes that the light is perceived with the same intensity regardless if the viewers position. Its intensity is proportional to both the lights diffuse intensity as well as material's diffuse reflection coefficient. The intensity is also proportional to the angle between the light direction and the normal of the surface.
The following formula is used in OpenGL to compute the diffuse term:
where I is the reflected intensity, Ld is the light's diffuse color (gl_LightSource[0].diffuse), and Md is the material's diffuse coefficient (gl_FrontMaterial.diffuse).
This is known as Lambertian Reflection. 'Lambert's cosine law' states that the brightness of a diffusely radiating plane surface is proportional to the cosine of the angle formed by the line of sight and the normal to the surface. This was more than 200 years ago (Johann Heinrich Lambert, 1728-1777)!
The vertex shader to implement this formula will use the lights properties, namely its position, and diffuse intensity. It will also use the materials diffuse setting. Hence to use this shader just set the light as usual in OpenGL. Note however that since we're not using the fixed functionality, there is no need to enable the lights.
Since we need to compute a cosine, first we're going to make sure that the normal vector and the light direction vector (gl_LightSource[0].position) are normalized, and then we'll use the dot product to get the cosine. Note that,for directional lights,OpenGL stores the light direction as the vector from the vertex to the light source,which is the opposite to what is shown in the above figure.指向光ではOPENGLはライトの方向ベクトルを保持し,頂点から光源まで
OpenGL stores the lights direction in eye space coordinates; hence we need to transform the normal to eye space in order to compute the dot product. To transform the normal to eye space we will use the pre-defined uniform variable mat3 gl_NormalMatrix. This matrix is the transpose of the inverse of the 3x3 upper left sub matrix from the modelview matrix.//Openglはライトの方向ベクトルを眼座標に格納するので、頂点のベクトルを眼座標に変換する必要があります.
The following vertex shader shows the GLSL code to achieve this.
void main() {
vec3 normal, lightDir;
vec4 diffuse;
float NdotL;
/* first transform the normal into eye space and normalize the result */
normal = normalize(gl_NormalMatrix * gl_Normal);
/* now normalize the light's direction. Note that according to the
OpenGL specification, the light is stored in eye space. Also since
we're talking about a directional light, the position field is actually
direction */
lightDir = normalize(vec3(gl_LightSource[0].position));
// ,
/* compute the cos of the angle between the normal and lights direction.
The light is directional so the direction is constant for every vertex.
Since these two are normalized the cosine is the dot product. We also
need to clamp the result to the [0,1] range. */
NdotL = max(dot(normal, lightDir), 0.0);
,
/* Compute the diffuse term */
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
gl_FrontColor = NdotL * diffuse;
gl_Position = ftransform();
}
Now in the fragment shader all there is left to do is setting the fragments color, using the varying gl_Color variable.
void main()
{
gl_FragColor = gl_Color;
}
The following image shows this shader applied to the teapot. Note that the bottom of the teapot is too dark. This is because we're not taking into account the ambient lighting terms available in OpenGL.
Incorporating the ambient terms is also easy to do. There is a global ambient term and a light ambient term. The formula for the ambient term is as follows:
環境光は、グローバル環境光成分に材料を乗じた環境光成分に等しく、照明の環境光成分に材料を乗じた環境光成分The vertex shader needs to add a few instructions to compute the ambient term:
void main()
{
vec3 normal, lightDir;
vec4 diffuse, ambient, globalAmbient;
float NdotL;
normal = normalize(gl_NormalMatrix * gl_Normal);
lightDir = normalize(vec3(gl_LightSource[0].position));
NdotL = max(dot(normal, lightDir), 0.0);
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
/* Compute the ambient and globalAmbient terms */
ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;
globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient;
gl_FrontColor = NdotL * diffuse + globalAmbient + ambient;
gl_Position = ftransform();
}
The following image shows the end result. Adding an ambient term washes out color, but it's a cheap workaround for the lack of a global illumination model where light bounces, and hence it affects surfaces not directly affected by the light source.
Move on to the next section for the specular component.