OpenGL GLSL

来源:互联网 发布:上海知恩服饰有限公司 编辑:程序博客网 时间:2024/05/01 16:11

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

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

如下图:



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


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

顶点着色器记录的是顶点的属性和一些对顶点的操作,顶点着色器的文件后缀为,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 vec4diffuseColor;//漫反射光的颜色值uniform vec3vLightPosition; //光源的位置uniform mat4mvpMatrix; //模型视图投影矩阵uniform mat4mvMatrix; //视图矩阵uniform mat3normalMatrix; //模型视图的法线矩阵//关键字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 <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     sphereBatch;GLMatrixStack       modelViewMatrix;GLMatrixStack       projectionMatrix;GLGeometryTransform transformPipeline;GLShaderManager     shaderManager;GLuintdiffuseLightShader;GLintdiffuseColor;GLintvLightPosition;GLintmvpMatrix;GLintmvMatrix;GLintnormalMatrix;

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

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

int main(int argc, char* argv[])    {//设置工作路径gltSetWorkingDirectory(argv[0]);//初始化glutglutInit(&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());//设置顶点着色器中的视图面环矩阵值mvMatrixglUniformMatrix4fv(mvMatrix, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());//设置顶点着色器中的模型视图矩阵法线矩阵normalMatrix值glUniformMatrix3fv(normalMatrix, 1, GL_FALSE, transformPipeline.GetNormalMatrix());//绘制模型sphereBatch.Draw();modelViewMatrix.PopMatrix();glutSwapBuffers();glutPostRedisplay();}



























0 0
原创粉丝点击