OpenGL GLSL

GLSL是OpenGL的着色语言, 我们之前的例子,都是用的着色器管理类GLShaderManager中的函数UseStockShader来使用着色器的,该函数完成的东西就是对我们的顶点数据进一步的加工,比如设置顶点颜色,设置顶点光照的强度,设置顶点纹理等。

假如说我们对UseStockShader函数一些默认的效果不满意,比如我们要让模型的一部分比另一部分更亮,也就是光线照到的地方,比没有照到的地方要亮,这个时候就要写自己的着色器。

如下图:

OpenGL GLSL_第1张图片


这也是我们这一节要实现的例子,模型的左上角比较亮。


着色器分为顶点着色器 ,几何着色器,片段着色器,本节只介绍顶点着色器和片段着色器

顶点着色器记录的是顶点的属性和一些对顶点的操作,顶点着色器的文件后缀为,vp

片段着色器记录的是片段的属性和一些对片段的操作,片段着色器的文件后缀是.fp

片段的意思就是组成模型的最小单元,比如一个三角形就是一个片段

顶点着色器在处理顶点后会将处理的结果传给片段着色器


着色器的入口函数同样是main函数


下面先写一个我们的顶点着色器,写完后我们在说怎么用它

创建一个记事本名字叫做DiffuseLight.txt,然后把后缀名改成.vp,最后是DiffuseLight.vp

在GLSL语言中,我们可以用vec3声明一个三维向量,vec4声明一个4维向量,用mat4声明一个4*4的矩阵,用mat3声明一个3*3的矩阵

我们在DiffuseLight.vp先来声明一下我们的全局变量


//指定OpenGL的最低版本为1.3
#version 130
//关键字in表示是要从外界输入的变量
in vec4 vVertex;
in vec3 vNormal;
//关键字uniform 表示统一值的意思
uniform vec4	diffuseColor;	//漫反射光的颜色值
uniform vec3	vLightPosition; //光源的位置
uniform mat4	mvpMatrix; //模型视图投影矩阵
uniform mat4	mvMatrix; //视图矩阵
uniform mat3	normalMatrix; //模型视图的法线矩阵
//关键字out表示的是输出的值,也就是传给片段着色器的值,smooth表示颜色值vVaryingColor采用平滑插值的方式
smooth out vec4 vVaryingColor;


 其中#version用来指导OpenGL的版本,#version 130 表示该着色器要求OpenGL的版本最低是1.3 
  

关键字in表示是要从外界输入的变量,我们要从外界输入模型的顶点vVertex,模型顶点的法线vNormal

关键字uniform 表示统一值的意思,也就是该图元都使用的一些相同的属性值,如果说图元是三角形,那么就表示三角形的三个顶点使用的都是统一值定义的属性值

统一值可以从外界赋值

我们可以用函数 glGetUniformLocation GLEW_GET_FUN(__glewGetUniformLocation) 来从外界获取这个统一值的字段

比如:

GLint locColor = glGetUniformLocation(diffuseLightShader, "diffuseColor");

我们可以用函数glUniform4fv 来设置一个四维向量的字段值

比如:

GLfloat vDiffuseColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
glUniform4fv(locColor, 1, vDiffuseColor);

设置四维矩阵的方法是glUniformMatrix4fv 

设置三维矩阵的方法是glUniformMatrix3fv 


最后的smooth out vec4 vVaryingColor,表示我们会把颜色值vVaryingColor传到片段着色器里


下面来看我们的main函数

void main(void) 
    { 
		// 把顶点的法线转换到模型视图变换矩阵中
		vec3 vEyeNormal = normalMatrix * vNormal;

		// 把顶点转换到照相机坐标系
		vec4 vPosition4 = mvMatrix * vVertex;
		//去除顶点的缩放,还原为原状态
		vec3 vPosition3 = vPosition4.xyz / vPosition4.w;

		// 得到顶点到光源的方向
		vec3 vLightDir = normalize(vLightPosition - vPosition3);

		//函数dot表示 用顶点到光源的方向乘以顶点的法线,得到夹角的余弦值
		//函数max表示将得到的余弦值和0作比较,取最大的
		float diff = max(0.0, dot(vEyeNormal, vLightDir));

		// 设置顶点的颜色,用上一步得到的diff乘以原来顶点的颜色,并保持alphp不变
		vVaryingColor.rgb = diff * diffuseColor.rgb;
		vVaryingColor.a = diffuseColor.a;

		// 把顶点的投影到模型视图矩阵中
		gl_Position = mvpMatrix * vVertex;
    }


 首先一定要记得,我们自己写顶点着色器程序,那么一些顶点的位置,光照强度,颜色,矩阵空间的变换都是有我们自己控制的 
  

下面来写我们的片段着色器程序,建一个名为DiffuseLight.fp的文件,注意后缀为.fp

下面是DiffuseLight.fp中的内容

 
  
#version 130
//从顶点着色器接受的值
smooth in vec4 vVaryingColor;
out vec4 vFragColor;

void main(void)
   { 
		vFragColor = vVaryingColor;
   }


 片段着色器比较简单 首先我们要接受顶点着色器传过来的颜色值vVaryingColor,并且名义一定要一样,然后我们声明一个传入光栅化阶段的颜色值vFragColor,vFragColor只是简单的和vVaryingColor相等,我们并没有做其他的操作 
  

下面来看一下我们是怎么来用这两个文件的

我们创建一个新的OpenGL工程,添加一个.cpp源文件

首先来看一下我们需要包含的头文件和全局变量部分

#include 	
#include 
#include 
#include 
#include 
#include 
#include 

#define FREEGLUT_STATIC
#include 



GLFrame             viewFrame;
GLFrustum           viewFrustum;
GLTriangleBatch     sphereBatch;
GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;
GLGeometryTransform transformPipeline;
GLShaderManager     shaderManager;

GLuint	diffuseLightShader;	
GLint	diffuseColor;
GLint	vLightPosition;
GLint	mvpMatrix;
GLint	mvMatrix;
GLint	normalMatrix;

我们可以看到最后五个参数和我们顶点着色器中的创建的5个统一值uniform参数是一样的

下面是主函数main,和之前的代码一样

int main(int argc, char* argv[])
    {

		//设置工作路径
		gltSetWorkingDirectory(argv[0]);
		//初始化glut
		glutInit(&argc, argv);
		//申请一个带有双缓冲区,颜色缓冲区的窗口
		glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
		//窗口大小
		glutInitWindowSize(800, 600);
		//窗口名字
		glutCreateWindow("GLSL");
		//窗口大小改变时的回调函数
		glutReshapeFunc(ChangeSize);
		//键盘按键响应函数
		glutSpecialFunc(SpecialKeys);
		//渲染的回调函数
		glutDisplayFunc(RenderScene);

		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 nWidth, int nHeight)
    {
		//设置视口大小
		glViewport(0, 0, nWidth, nHeight);
		//将视图变换矩阵 和 模型 变换矩阵统一管理起来
		transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
		//设置视口变换矩阵
		viewFrustum.SetPerspective(35.0f, float(nWidth) / float(nHeight), 1.0f, 100.0f);
		//设置模型变换矩阵
		projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
	}


下面是初始化函数SetupRC

我们可以用方法GLuint LoadShaderPairWithAttributes(const char *szVertexProgFileName, const char *szFragmentProgFileName, ...);

来加载我们自己写的着色器文件

void SetupRC(void)
	{
		glClearColor(0.3f, 0.3f, 0.3f, 1.0f );

		glEnable(GL_DEPTH_TEST);
		glEnable(GL_CULL_FACE);

		shaderManager.InitializeStockShaders();
		viewFrame.MoveForward(4.0f);

		gltMakeSphere(sphereBatch, 1.0f, 26, 13);

		//加载着色器,并设置需要传入着色器中的属性字段名
		diffuseLightShader = shaderManager.LoadShaderPairWithAttributes("DiffuseLight.vp", "DiffuseLight.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex",
				GLT_ATTRIBUTE_NORMAL, "vNormal");
		//得到顶点着色器中漫反射光颜色diffuseColor的位置引用
		diffuseColor = glGetUniformLocation(diffuseLightShader, "diffuseColor");
		//得到顶点着色器中光源vLightPosition位置的位置引用
		vLightPosition = glGetUniformLocation(diffuseLightShader, "vLightPosition");
		//的到顶点着色器中模型视图矩阵mvpMatrix的位置引用
		mvpMatrix = glGetUniformLocation(diffuseLightShader, "mvpMatrix");
		//得到顶点着色器中视图变换矩阵mvMatrix的位置引用
		mvMatrix = glGetUniformLocation(diffuseLightShader, "mvMatrix");
		//得到顶点着色器中模型视图矩阵normalMatrix的位置引用
		normalMatrix = glGetUniformLocation(diffuseLightShader, "normalMatrix");
	}

下面是渲染函数RenderScene

我们可以使用函数glUseProgram 来使用着色器,其中参数是函数LoadShaderPairWithAttributes的返回值

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 vDiffuseColor[] = { 0.0f, 0.0f, 1.0f, 1.0f };
		//使用着色器
		glUseProgram(diffuseLightShader);
		//设置顶点着色器中的漫反射光diffuseColor的颜色值
		glUniform4fv(diffuseColor, 1, vDiffuseColor);
		//设置顶点着色器中的光源位置vLightPosition的值
		glUniform3fv(vLightPosition, 1, vEyeLight);
		//设置顶点着色器中的模型视图矩阵mvpMatrix值
		glUniformMatrix4fv(mvpMatrix, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
		//设置顶点着色器中的视图面环矩阵值mvMatrix
		glUniformMatrix4fv(mvMatrix, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
		//设置顶点着色器中的模型视图矩阵法线矩阵normalMatrix值
		glUniformMatrix3fv(normalMatrix, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
		//绘制模型
		sphereBatch.Draw();

		modelViewMatrix.PopMatrix();

		glutSwapBuffers();
		glutPostRedisplay();
	}



























你可能感兴趣的:(OpenGL)