OpenGL ADSGouraud着色

来源:互联网 发布:boss 弹道优化瞄准镜 编辑:程序博客网 时间:2024/05/21 15:49

ADS代表环境光(Ambient),漫射光(Diffuse)和镜面光(Specular).我们可以用当前物体的材质对这三种光的反射量来决定物体的最终颜色值

环境光的计算公式是 物体的材质*环境光的值

uniform vec3 vAmbientMaterial;

uniform vec3 vAmbientLight;

vrc3 vAmbientColor = vAmbientMaterial * vAmbientLight;


漫射光的计算公式是 物体的材质*漫射光的值*(表面法线*光照向量)

uniform vec3 vDiffuseMaterial;

uniform vec3 vDiffuseLight;

float fDotProduct = max(0,0,dot(vNormal,vLightDir));

vec3 vDiffuseColor = vDiffuseMaterial*vDiffuseLight*fDotProduct ;


镜面光的计算公式是物体的材质*镜面光的值*反光强度

反光强度的计算公式是 (原来顶点到光的方向向量的反方向*法线)*n次幂,一般n=128

uniform vec3 vSpecularMaterial;

uniform vec3 vSpecularLight;

float shininess = 128.0;

vec3 vReflection = reflect(-vLightDir,vEyeNormal);

float EyeReflectionAngle = max(0.0,dot(vEyeNormal,vReflection ));

fSpec = pow(EyeReflectionAngle ,shininess );

vec3 vSpecularColor = vSpecularLight * vSpecularLight * fSpec ;


我们来看一下这节要实现的例子

如图:




我们会创建一个自身会旋转的小球,并且光源在其左上角,我们会发现小球左上角会有亮光,在例子中我们暂时不考虑材质。


下面是顶点着色器ADSGouraud.vp的全部代码,每一行都有注释

#version 130//需要从外界传入的参数//顶点in vec4 vVertex;//顶点法线in vec3 vNormal;// 需要在外界设置的参数//环境光颜色值uniform vec4    ambientColor;//漫射光颜色值uniform vec4    diffuseColor;//镜面光颜色值uniform vec4    specularColor;//光源位置uniform vec3vLightPosition;//模型视图变换矩阵uniform mat4mvpMatrix;//视图变换矩阵uniform mat4mvMatrix;//模型视图变换矩阵法线矩阵uniform mat3normalMatrix;// 需要传入到片段着色器的参数smooth out vec4 vVaryingColor;void main(void)     { // 把顶点发现变换到照相机坐标系中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;// 加上环境光vVaryingColor += ambientColor;// 加上镜面光vec3 vReflection = normalize(reflect(-vLightDir, vEyeNormal));float spec = max(0.0, dot(vEyeNormal, vReflection));if(diff != 0) {float fSpec = pow(spec, 128.0);vVaryingColor.rgb += vec3(fSpec, fSpec, fSpec);}//把顶点变换到照相机坐标系中gl_Position = mvpMatrix * vVertex;    }

下面是片段着色器ADSGouraud.fp的全部代码,同样都有注释

// 需要的OpenGL最低版本 #version 130//输出到光栅化的参数out vec4 vFragColor;//从顶点着色器传入的参数smooth in vec4 vVaryingColor;void main(void)   { //把从顶点着色器传入的参数赋值给需要传出到光栅化阶段的参数vFragColor = vVaryingColor;   }


下面我们来看看怎么使用这两个着色器文件

我们首先建一个新的OpenGL的工程,然后添加一个ADSGouraud.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;GLuintADSLightShader;// GLintlocAmbient;// 环境光在顶点着色器中的字段位置的引用GLint   locDiffuse;// 漫反射光在顶点着色器中的字段位置的引用GLint   locSpecular;// 镜面光在顶点着色器中的字段位置的引用GLintlocLight;// 光源位置在顶点着色器中的字段位置的引用GLintlocMVP;// 模型视图变换矩阵在顶点着色器中的字段位置的引用GLintlocMV;// 视图变换矩阵在顶点着色器中的字段位置的引用GLintlocNM;// 模型视图变换矩阵的法线矩阵在顶点着色器中的字段位置的引用

然后是主函数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

void SetupRC(void){glClearColor(0.0f, 0.0f, 0.0f, 1.0f );glEnable(GL_DEPTH_TEST);glEnable(GL_CULL_FACE);shaderManager.InitializeStockShaders();viewFrame.MoveForward(4.0f);gltMakeSphere(sphereBatch, 1.0f, 26, 13);//加载着色器文件,并设置需要传入的变量ADSLightShader = shaderManager.LoadShaderPairWithAttributes("ADSGouraud.vp", "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");}


下面是渲染函数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.0f, 0.0f, 1.0f, 1.0f };//镜面光的颜色GLfloat vSpecularColor[] = { 1.0f, 1.0f, 1.0f, 1.0f };//使用着色器glUseProgram(ADSLightShader);//为着色器中相应的统一值uniform字段赋值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();}











0 0
原创粉丝点击