我们这节将使用一维纹理实现下图中的效果
我们首先会创建一个红色分量逐渐增大的一维纹理数据
<pre name="code" class="cpp"> //纹理对象颜色值
GLubyte textureData[4][3] = {
32, 0, 0,
64, 0, 0,
128, 0, 0,
255, 0, 0
};
该一维纹理只有颜色值,纹理的坐标从0到1,我们根据漫反射的光照强度来决定使用的纹理坐标颜色值
下面是顶点着色器ToonShader.vp中的全部代码
// 要求OpenGL的版本最低是1.3
#version 130
// 需要从外界传入的字段
//顶点
in vec4 vVertex;
//顶点法线
in vec3 vNormal;
smooth out float textureCoordinate;
//下面是需要外界设置的统一值
//光源的位置
uniform vec3 vLightPosition;
//模型视图变换矩阵
uniform mat4 mvpMatrix;
//视图变换矩阵
uniform mat4 mvMatrix;
//模型视图变换矩阵法线矩阵
uniform mat3 normalMatrix;
void main(void)
{
// 得到法线在照相机坐标系下的位置
vec3 vEyeNormal = normalMatrix * vNormal;
// 得到顶点在照相机坐标系下的位置
vec4 vPosition4 = mvMatrix * vVertex;
vec3 vPosition3 = vPosition4.xyz / vPosition4.w;
// 得到光源方向
vec3 vLightDir = normalize(vLightPosition - vPosition3);
// 漫反射光照强度
textureCoordinate = max(0.0, dot(vEyeNormal, vLightDir));
// 把顶点变换到照相机坐标系下
gl_Position = mvpMatrix * vVertex;
}
下面是片段着色器ToonShader.fp中的全部代码
// 要求OpenGL的版本最低是1.3
#version 130
//纹理对象
uniform sampler1D colorTable;
//传出到光栅化阶段的颜色值
out vec4 vFragColor;
//从顶点着色器传入的漫反射光照强度值
smooth in float textureCoordinate;
void main(void)
{
vFragColor = texture(colorTable, textureCoordinate);
}
下面是工程中的代码
首先我们来看一下需要包含的头文件和全局变量部分
#include <GLTools.h>
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>
#include <math.h>
#define FREEGLUT_STATIC
#include <GL/glut.h>
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;
下面是主函数main
int main(int argc, char* argv[])
{
//设置工程路径
gltSetWorkingDirectory(argv[0]);
//初始化GLUT
glutInit(&argc, argv);
//设置需要使用的窗口模式
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH | GLUT_STENCIL);
//窗口的大小
glutInitWindowSize(800, 600);
//窗口的名字
glutCreateWindow("ToomShader");
//窗口大小改变时的回调函数
glutReshapeFunc(ChangeSize);
//渲染时的回调函数
glutDisplayFunc(RenderScene);
//初始化glew
GLenum err = glewInit();
if (GLEW_OK != err) {
fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
return 1;
}
//初始化函数
SetupRC();
//消息循环
glutMainLoop();
//程序退出时的清理工作
ShutdownRC();
return 0;
}
下面是窗口大小改变时的回调函数ChangeSize
void ChangeSize(int w, int h)
{
// Prevent a divide by zero
if (h == 0)
h = 1;
//设置视口大小
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);
}
下面是初始化函数SetupRC
void SetupRC(void)
{
glClearColor(0.025f, 0.25f, 0.25f, 1.0f );
glEnable(GL_DEPTH_TEST);
shaderManager.InitializeStockShaders();
viewFrame.MoveForward(4.0f);
// 创建泳圈模型数据
gltMakeTorus(torusBatch, .80f, 0.25f, 52, 26);
//加载自己写的着色器
toonShader = gltLoadShaderPairWithAttributes("ToonShader.vp", "ToonShader.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",
GLT_ATTRIBUTE_NORMAL, "vNormal");
//得到着色器中的uniform值的位置引用,以便对它赋值
locLight = glGetUniformLocation(toonShader, "vLightPosition");
locMVP = glGetUniformLocation(toonShader, "mvpMatrix");
locMV = glGetUniformLocation(toonShader, "mvMatrix");
locNM = glGetUniformLocation(toonShader, "normalMatrix");
locColorTable = glGetUniformLocation(toonShader, "colorTable");
//创建纹理对象
glGenTextures(1, &texture);
//绑定纹理对象
glBindTexture(GL_TEXTURE_1D, texture);
//纹理对象颜色值
GLubyte textureData[4][3] = { 32, 0, 0,
64, 0, 0,
128, 0, 0,
255, 0, 0};
//创建一维纹理
glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 4, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);
//设置过滤模式
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//设置环绕模式
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
}
下面是渲染函数RenderScene
void RenderScene(void)
{
static CStopWatch rotTimer;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
modelViewMatrix.PushMatrix(viewFrame);
modelViewMatrix.Rotate(rotTimer.GetElapsedSeconds() * 10.0f, 0.0f, 1.0f, 0.0f);
GLfloat vEyeLight[] = { -100.0f, 100.0f, 100.0f };
GLfloat vAmbientColor[] = { 0.1f, 0.1f, 0.1f, 1.0f };
GLfloat vDiffuseColor[] = { 0.1f, 1.0f, 0.1f, 1.0f };
GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };
//使用自己写的着色器
glUseProgram(toonShader);
//设置着色器中的uniform值
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();
glutSwapBuffers();
glutPostRedisplay();
}
下面是程序退出时的清理函数ShutdownRC
void ShutdownRC(void)
{
//删除纹理对象
glDeleteTextures(1, &texture);
}