OpenGL ADSGouraud着色

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 vec3	vLightPosition;
//模型视图变换矩阵
uniform mat4	mvpMatrix;
//视图变换矩阵
uniform mat4	mvMatrix;
//模型视图变换矩阵法线矩阵
uniform mat3	normalMatrix;

// 需要传入到片段着色器的参数
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;

GLuint	ADSLightShader;		// 
GLint	locAmbient;			// 环境光在顶点着色器中的字段位置的引用
GLint   locDiffuse;			// 漫反射光在顶点着色器中的字段位置的引用
GLint   locSpecular;		// 镜面光在顶点着色器中的字段位置的引用
GLint	locLight;			// 光源位置在顶点着色器中的字段位置的引用
GLint	locMVP;				// 模型视图变换矩阵在顶点着色器中的字段位置的引用
GLint	locMV;				// 视图变换矩阵在顶点着色器中的字段位置的引用
GLint	locNM;				// 模型视图变换矩阵的法线矩阵在顶点着色器中的字段位置的引用

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

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
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值