1. 著色器ADS光照,Phong著色,紋理的使用,Disssovle丟棄片段的例子
1. 客戶端代碼
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch sphereBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;
GLuint ADSLightShader;
GLint locAmbient;
GLint locDiffuse;
GLint locSpecular;
GLint locLight;
GLint locMVP;
GLint locMV;
GLint locNM;
GLint locTexture;
GLuint locDissolve;
GLuint texture;
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode) {
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
//讀取圖片像素
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
//設(shè)置紋理環(huán)繞模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
//設(shè)置紋理過濾模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
//像素以非包裝,每一個字節(jié)的方式進行存儲
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//加載紋理
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
//釋放像素
free(pBits);
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
//預(yù)加載紋理Mip貼圖層,防止向前后移動幾何體時上面的貼圖加載過大,而出現(xiàn)性能消耗或者失真
glGenerateMipmap(GL_TEXTURE_2D);
return true;
}
void SetupRC(void){
//設(shè)置背景顏色
glClearColor(0.0, 0.0, 0.0, 1.0);
//開啟深度測試
glEnable(GL_DEPTH_TEST);
//剔除看不見的面,提高性能
glEnable(GL_CULL_FACE);
//初始化存儲著色器
shaderManager.InitializeStockShaders();
//將角色幀向前移動
viewFrame.MoveForward(4.0);
//設(shè)置一個球體
gltMakeSphere(sphereBatch, 1.0, 26, 13);
//構(gòu)建一個著色器
ADSLightShader = gltLoadShaderPairWithAttributes("ADSTexture.vp", "ADSTexture.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVtertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexture0");
//定位統(tǒng)一值得到統(tǒng)一值管理對象
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");
locTexture = glGetUniformLocation(ADSLightShader, "colorMap");
locDissolve = glGetUniformLocation(ADSLightShader, "dissolveFactor");
//設(shè)置紋理對象
glGenTextures(1, &texture);
//綁定紋理
glBindTexture(GL_TEXTURE_2D, texture);
//載入并設(shè)置紋理
LoadTGATexture("CoolTexture.tga", GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, GL_CLAMP_TO_EDGE);
}
void ShutdownRC(void){
//刪除紋理對象
glDeleteTextures(1, &texture);
}
void RenderScene(void){
static CStopWatch rotTimer;
//清除顏色緩沖區(qū)和深度緩沖區(qū)數(shù)據(jù)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//將角色幀對應(yīng)的幾何體和頂部的模型視圖堆棧矩陣相乘放入模型視圖堆棧的頂部
modelViewMatrix.PushMatrix(viewFrame);
//將堆棧中的角色幀旋轉(zhuǎn)
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);
//設(shè)置光線位置
GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
//設(shè)置環(huán)境光顏色
GLfloat vAmbientColor[] = { 0.2f, 0.2f, 0.2f, 1.0f };
//設(shè)置漫射光顏色
GLfloat vDiffuseColor[] = { 1.0f, 1.0f, 1.0f, 1.0f};
//設(shè)置反射光顏色
GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
//使用著色器程序
glUseProgram(ADSLightShader);
//設(shè)置環(huán)境光初始值
glUniform4fv(locAmbient, 1, vAmbientColor);
//設(shè)置漫射光初始值
glUniform4fv(locDiffuse, 1, vDiffuseColor);
//設(shè)置折射光初始值
glUniform4fv(locSpecular, 1, vSpecularColor);
//設(shè)置光源位置
glUniform3fv(locLight, 1, vEyeLight);
//設(shè)置模型視圖投影矩陣
glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
//設(shè)置模型視圖矩陣
glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
//設(shè)置世界坐標系的幾何表面法向矩陣
glUniformMatrix3fv(locNM, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
//得到綁定的紋理對象
glBindTexture(GL_TEXTURE_2D, texture);
//設(shè)置紋理使用的Mip紋理貼圖為基層
glUniform1i(locTexture, 0);
float fFactor = fmod(rotTimer.GetElapsedSeconds(), 20.0f);
fFactor /= 20.0f;
glUniform1f(locDissolve, fFactor);
// 繪制
sphereBatch.Draw();
// 角色幀出棧
modelViewMatrix.PopMatrix();
//雙緩沖區(qū)交換數(shù)據(jù)
glutSwapBuffers();
//窗口刷新顯示
glutPostRedisplay();
}
void ChangeSize(int w, int h){
if (h == 0){
h = 1;
}
//設(shè)置視口大小
glViewport(0, 0, w, h);
//設(shè)置投影錐體
viewFrustum.SetPerspective(35.0, float(w)/float(h), 1.0, 100.0);
//載入投影矩陣到投影堆棧
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//設(shè)置管線管理模型視圖矩陣堆棧和投影矩陣堆棧
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("Lit Texture");
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;
}
2. 著色器代碼
//頂點著色器
//設(shè)置著色器版本
#version 120
//頂點著色器屬性
attribute vec4 vVertex;
attribute vec3 vNormal;
attribute vec4 vTexture0;
//統(tǒng)一值
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
uniform vec3 vLightPosition;
//下一階段輸出值
varying vec3 vVaryingNormal;
varying vec3 vVaryingLightDir;
varying vec2 vTexCoords;
void main(void) {
//得到視覺坐標系下的法向量
vVaryingNormal = normalMatrix * vNormal;
//得到視覺坐標系下的頂點
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
//得到單位光源向量
vVaryingLightDir = normalize(vLightPosition - vPosition3);
//設(shè)置紋理坐標,紋理坐標會映射紋理單元的地址
vTexCoords = vTexture0.st;
// 對頂點進行模型視圖投影變換計算
gl_Position = mvpMatrix * vVertex;
}
//片段著色器
//設(shè)置著色器版本號
#version 120
//統(tǒng)一值
uniform vec4 ambientColor;
uniform vec4 diffuseColor;
uniform vec4 specularColor;
uniform sampler2D colorMap;
uniform float dissolveFactor;
//上一階段輸入值
varying vec3 vVaryingNormal;
varying vec3 vVaryingLightDir;
varying vec2 vTexCoords;
//這里用到了Phong著色,只是向片段著色器傳入沒有插值顏色的頂點,因為插值顏色頂點是分布不均的,這樣可能會出現(xiàn)光照不均的不想要的結(jié)果
//這里將顏色值作為統(tǒng)一值直接傳給了片段著色器處理,代價是更多的性能消耗
void main(void) {
//通過紋理坐標找到需要貼圖的幾何體對應(yīng)的紋理單元的紋理顏色值
vec4 vCloudSample = texture2D(colorMap, vTexCoords);
//當(dāng)紋理單元的r值小于dissolveFactor時,舍棄該片段
if(vCloudSample.r < dissolveFactor)
discard;
// 得到法向量和光源向量的夾角,夾角的強度模擬漫射光在不同光源位置下的強度
float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir)));
// 得到漫射光
gl_FragColor = diff * diffuseColor;
// 添加環(huán)境光
gl_FragColor += ambientColor;
// 這里先照亮紋理,因為紋理值乘以純白色只會得到一個照亮的紋理值,不會表現(xiàn)出高光,然后在進行高光折射光的處理
//通過紋理坐標找到需要貼圖的幾何體對應(yīng)的紋理單元的紋理顏色值通過相乘添加到之前的光源上得到新的光柵顏色值
gl_FragColor *= texture2D(colorMap, vTexCoords);
// 得到折射向量
vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal)));
// 得到反射光與法向量的夾角
float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection));
if(diff != 0) {
//得到漫射光強度,其實OpenGL的照相機隱藏的做了視線的管理,反射光的強度是視覺向量和反射光向量的夾角值
float fSpec = pow(spec, 128.0);
//添加反射光
gl_FragColor.rgb += vec3(fSpec, fSpec, fSpec);
}
}
2. 紋理模擬光源
1. 客戶端代碼
GLFrame viewFrame;
GLFrustum viewFrustum;
GLTriangleBatch torusBatch;
GLMatrixStack modelViewMatrix;
GLMatrixStack projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager shaderManager;
GLuint toonShader;
GLint locLight;
GLint locMVP;
GLint locMV;
GLint locNM;
GLint locColorTable;
GLuint texture;
void SetupRC(void) {
//設(shè)置背景顏色
glClearColor(0.025f, 0.25f, 0.25f, 1.0f );
//開啟深度測試,防止圖元重疊
glEnable(GL_DEPTH_TEST);
//開啟圖元剔除,剔除看不見的圖元提高性能
glEnable(GL_CULL_FACE);
//初始化存儲著色器
shaderManager.InitializeStockShaders();
//角色幀向前移動
viewFrame.MoveForward(4.0f);
//設(shè)置花托,通過torusBatch容器管理
gltMakeTorus(torusBatch, 0.80f, 0.25f, 52, 26);
//生成著色器程序
toonShader = gltLoadShaderPairWithAttributes("ToonShader.vp", "ToonShader.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal");
//定位統(tǒng)一值,得到統(tǒng)一值管理對象
locLight = glGetUniformLocation(toonShader, "vLightPosition");
locMVP = glGetUniformLocation(toonShader, "mvpMatrix");
locMV = glGetUniformLocation(toonShader, "mvMatrix");
locNM = glGetUniformLocation(toonShader, "normalMatrix");
locColorTable = glGetUniformLocation(toonShader, "colorTable");
//設(shè)置紋理對象
glGenTextures(1, &texture);
//綁定紋理
glBindTexture(GL_TEXTURE_1D, texture);
//設(shè)置一維紋理對應(yīng)的像素數(shù)據(jù)(RGB),一維紋理的坐標大于0小于1,通過一維紋理坐標會映射到紋理地址,著色器會通過法向量和光源向量夾角來表示一維紋理坐標來模擬漫射光強度,
GLubyte textureData[4][3] = { 32, 0, 0,
64, 0, 0,
128, 0, 0,
255, 0, 0};
//載入紋理,一維紋理,當(dāng)前層為基層,壓縮方式為rgb,長度是4,邊框為0,紋理數(shù)據(jù)為無符號,像素是textureData
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 4, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);
//設(shè)置紋理過濾方式
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
//設(shè)置紋理環(huán)繞模式
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
//預(yù)加載紋理Mip貼圖層,防止向前后移動幾何體時上面的貼圖加載過大,而出現(xiàn)性能消耗或者失真
glGenerateMipmap(GL_TEXTURE_1D);
}
void ShutdownRC(void) {
//清理紋理對象
glDeleteTextures(1, &texture);
}
// Called to draw scene
void RenderScene(void) {
static CStopWatch rotTimer;
//清除顏色緩沖區(qū)數(shù)據(jù),清除深度緩沖區(qū)數(shù)據(jù)和
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//將角色幀對應(yīng)的幾何體的頂點和頂部的模型視圖矩陣堆棧矩陣相乘放入模型視圖矩陣堆棧的頂部
modelViewMatrix.PushMatrix(viewFrame);
//模型視圖變換,旋轉(zhuǎn)變換
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);
//設(shè)置光線位置
GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
//使用著色器程序
glUseProgram(toonShader);
//設(shè)置著色器統(tǒng)一值
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());
glUniform1i(locColorTable, 0);
//繪制
torusBatch.Draw();
//移出模型視圖堆棧底部的矩陣
modelViewMatrix.PopMatrix();
//交換前后臺緩沖區(qū)數(shù)據(jù)
glutSwapBuffers();
//刷新展示
glutPostRedisplay();
}
void ChangeSize(int w, int h) {
if(h == 0){
h = 1;
}
//設(shè)置視口
glViewport(0, 0, w, h);
//設(shè)置投影變換
viewFrustum.SetPerspective(35.0f, float(w)/float(h), 1.0f, 100.0f);
//載入投影矩陣到投影矩陣堆棧
projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
//設(shè)置管線管理模型視圖矩陣堆棧和投影矩陣堆棧
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("Cell (toon) 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;
}
2. 著色器代碼
//頂點著色器
//設(shè)置著色器版本
#version 120
//設(shè)置頂點著色器屬性
attribute vec4 vVertex;
attribute vec3 vNormal;
//下一階段輸出值
varying float textureCoordinate;
//統(tǒng)一值
uniform vec3 vLightPosition;
uniform mat4 mvpMatrix;
uniform mat4 mvMatrix;
uniform mat3 normalMatrix;
void main(void) {
//設(shè)置視覺坐標系下的單位法向量
vec3 vEyeNormal = normalMatrix * vNormal;
//設(shè)置視覺坐標系下的頂點值
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
//設(shè)置光源向量
vec3 vLightDir = normalize(vLightPosition - vPosition3);
//得到法向量與光線向量的夾角,這個值作為片段著色器一維紋理的尋址坐標
//一維紋理單元坐標是大于0小于1的會映射到一維紋理單元的地址,正好可用夾角值模擬
textureCoordinate = max(0.0, dot(vEyeNormal, vLightDir));
//對頂點進行模型視圖投影矩陣變換計算
gl_Position = mvpMatrix * vVertex;
}
//片段著色器
//著色器版本
#version 120
//統(tǒng)一值
uniform sampler1D colorTable;
//上一階段輸出值
varying float textureCoordinate;
void main(void) {
//通過紋理坐標找到紋理單元得到紋理顏色值
//對紋理顏色光柵化
gl_FragColor = texture1D(colorTable, textureCoordinate);
}