【OpenGL】立方体贴图——Cubemap天空盒案例_opengl球体贴图-程序员宅基地

技术标签: # OpenGL案例  

核心内容:
gltMakeCube(cubeBatch, 20.0); //创建一个半径为20个单位长度的立方体批次数据填充到cubeBatch (GLBatch对象)
该函数会将2D纹理坐标分配到GLT_ATTRIBUTE_TEXTURE0属性槽,但我们需要的并不是2D纹理坐标,而是3D纹理坐标。

3D纹理坐标获取方法是在顶点着色器里直接将归一化的顶点坐标作为输出到片段着色器,此时片段着色器插值得到的顶点坐标就是三维纹理坐标了,接着在片段着色器使用texture(samplerCube纹理对象, 三维纹理坐标);采样得到颜色作为输出,下面列出所有代码:

天空盒顶点着色器:

// Skybox Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

// Incoming per vertex... just the position
in vec4 vVertex;

uniform mat4   mvpMatrix;  // Transformation matrix

// Texture Coordinate to fragment program
out vec3 vVaryingTexCoord;


void main(void) 
    {
    // Pass on the texture coordinates 
    vVaryingTexCoord = normalize(vVertex.xyz);

    // Don't forget to transform the geometry!
    gl_Position = mvpMatrix * vVertex;
    }

天空盒片段着色器:

// Skybox Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

out vec4 vFragColor;

uniform samplerCube  cubeMap;

in vec3 vVaryingTexCoord;

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

 注意:天空盒两个面之间的缝隙问题 解决方法  glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS); 即可

在GLSL代码里,需注意的是天空盒顶点着色器使用到的MVP矩阵,其中MV矩阵只有摄像机旋转矩阵生效的。

紧接着需渲染反射环境的球体解释,主要是反射球体的顶点着色器,它进行了计算出视觉空间的法线向量、视角向量,再用reflect函数获取反射向量,并进行了反向的摄像机旋转矩阵变换(即转置摄像机旋转矩阵),最后归一化反射向量传给片段着色器作为三维纹理坐标,进行采样立方体贴图输出颜色。

注意:反射向量进行了一个反向的摄像机旋转变换,书上解释说是如果不进行的话就会导致当摄像机在场景中移动时,立方体贴图将不能正确地反射围绕它的天空盒。
可亲自测试不进行这个变换,即vCoords = mInverseCamera * vCoords; 会如何,我猜测是没有影响的,因为平移摄像机不会导致摄像机旋转矩阵变化,其转置矩阵也不会变化,而产生不了任何效果,只有当旋转摄像机时才会出现问题,可能作者是想球体反射环境是绝对不变化的吧,例如:摄像机旋转时,球体反射的景象依然是一样的,这就需要进行一个反向旋转来保持一致了。

// Reflection Shader
// Vertex Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

// Incoming per vertex... position and normal
in vec4 vVertex;
in vec3 vNormal;

uniform mat4   mvpMatrix;
uniform mat4   mvMatrix;
uniform mat3   normalMatrix;
uniform mat4   mInverseCamera;

// Texture coordinate to fragment program
smooth out vec3 vVaryingTexCoord;

void main(void) 
    {
    // Normal in Eye Space
    vec3 vEyeNormal = normalMatrix * vNormal;
    
    // Vertex position in Eye Space
    vec4 vVert4 = mvMatrix * vVertex;
    vec3 vEyeVertex = normalize(vVert4.xyz / vVert4.w);
    
    // Get reflected vector
    vec4 vCoords = vec4(reflect(vEyeVertex, vEyeNormal), 1.0);
   
    // Rotate by flipped camera
    vCoords = mInverseCamera * vCoords;
    vVaryingTexCoord.xyz = normalize(vCoords.xyz);

    // Don't forget to transform the geometry!
    gl_Position = mvpMatrix * vVertex;
    }

 反射球体的片段着色器:

// Reflection Shader
// Fragment Shader
// Richard S. Wright Jr.
// OpenGL SuperBible
#version 130

out vec4 vFragColor;

uniform samplerCube cubeMap;
smooth in vec3 vVaryingTexCoord;

void main(void)
    { 
    vFragColor = texture(cubeMap, vVaryingTexCoord.stp);
    }
    
// CubeMapped.cpp
// OpenGL SuperBible
// Demonstrates applying a cube map to an object (sphere) using
// and using the same map for the skybox.
// Program by Richard S. Wright Jr.
#pragma comment(lib,"gltools.lib")
#include <GLTools.h>	// OpenGL toolkit
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLGeometryTransform.h>
#include <StopWatch.h>

#include <math.h>
#include <stdlib.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif


GLFrame             viewFrame;
GLFrustum           viewFrustum;
GLTriangleBatch     sphereBatch;
GLBatch             cubeBatch;
GLMatrixStack       modelViewMatrix;
GLMatrixStack       projectionMatrix;
GLGeometryTransform transformPipeline;
GLuint              cubeTexture;
GLint               reflectionShader;
GLint               skyBoxShader;

GLint               locMVPReflect, locMVReflect, locNormalReflect, locInvertedCamera;
GLint				locMVPSkyBox;


// Six sides of a cube map
const char *szCubeFaces[6] = { "pos_x.tga", "neg_x.tga", "pos_y.tga", "neg_y.tga", "pos_z.tga", "neg_z.tga" };

GLenum  cube[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X,
					 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
					 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
					 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
					 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
					 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z };


//
// This function does any needed initialization on the rendering
// context. 
void SetupRC()
{
	GLbyte *pBytes;
	GLint iWidth, iHeight, iComponents;
	GLenum eFormat;
	int i;

	// Cull backs of polygons
	glCullFace(GL_BACK);
	glFrontFace(GL_CCW);
	glEnable(GL_DEPTH_TEST);

	glGenTextures(1, &cubeTexture);
	glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);

	// Set up texture maps        
	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);


	// Load Cube Map images
	for (i = 0; i < 6; i++)
	{
		// Load this texture map
		pBytes = gltReadTGABits(szCubeFaces[i], &iWidth, &iHeight, &iComponents, &eFormat);
		glTexImage2D(cube[i], 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);
		free(pBytes);
	}
	glGenerateMipmap(GL_TEXTURE_CUBE_MAP);

	viewFrame.MoveForward(-4.0f);
	gltMakeSphere(sphereBatch, 1.0f, 52, 26);
	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");


	skyBoxShader = gltLoadShaderPairWithAttributes("SkyBox.vp", "SkyBox.fp", 2,
		GLT_ATTRIBUTE_VERTEX, "vVertex",
		GLT_ATTRIBUTE_NORMAL, "vNormal");

	locMVPSkyBox = glGetUniformLocation(skyBoxShader, "mvpMatrix");


}

void ShutdownRC(void)
{
	glDeleteTextures(1, &cubeTexture);
}


// Called to draw scene
void RenderScene(void)
{
	// Clear the window
	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();
	// Draw the sphere
	modelViewMatrix.MultMatrix(mCamera);
	glUseProgram(reflectionShader);
	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(mCameraRotOnly);
	glUseProgram(skyBoxShader);
	glUniformMatrix4fv(locMVPSkyBox, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
	cubeBatch.Draw();
	modelViewMatrix.PopMatrix();

	// Do the buffer Swap
	glutSwapBuffers();
}



// Respond to arrow keys by moving the camera frame of reference
void SpecialKeys(int key, int x, int y)
{
	if (key == GLUT_KEY_UP)
		viewFrame.MoveForward(0.1f);

	if (key == GLUT_KEY_DOWN)
		viewFrame.MoveForward(-0.1f);

	if (key == GLUT_KEY_LEFT)
		viewFrame.RotateLocalY(0.1);

	if (key == GLUT_KEY_RIGHT)
		viewFrame.RotateLocalY(-0.1);

	// Refresh the Window
	glutPostRedisplay();
}


void ChangeSize(int w, int h)
{
	// Prevent a divide by zero
	if (h == 0)
		h = 1;

	// Set Viewport to window dimensions
	glViewport(0, 0, w, h);

	viewFrustum.SetPerspective(35.0f, float(w) / float(h), 1.0f, 1000.0f);

	projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
	transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

int main(int argc, char* argv[])
{
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(800, 600);
	glutCreateWindow("OpenGL Cube Maps");
	glutReshapeFunc(ChangeSize);
	glutDisplayFunc(RenderScene);
	glutSpecialFunc(SpecialKeys);

	GLenum err = glewInit();
	if (GLEW_OK != err) {
		fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
		return 1;
	}


	SetupRC();

	glutMainLoop();

	ShutdownRC();

	return 0;
}

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_39574690/article/details/115499082

智能推荐

大数据毕设分享(含算法) 机器学习二手房价格预测及可视化系统(源码+论文)_数据挖掘二手房价预测-程序员宅基地

文章浏览阅读850次,点赞23次,收藏24次。​ 通过整个项目的实践,我们亲身体会了数据挖掘的那张路线图,预处理、分析之后发现问题(Knowledge),再进行新的处理,再重新分析挖掘,做评估,然后发现新的问题,再从头开始,在这几个过程的循环往复中完成了整个项目。_数据挖掘二手房价预测

input框 下面 紧跟着div弹出层,js取top left数值[实例]_input触发弹出层-程序员宅基地

文章浏览阅读3.6k次。var setSearchFlag; function showSearch(obj){ clearSearchFlag(); var w3c=(document.getElementById)? true:false;//w3c 标准 var ns6=(w3c && (navigator.appName=="Netscape"))? true: false;//Netsca_input触发弹出层

K折交叉验证(StratifiedKFold与KFold比较)_四折交叉验证-程序员宅基地

文章浏览阅读5.6k次,点赞7次,收藏63次。文章目录一、交叉验证二、K折交叉验证KFold()方法StratifiedKFold()方法一、交叉验证交叉验证的基本思想是把在某种意义下将原始数据(dataset)进行分组,一部分做为训练集(train set),另一部分做为验证集(validation set or test set),首先用训练集对分类器进行训练,再利用验证集来测试训练得到的模型(model),以此来做为评价分类器的性能指标。–来自百科二、K折交叉验证KFold()方法KFold(): KFold 将所有的样例划分为 _四折交叉验证

怎么让联想计算机升级,如何刷bios,教您联想电脑如何刷bios-程序员宅基地

文章浏览阅读9k次。我们都知道刷bios的时候,在整个升级过程中都需要谨慎,不然很容易搞坏主板,就会得不偿失,那么如果使用联想电脑的用户该怎么去刷bios呢?虽然使用联想的用户很多,但是会的没几个,下面,小编就来跟大家讲讲联想电脑如何刷bios。刷bios有什么用?这是一些用户都想要知道了,其实我们的电脑想要增加新的选项,就像软件更新一样增加功能,那么该怎么去刷bios呢?很多的用户都不知道该怎么去操作呢?下面,小编..._联想主板刷bios教程

DWM之创建窗口_获取dwm窗口-程序员宅基地

文章浏览阅读996次。Win7与Xp,直观上最大的区别便是界面上的改变了,win7拥有着华丽的玻璃界面.今天就写一下关于这方面的文章.毫无疑问,一切都是微软提供,以下一切内容参考于MSDN中http://msdn.microsoft.com/en-us/library/windows/desktop/aa969540(v=vs.85).aspx这篇文章.先给出代码.再做解释: 1 .3_获取dwm窗口

p2p网贷平台设计简析-程序员宅基地

文章浏览阅读308次。以我之前主持开发的一个商业产品:p2p网贷为例进行分析。整个的概况,可以参见:www.huixinp2p.com(目的只会技术交流)界面可以直接参考前期博客:http://www.cnblogs.com/shenliang123/p/3435427.html其中涉及到的部分web安全的解决可以参考最新博客:http://www.cnblogs.com/shenliang123/p/3835..._p2p网贷系统平台设计简析

随便推点

自定义View-Rect和RectF_android根据rect坐标添加控件-程序员宅基地

文章浏览阅读1.4k次。Rect 类定义了一个矩形结构,同样实现了 Parcelable 序列化接口。Rect 类定义了 left、top、right、bottom 四个成员变量,我们需要正确理解这 4 个成员变量的作用:left:矩形左边线条离 y 轴的距离top:矩形上面线条离 x 轴的距离right:矩形右边线条离 y 轴的距离bottom:矩形底部线条离 x 轴的距离矩形是一种非常常见的图_android根据rect坐标添加控件

CCS5导入工程时出错:Issues that may require your attention were encountered while importing the projects-程序员宅基地

文章浏览阅读2.4w次,点赞10次,收藏27次。1.出错CCS5.5.0导入工程(Import CCS Eclispse Project)时出错:Issues that may require your attention were encountered while importing the projects ,如下图:2.原因是由于文件夹名(例如f28335_Sci_Update_Flash_first)和文件夹中的工程名

Android4.0 Toast显示问题分析_安卓4.0不支持uni.showtoast-程序员宅基地

文章浏览阅读8.9k次,点赞3次,收藏4次。在修复RUI桌面在4.0系统下的提示信息不完善的Bug过程的一些思路与大家分享一下。Bug描述:RUI在2.2的系统点击推荐图标下载后,就会进入下载队列中下载,如果再次点击相同的图标就会使用Toast提示“**已经在下载队列中”。但是在4.0的系统就会出现异常,第二次点击相同的推荐图标时没有出现Toast提示。相关源码:public static void showMe_安卓4.0不支持uni.showtoast

服务器无法与DeviceNetBT_Tcpip_{670E1543-79C1-485C-9B4B-835CE3BA37B3}传输相绑定-程序员宅基地

文章浏览阅读3.3k次。在运行 Windows Server 2003 的计算机上,您可以根据需要对所选的客户端关闭 TCP/IP 上的 NetBIOS (NetBT)。如果您希望只使用 DNS 在一台指定计算机(该计算机用于您网络中的专门角色或安全角色)上提供名称注册和解析,则您可以选择为该计算机上安装的一个或所有网络适配器关闭 NetBT 服务。配置要关闭 WINS/NetBT..._服务器无法与传输绑定,因为网络上的另一部计算机具有相同的名称。服务器无法启动

NYOJ 118 修路方案(次小生成树)-程序员宅基地

文章浏览阅读806次。修路方案时间限制:3000 ms | 内存限制:65535 KB难度:5描述南将军率领着许多部队,它们分别驻扎在N个不同的城市里,这些城市分别编号1~N,由于交通不太便利,南将军准备修路。现在已经知道哪些城市之间可以修路,如果修路,花费是多少。现在,军师小工已经找到了一种修路的方案,能够使各个城市都联通起来,而且花费最少。但是,南

【期末复习】微机原理与接口技术_己知 8254 的端口地址为 3000h、3004h3008h 和 30bh外接时钟频率为 2mh2-程序员宅基地

文章浏览阅读5w次,点赞134次,收藏961次。知识重点整理第一章 输入/输出系统1.接口电路的作用和基本功能接口电路是CPU与外设交换信息的中转站。接口电路应具备的功能为:数据缓冲功能、联络功能、寻址功能、数据转换功能、中断管理功能。2.端口的概念和分类端口是接口电路中能与CPU直接进行信息交换的寄存器,即I/O端口寄存器。在接口电路中,按端口寄存器存放信息的物理意义可划分为数据端口、控制端口和状态端口:数据端..._己知 8254 的端口地址为 3000h、3004h3008h 和 30bh外接时钟频率为 2mh2,利用 825

推荐文章

热门文章

相关标签