在上一节CubeMap的基础上新增了一个纹理贴图实现多重纹理。

// MultiTexture.cpp
// OpenGL SuperBible
// Demonstrates applying a cube map to an object (sphere)
// simultaneously with a "tarnish" texture.
// Program by Richard S. Wright Jr.#include // OpenGL toolkit
#include #include #include #include #include #include #include #ifdef __APPLE__ #include #else #define FREEGLUT_STATIC #include #endif GLFrame viewFrame; GLFrustum viewFrustum; GLTriangleBatch sphereBatch; GLBatch cubeBatch; GLMatrixStack modelViewMatrix; GLMatrixStack projectionMatrix; GLGeometryTransform transformPipeline; GLuint cubeTexture; GLuint tarnishTexture; GLint reflectionShader; GLint skyBoxShader; GLint locMVPReflect, locMVReflect, locNormalReflect, locInvertedCamera; GLint locCubeMap, locTarnishMap; 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); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Load the tarnish texture glGenTextures(1, &tarnishTexture); glBindTexture(GL_TEXTURE_2D, tarnishTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); pBytes = gltReadTGABits("tarnish.tga", &iWidth, &iHeight, &iComponents, &eFormat); glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); free(pBytes); glGenerateMipmap(GL_TEXTURE_2D); // Load the cube map 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); // 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", 3, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords"); locMVPReflect = glGetUniformLocation(reflectionShader, "mvpMatrix"); locMVReflect = glGetUniformLocation(reflectionShader, "mvMatrix"); locNormalReflect = glGetUniformLocation(reflectionShader, "normalMatrix"); locInvertedCamera = glGetUniformLocation(reflectionShader, "mInverseCamera"); locCubeMap = glGetUniformLocation(reflectionShader, "cubeMap"); locTarnishMap = glGetUniformLocation(reflectionShader, "tarnishMap"); skyBoxShader = gltLoadShaderPairWithAttributes("SkyBox.vp", "SkyBox.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_NORMAL, "vNormal"); locMVPSkyBox = glGetUniformLocation(skyBoxShader, "mvpMatrix"); // Set textures to their texture units glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tarnishTexture); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture); } 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); glUniform1i(locCubeMap, 0); glUniform1i(locTarnishMap, 1); 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 MultiTexture"); 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; } // Reflection Shader // Vertex Shader // Richard S. Wright Jr. // OpenGL SuperBible #version 130 // Incoming per vertex... position and normal in vec4 vVertex; in vec3 vNormal; in vec2 vTexCoords; uniform mat4 mvpMatrix; uniform mat4 mvMatrix; uniform mat3 normalMatrix; uniform mat4 mInverseCamera; // Texture coordinate to fragment program smooth out vec3 vVaryingTexCoord; smooth out vec2 vTarnishCoords; 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); vTarnishCoords = vTexCoords.st; // 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; varying vec3 vVaryingTexCoord; void main(void) { vFragColor = texture(cubeMap, vVaryingTexCoord); } // Reflection Shader // Fragment Shader // Richard S. Wright Jr. // OpenGL SuperBible #version 130 out vec4 vFragColor; uniform samplerCube cubeMap; uniform sampler2D tarnishMap; smooth in vec3 vVaryingTexCoord; smooth in vec2 vTarnishCoords; void main(void) { vFragColor = texture(cubeMap, vVaryingTexCoord.stp); vFragColor *= texture(tarnishMap, vTarnishCoords); } // 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 varying 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; } 

一、多重纹理基础

在之前的学习的纹理贴图都是将一个单独的纹理加载到纹理对象上。当我们要使用这个纹理时,将他绑定到选定的纹理纹理对象上,然后将片段着色器的单个统一值设置为0。为什么是0呢?因为0是我们将要绑定到纹理单元的索引。OpenGL允许我们将独立的纹理对象绑定到一些可用的纹理单元上,从而提供了将两个或更多纹理同时应用到几何图形。可以对实现进行查询,来查看支持的纹理单元数量。如下:
GLint iUnits;
glGenIntegerv(GL_MAX_TEXTURE_UNITS,&Units);

默认情况下,第一个纹理单元为活动的纹理单元。所有纹理绑定操作都会影响当前活动的纹理单元。我们可以通过调用以纹理单元标识为变量的glActiveTexture来改变当前纹理单元。例如,要切换到第二个纹理单元并将它绑定到指定纹理对象上:

glActiveTexture(GL_TEXTURE1);

glBindTexture(GL_TEXTURE_2D,textureID);

二、多重纹理坐标

有两个函数可以提供纹理坐标。

1、CopyTexCoordData2f,它的速度是最快的,因为它会一次复制整个一组纹理坐标。

2、使用较慢的每次一个顶点的接口,与立即模式类似。可以通过两种方式指定一个二维纹理坐标,每次指定一个。

此次的源码是在上次学习的源码基础上新增了多重纹理的应用,所以只着重解析多重纹理部分源码。

三、Client程序解析

MultiTexture.cpp

1、全局变量

//声明两个纹理对象标识,对应着色器程序的统一值

GLint locCubeMap, locTarnishMap;

2、函数解析

1)void SetupRC()

.....

//生成纹理对象

glGenTextures(1, &tarnishTexture);

//绑定纹理对象
glBindTexture(GL_TEXTURE_2D, tarnishTexture);

//设置纹理对象的过滤和环绕模式
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

//加载纹理贴图,指定宽、高、新的缓冲区和文件格式

pBytes = gltReadTGABits("tarnish.tga", &iWidth, &iHeight, &iComponents, &eFormat);

//从缓冲区载入纹理数据,一旦载入,纹理就会成为当前纹理状态(即活动的)

glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes);

//释放内存

free(pBytes);

//生成Mip贴图层

glGenerateMipmap(GL_TEXTURE_2D);

...............

//得到着色器程序中的两个贴图的统一值,赋值给纹理对象标识

 locCubeMap = glGetUniformLocation(reflectionShader, "cubeMap");
locTarnishMap = glGetUniformLocation(reflectionShader, "tarnishMap");

.............

//切换纹理单元。将两个纹理进行绑定,每个纹理都会绑定到自己的纹理单元上

glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tarnishTexture);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, cubeTexture);

2)void RenderScene(void)

.........

//设置着色器程序纹理对象的统一值

glUniform1i(locCubeMap, 0);
glUniform1i(locTarnishMap, 1);

注:多重纹理的源码是在上一节的源码基础上新添,所以略去了全部的解析。可回顾上一节。下面着重解析着色器程序。

四、着色器程序解析

与CubeMap的源码基本一致,这里解析一下新增的代码。

Reflection.vp

 // 设置第二个纹理的纹理坐标

in vec2 vTexCoords;

vTarnishCoords = vTexCoords.st; 

Reflection.fp

//采样器,将要采样的纹理所绑定的纹理单元

uniform sampler2D   tarnishMap;

//设置输出颜色:立方体纹理采样得到的颜色再乘等于第二个纹理采样得到的颜色值

vFragColor = texture(cubeMap, vVaryingTexCoord.stp);  
    vFragColor *= texture(tarnishMap, vTarnishCoords);

五、小结

此多重纹理的源码示例是在上一节的CubeMap的示例的基础上新增了多重纹理的渲染效果。需要注意的是,在客户端程序中第二个纹理对象的生成和绑定,得到着色器程序中的纹理采样器的统一值,再进行绑定设置纹理单元,在着色器程序中,得到要进行渲染的输出颜色值。

OpenGL蓝宝书源码学习(二十三)第七章——MultiTexture多重纹理相关推荐

  1. OpenGL蓝宝书源码学习(十)第五章——纹理的应用、Mip贴图、各项异性过滤和纹理压缩基础

    一.纹理应用 1.纹理坐标 我们是通过为每个顶点指定一个纹理坐标而直接在几何图形上进行纹理贴图的.纹理坐标要么是指定为着色器的一个属性,要么通过算法计算出来.纹理贴图中的纹理单元是作为一个更加抽象的纹 ...

  2. OpenGL蓝宝书源码学习(二十)第六章——Dissolve

    侵蚀着色器渲染图元,呈现腐蚀效果的源码示例. // Dissolve.cpp // OpenGL SuperBible // Demonstrates discard fragment command ...

  3. OpenGL蓝宝书源码学习(准备工作)

    一边看书一边整理归纳是一个非常高效的学习方法,写此博文的目的也是我学习的一种方法,闲话少说,进入正题. 一.glut,glew,gltools的简单介绍 1.GLUT 代表OpenGL实用工具,在Wi ...

  4. OpenGL蓝宝书源码学习(五)第三章——Blending.cpp

    颜色混合源码实例,此程序使用透明度来实现可以在白色背景上来回移动的半透明红色的幻觉,并且移动过程中实现了有其他色块颜色混合的效果. 此实例是在Move.cpp示例程序基础上编写的,所以这里只贴出新增的 ...

  5. 配置Visual Studio 2015+OpenGL可运行蓝宝书源码

    首先要感谢CSDN的两位博主的参考博文,http://blog.csdn.net/iceteaset/article/details/50359559    http://blog.csdn.net/ ...

  6. Tensorflow 2.x(keras)源码详解之第七章:keras中的tf.keras.layers

      大家好,我是爱编程的喵喵.双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中.从事机器学习以及相关的前后端开发工作.曾在阿里云.科大讯飞.CCF等比赛获得多次Top名次.现 ...

  7. 使用base标签后图片无法加载_Spring 源码学习(二)-默认标签解析

    `Spring` 解析默认标签~ 从上一篇笔记可以看出,在容器注册 bean 信息的时候,做了很多解析操作,而 xml 文件中包含了很多标签.属性,例如 bean . import 标签, meta ...

  8. Golang源码学习(二)----Go源码学习基础

    ### 本文源码版本为 GO 1.17.8 Windows/amd64: ### 可能参与对比的版本:GO 1.16.2 Linux/amd64一.Golang的编译器究竟是如何工作的? (学习源码有 ...

  9. SocketServer源码学习(二)

    SocketServer 中非常重要的两个基类就是:BaseServer 和 BaseRequestHandler 在SocketServer 中也提供了对TCP以及UDP的高级封装,这次我们主要通过 ...

最新文章

  1. JAVA中文注解驱动,解决api接口返回的json里面出现中文乱码的问题
  2. git最佳实践_Git最佳实践如何为我节省大量的返工时间
  3. CodeForces - 1529F It‘s a bird! No, it‘s a plane! No, it‘s AaParsa!(最短路+思维建图)
  4. oracle体系结构和组件图示,Oracle 体系结构组件
  5. SQL - 通过某个字段名称找到数据库中对应的表
  6. Mac OSX 平台安装 MongoDB
  7. 多项式拟合怎么确定次数_PyTorch入门4 搭建多项式回归模型
  8. linux内核版本2 3 20,redhat9装配RTLINUX-3.2,内核版本为Kernel-2.4.23
  9. ToStringBuilder.reflectionToString
  10. 调查:2013年十大急需的热门IT技能
  11. 如何解决卸载McAfee时出现“处于托管模式时无法删除”问题(转)
  12. 成长笔记之博客统计第一篇
  13. 30m服务器可以用多少人在线,30m网速(30m宽带够几个人用)
  14. 次坐标从0开始_三坐标测量机安全使用+量块校准操作规程
  15. 支付宝app登录授权的infoStr授权登录流程
  16. 生存模型的calibration需要注意的一个问题
  17. 一年中最后一个月的最后一天说说_2020只剩最后一个月的励志说说致自己
  18. 24点游戏 计算机编程,关于24点游戏的编程思路与基本算法
  19. 计算机基础(笔记)——计算机网络(计算机网络中的安全)
  20. 视频文件太大如何压缩变小?

热门文章

  1. 小新开机出现,由于启动计算机时出现了页面配置问题,Windows在你的计算机上创建了一个临时页面文件。
  2. 网易云音乐是怎么做曲库缓存的?设计动机大揭秘!
  3. 什么是方法?方法的定义
  4. 计算机基础及msoffice应用一级教程,全国计算机等级考试一级教程——计算机基础及MS Office应用(2013年版)...
  5. Transformer40~
  6. 模板引擎art-template应用 案例 ---- 学生档案管理
  7. percona-xtrabackup备份示例完全备份和增量备份
  8. oracle历史库架构,oracle体系结构
  9. linux内存木马,警惕更多 Linux木马的到来
  10. Android第三方登陆之QQ篇(原生登陆授权)