OpenGL 创建反射

这一节我们实现下图中的效果





要实现这个效果非常简单,我们只需要在上一节 天空盒的代码中增加点东西即可

在现实生活中,我们从上图小球中看到的景象实际是光线通过小球的反射,进入我们的眼睛肿才能看到的

我们会通过自己的写的反射着色器Reflection.vp 来获取这个反射的向量,这个向量就可以作为小球的纹理坐标,小球的纹理任然使用天空盒的纹理图

另外我们的程序支持按住键盘上的方向键在地图上行走,假如我们的照相机向左旋转了,在我们的小球中的景象应该向右旋转

所以我们应该得到照相机旋转矩阵的反向旋转矩阵,我们用反向旋转矩阵和反射向量相称,把结果作为小球的纹理坐标

可以使用方法 m3dInvertMatrix44(M3DMatrix44f mInverse, const M3DMatrix44f m) 得到矩阵的反向矩阵


这一节的程序实在上一节天空盒的基础上实现的

下面是反射顶点着色器Reflection.vp中的代码

// 需要OpenGL 最低版本为1.3
#version 130

// 需要从外界输入的值
//顶点
in vec4 vVertex;
//法线
in vec3 vNormal;
//需要从外界设置的uniform值
uniform mat4   mvpMatrix;
uniform mat4   mvMatrix;
uniform mat3   normalMatrix;
uniform mat4   mInverseCamera;

//需要传入到片段着色器中的纹理坐标
smooth out vec3 vVaryingTexCoord;

void main(void) 
    {
		// 照相机空间中的顶点法线
		vec3 vEyeNormal = normalMatrix * vNormal;
		
		// 照相机空间中的顶点位置
		vec4 vVert4 = mvMatrix * vVertex;
		vec3 vEyeVertex = normalize(vVert4.xyz / vVert4.w);
		
		// 得到顶点的反射向量
		vec4 vCoords = vec4(reflect(vEyeVertex, vEyeNormal), 1.0);
	   
		// 通过反转的照相机进行旋转
		vCoords = mInverseCamera * vCoords;
		vVaryingTexCoord.xyz = normalize(vCoords.xyz);

		// 将顶点变换到照相机坐标系下
		gl_Position = mvpMatrix * vVertex;
    }

下面是反射片段着色器Reflection.fp中的代码

// 需要OpenGL 最低版本为1.3
#version 130

out vec4 vFragColor;

uniform samplerCube cubeMap;
//纹理坐标
smooth in vec3 vVaryingTexCoord;

void main(void)
    { 
		vFragColor = texture(cubeMap, vVaryingTexCoord);
    }

下面我们只列出和上一节天空盒代码不一样的地方

首先是全局变量部分增加了如下代码

GLint               reflectionShader;
GLint               locMVPReflect, locMVReflect, locNormalReflect, locInvertedCamera;

然后是初始化函数SetupRC

void SetupRC()
    {
		GLbyte *pBytes;
		GLint iWidth, iHeight, iComponents;
		GLenum eFormat;
		int i;
       
		// 禁用多边形背面上的光照、阴影和颜色计算及操作
		glCullFace(GL_BACK);
		//GL_CCW 表示窗口坐标上投影多边形的顶点顺序为逆时针方向的表面为正面
		glFrontFace(GL_CCW);
		//开启深度测试
		glEnable(GL_DEPTH_TEST);
        <span style="white-space:pre">	</span>//创建纹理对象
		glGenTextures(1, &cubeTexture);
		//绑定纹理对象
		glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);
        
		//设置纹理过滤模式    
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
		//设置纹理渲染模式
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);   
		//设置数据内存对齐方式
		glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  
		//加载纹理图片
		for(i = 0; i < 6; i++)
			{        
				pBytes = gltReadTGABits(szCubeFaces[i], &iWidth, &iHeight, &iComponents, &eFormat);
				glTexImage2D(cube[i], 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
				free(pBytes);
			}
		//开启mip贴图模式
		glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
    
		viewFrame.MoveForward(-4.0f);
		//初始化小球模型数据
		gltMakeSphere(sphereBatch, 1.0f, 52, 26);
		//初始化立方体模型的数据,这个立方体就是用来贴6张天空的纹理图片的,从而形成天空盒
		gltMakeCube(cubeBatch, 20.0f);
    
		reflectionShader = gltLoadShaderPairWithAttributes("Reflection.vp", "Reflection.fp", 2, 
													GLT_ATTRIBUTE_VERTEX, "vVertex",
													GLT_ATTRIBUTE_NORMAL, "vNormal");
                                                
		locMVPReflect = glGetUniformLocation(reflectionShader, "mvpMatrix");
		locMVReflect = glGetUniformLocation(reflectionShader, "mvMatrix");
		locNormalReflect = glGetUniformLocation(reflectionShader, "normalMatrix");
		locInvertedCamera = glGetUniformLocation(reflectionShader, "mInverseCamera");
                                                
       <span style="white-space:pre">		</span> //加载自己写的天空盒的着色器                                        
		skyBoxShader = gltLoadShaderPairWithAttributes("SkyBox.vp", "SkyBox.fp", 2, 
													GLT_ATTRIBUTE_VERTEX, "vVertex",
													GLT_ATTRIBUTE_NORMAL, "vNormal");

		locMVPSkyBox = glGetUniformLocation(skyBoxShader, "mvpMatrix");

    }


然后是渲染函数RenderScene

void RenderScene(void)
    {
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
		M3DMatrix44f mCamera;
		M3DMatrix44f mCameraRotOnly;
		M3DMatrix44f mInverseCamera;
    
		viewFrame.GetCameraMatrix(mCamera, false);
		viewFrame.GetCameraMatrix(mCameraRotOnly, true);
		m3dInvertMatrix44(mInverseCamera, mCameraRotOnly);

		modelViewMatrix.PushMatrix();    
		modelViewMatrix.MultMatrix(mCamera);
		//使用自己写的着色器
		glUseProgram(reflectionShader);
		//设置着色器uniform值
		glUniformMatrix4fv(locMVPReflect, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
		glUniformMatrix4fv(locMVReflect, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
		glUniformMatrix3fv(locNormalReflect, 1, GL_FALSE, transformPipeline.GetNormalMatrix());
		glUniformMatrix4fv(locInvertedCamera, 1, GL_FALSE, mInverseCamera);

		glEnable(GL_CULL_FACE);
		sphereBatch.Draw();
		glDisable(GL_CULL_FACE);
		modelViewMatrix.PopMatrix(); 

		modelViewMatrix.PushMatrix();
		modelViewMatrix.MultMatrix(mCamera);
		//使用自己写的着色器
		glUseProgram(skyBoxShader);
		//设置着色器uniform值
		glUniformMatrix4fv(locMVPSkyBox, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
		//绘制模型
		cubeBatch.Draw();       
		modelViewMatrix.PopMatrix();
		glutSwapBuffers();
    }

其他的代码都和上一节天空盒的代码一样







  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值