光照模型
ADS代表環境光(Ambient)、漫射光(Diffuse)、鏡面光(Specular)。
環境光
環境光所照射的物體在所有方向的表面都是均勻照亮的,我們可以把環境光看成應用到每個光源的全局照明因子。
vVaryingColor += ambientColor;
漫射光
關於漫射光的算法,上篇敘述很詳細了,此處不多贅述。
vec3 vEyeNormal = normalMatrix * vNormal;
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
vec3 vLightDir = normalize(vLightPosition - vPosition3);
float diff = max(0.0, dot(vEyeNormal, vLightDir));
vVaryingColor = diff * diffuseColor;
鏡面光
鏡面光的反射角度很銳利,只沿一個特定的方向反射,高強度的鏡面光趨向於在它所照射的表面形成一個亮點,成爲鏡面亮點。
計算方法:把反射的表面法線向量和反向的光線向量點乘,然後取反光度(shininess)次冪,反光度數值越大,結果得到鏡面反射的高亮區越小,最高的鏡面指數(specular power)被設置爲128,大於這個數字的值效果會逐漸減弱。
vec3 vReflection = normalize(reflect(-vLightDir, vEyeNormal));
float spec = max(0.0, dot(vEyeNormal, vReflection));
if(diff != 0.0f) {
float fSpec = pow(spec, 128.0);
vVaryingColor.rgb += vec3(fSpec, fSpec, fSpec);
}
main.cpp
#include<GLTools.h>
#include<GLFrame.h>
#include<GLFrustum.h>
#include<GLMatrixStack.h>
#include<StopWatch.h>
#include<GLGeometryTransform.h>
#include<math.h>
#include<GLUT/GLUT.h>
GLFrame viewFrame;
GLFrustum viewFrustum;
GLGeometryTransform transformPipeline;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLTriangleBatch sphereBatch;
GLuint ADSLightShader;
GLint locAmbient;
GLint locDiffuse;
GLint locSpecular;
GLint locLight;
GLint locMVP;
GLint locMV;
GLint locNM;
void SetupRC(void)
{
glClearColor(1.0f,1.0f,1.0f,1.0f);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
viewFrame.MoveForward(4.0f);
gltMakeSphere(sphereBatch,1.0f,26,13);
ADSLightShader=gltLoadShaderPairWithAttributes("/Users/mac/Downloads/1/ADSGouraud.vp","/Users/mac/Downloads/1/ADSGouraud.fp",2,GLT_ATTRIBUTE_VERTEX,"vVertex",GLT_ATTRIBUTE_NORMAL,"vNormal");
locAmbient = glGetUniformLocation(ADSLightShader, "ambientColor");
locDiffuse = glGetUniformLocation(ADSLightShader, "diffuseColor");
locSpecular = glGetUniformLocation(ADSLightShader, "specularColor");
locLight = glGetUniformLocation(ADSLightShader, "vLightPosition");
locMVP = glGetUniformLocation(ADSLightShader, "mvpMatrix");
locMV = glGetUniformLocation(ADSLightShader, "mvMatrix");
locNM = glGetUniformLocation(ADSLightShader, "normalMatrix");
}
void ShutdownRC()
{
}
void RenderScene(void)
{
static CStopWatch rotTimer;
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
modelViewMatrix.PushMatrix(viewFrame);
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds()*5.0f,0.0f,1.0f,0.0f);
GLfloat vEyeLight[]={-100.0f,100.0f,100.0f};
GLfloat vAmbientColor[]={0.1f,0.1,0.1f,1.0f};
GLfloat vDiffuseColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glUseProgram(ADSLightShader);
glUniform4fv(locAmbient, 1, vAmbientColor);
glUniform4fv(locDiffuse, 1, vDiffuseColor);
glUniform4fv(locSpecular, 1, vSpecularColor);
glUniform3fv(locLight, 1, vEyeLight);
glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
sphereBatch.Draw();
modelViewMatrix.PopMatrix();
glutSwapBuffers();
glutPostRedisplay();
}
void ChangeSize(int w,int h)
{
glViewport(0,0,w,h);
viewFrustum.SetPerspective(35.0f,float(w)/float(h),1.0f,100.0f);
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
transformPipeline.SetMatrixStacks(modelViewMatrix,projectionMatrix);
}
int main(int argc, char* argv[])
{
gltSetWorkingDirectory(argv[0]);
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
glutInitWindowSize(800, 600);
glutCreateWindow("ADS Lighting, Gouraud Shading");
glutReshapeFunc(ChangeSize);
glutDisplayFunc(RenderScene);
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
SetupRC();
glutMainLoop();
ShutdownRC();
return 0;
}
.vp
#version 120
// Incoming per vertex... position and normal
attribute vec4 vVertex;
attribute vec3 vNormal;
// Set per batch
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
uniform vec3 vLightPosition;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
// Color to fragment program
varying vec4 vVaryingColor;
void main(void)
{
// Get surface normal in eye coordinates
vec3 vEyeNormal = normalMatrix * vNormal;
// Get vertex position in eye coordinates
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
// Get vector to light source
vec3 vLightDir = normalize(vLightPosition - vPosition3);
// Dot product gives us diffuse intensity
float diff = max(0.0, dot(vEyeNormal, vLightDir));
// Multiply intensity by diffuse color, force alpha to 1.0
vVaryingColor = diff * diffuseColor;
// Add in ambient light
vVaryingColor += ambientColor;
// Specular Light
vec3 vReflection = normalize(reflect(-vLightDir, vEyeNormal));
float spec = max(0.0, dot(vEyeNormal, vReflection));
if(diff != 0.0f) {
float fSpec = pow(spec, 128.0);
vVaryingColor.rgb += vec3(fSpec, fSpec, fSpec);
}
// Don't forget to transform the geometry!
gl_Position = mvpMatrix * vVertex;
}
.fp
#version 120
varying vec4 vVaryingColor;
void main(void)
{
gl_FragColor = vVaryingColor;
}