立方体纹理(cube map)

概念:

         立方体纹理是一种特殊的纹理技术,它用6幅二维纹理图像构成一个以原点为中心的纹理立方体。对于每个片段,纹理坐标(s, t, r)被当作方向向量看待,每个纹素(texel)都表示从原点所看到的纹理立方体上的图像。

指定6个面的纹理图像:

glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGBA,
 imageSize, imageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image1);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGBA,
 imageSize, imageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image4);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGBA,
 imageSize, imageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image2);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGBA,
 imageSize, imageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image5);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGBA,
 imageSize, imageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image3);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGBA,
 imageSize, imageSize, 0, GL_RGBA, GL_UNSIGNED_BYTE, image6);

 

指定立方体纹理对象的参数:

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S,
                GL_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T,
                GL_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R,
                GL_REPEAT);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER,
                GL_NEAREST);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER,
                GL_NEAREST);



      为了创建立方体纹理图像数据,可以在场景的原点上防止一架照相机,然后把相机一次对准各个轴的正方向和负方向,拍摄6幅视野为90(fovy=90)度的"快照"。这些快照把3D空间划分为6个在原点相交的平头截体(frustum)。

 

 纹理纹素的获取算法

          正如前面所述,对于每个片段,纹理坐标(s, t, r)被当作方向向量看待,每个纹素(texel)都表示从原点所看到的纹理立方体上的图像。下面实现代码来自mesa3d里面,源文件路径为Mesa-8.0.4\src\mesa\swrast\s_texfilter.c

/**********************************************************************/
/*                Texture Cube Map Sampling Functions                 */
/**********************************************************************/

/**
 * Choose one of six sides of a texture cube map given the texture
 * coord (rx,ry,rz).  Return pointer to corresponding array of texture
 * images.
 */
static const struct gl_texture_image **
choose_cube_face(const struct gl_texture_object *texObj,
                 const GLfloat texcoord[4], GLfloat newCoord[4])
{
   /*
      major axis
      direction     target                             sc     tc    ma
      ----------    -------------------------------    ---    ---   ---
       +rx          TEXTURE_CUBE_MAP_POSITIVE_X_EXT    -rz    -ry   rx
       -rx          TEXTURE_CUBE_MAP_NEGATIVE_X_EXT    +rz    -ry   rx
       +ry          TEXTURE_CUBE_MAP_POSITIVE_Y_EXT    +rx    +rz   ry
       -ry          TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT    +rx    -rz   ry
       +rz          TEXTURE_CUBE_MAP_POSITIVE_Z_EXT    +rx    -ry   rz
       -rz          TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT    -rx    -ry   rz
   */
   const GLfloat rx = texcoord[0];
   const GLfloat ry = texcoord[1];
   const GLfloat rz = texcoord[2];
   const GLfloat arx = FABSF(rx), ary = FABSF(ry), arz = FABSF(rz);
   GLuint face;
   GLfloat sc, tc, ma;

   if (arx >= ary && arx >= arz) {
      if (rx >= 0.0F) {
         face = FACE_POS_X;
         sc = -rz;
         tc = -ry;
         ma = arx;
      }
      else {
         face = FACE_NEG_X;
         sc = rz;
         tc = -ry;
         ma = arx;
      }
   }
   else if (ary >= arx && ary >= arz) {
      if (ry >= 0.0F) {
         face = FACE_POS_Y;
         sc = rx;
         tc = rz;
         ma = ary;
      }
      else {
         face = FACE_NEG_Y;
         sc = rx;
         tc = -rz;
         ma = ary;
      }
   }
   else {
      if (rz > 0.0F) {
         face = FACE_POS_Z;
         sc = rx;
         tc = -ry;
         ma = arz;
      }
      else {
         face = FACE_NEG_Z;
         sc = -rx;
         tc = -ry;
         ma = arz;
      }
   }

   { 
      const float ima = 1.0F / ma;
      newCoord[0] = ( sc * ima + 1.0F ) * 0.5F;
      newCoord[1] = ( tc * ima + 1.0F ) * 0.5F;
   }

   return (const struct gl_texture_image **) texObj->Image[face];
}


static void
sample_nearest_cube(struct gl_context *ctx,
		    const struct gl_texture_object *tObj, GLuint n,
                    const GLfloat texcoords[][4], const GLfloat lambda[],
                    GLfloat rgba[][4])
{
   GLuint i;
   (void) lambda;
   for (i = 0; i < n; i++) {
      const struct gl_texture_image **images;
      GLfloat newCoord[4];
      images = choose_cube_face(tObj, texcoords[i], newCoord);
      sample_2d_nearest(ctx, tObj, images[tObj->BaseLevel],
                        newCoord, rgba[i]);
   }
}


static void
sample_linear_cube(struct gl_context *ctx,
		   const struct gl_texture_object *tObj, GLuint n,
                   const GLfloat texcoords[][4],
		   const GLfloat lambda[], GLfloat rgba[][4])
{
   GLuint i;
   (void) lambda;
   for (i = 0; i < n; i++) {
      const struct gl_texture_image **images;
      GLfloat newCoord[4];
      images = choose_cube_face(tObj, texcoords[i], newCoord);
      sample_2d_linear(ctx, tObj, images[tObj->BaseLevel],
                       newCoord, rgba[i]);
   }
}


static void
sample_cube_nearest_mipmap_nearest(struct gl_context *ctx,
                                   const struct gl_texture_object *tObj,
                                   GLuint n, const GLfloat texcoord[][4],
                                   const GLfloat lambda[], GLfloat rgba[][4])
{
   GLuint i;
   ASSERT(lambda != NULL);
   for (i = 0; i < n; i++) {
      const struct gl_texture_image **images;
      GLfloat newCoord[4];
      GLint level;
      images = choose_cube_face(tObj, texcoord[i], newCoord);

      /* XXX we actually need to recompute lambda here based on the newCoords.
       * But we would need the texcoords of adjacent fragments to compute that
       * properly, and we don't have those here.
       * For now, do an approximation:  subtracting 1 from the chosen mipmap
       * level seems to work in some test cases.
       * The same adjustment is done in the next few functions.
      */
      level = nearest_mipmap_level(tObj, lambda[i]);
      level = MAX2(level - 1, 0);

      sample_2d_nearest(ctx, tObj, images[level], newCoord, rgba[i]);
   }
}


static void
sample_cube_linear_mipmap_nearest(struct gl_context *ctx,
                                  const struct gl_texture_object *tObj,
                                  GLuint n, const GLfloat texcoord[][4],
                                  const GLfloat lambda[], GLfloat rgba[][4])
{
   GLuint i;
   ASSERT(lambda != NULL);
   for (i = 0; i < n; i++) {
      const struct gl_texture_image **images;
      GLfloat newCoord[4];
      GLint level = nearest_mipmap_level(tObj, lambda[i]);
      level = MAX2(level - 1, 0); /* see comment above */
      images = choose_cube_face(tObj, texcoord[i], newCoord);
      sample_2d_linear(ctx, tObj, images[level], newCoord, rgba[i]);
   }
}


static void
sample_cube_nearest_mipmap_linear(struct gl_context *ctx,
                                  const struct gl_texture_object *tObj,
                                  GLuint n, const GLfloat texcoord[][4],
                                  const GLfloat lambda[], GLfloat rgba[][4])
{
   GLuint i;
   ASSERT(lambda != NULL);
   for (i = 0; i < n; i++) {
      const struct gl_texture_image **images;
      GLfloat newCoord[4];
      GLint level = linear_mipmap_level(tObj, lambda[i]);
      level = MAX2(level - 1, 0); /* see comment above */
      images = choose_cube_face(tObj, texcoord[i], newCoord);
      if (level >= tObj->_MaxLevel) {
         sample_2d_nearest(ctx, tObj, images[tObj->_MaxLevel],
                           newCoord, rgba[i]);
      }
      else {
         GLfloat t0[4], t1[4];  /* texels */
         const GLfloat f = FRAC(lambda[i]);
         sample_2d_nearest(ctx, tObj, images[level  ], newCoord, t0);
         sample_2d_nearest(ctx, tObj, images[level+1], newCoord, t1);
         lerp_rgba(rgba[i], f, t0, t1);
      }
   }
}


static void
sample_cube_linear_mipmap_linear(struct gl_context *ctx,
                                 const struct gl_texture_object *tObj,
                                 GLuint n, const GLfloat texcoord[][4],
                                 const GLfloat lambda[], GLfloat rgba[][4])
{
   GLuint i;
   ASSERT(lambda != NULL);
   for (i = 0; i < n; i++) {
      const struct gl_texture_image **images;
      GLfloat newCoord[4];
      GLint level = linear_mipmap_level(tObj, lambda[i]);
      level = MAX2(level - 1, 0); /* see comment above */
      images = choose_cube_face(tObj, texcoord[i], newCoord);
      if (level >= tObj->_MaxLevel) {
         sample_2d_linear(ctx, tObj, images[tObj->_MaxLevel],
                          newCoord, rgba[i]);
      }
      else {
         GLfloat t0[4], t1[4];
         const GLfloat f = FRAC(lambda[i]);
         sample_2d_linear(ctx, tObj, images[level  ], newCoord, t0);
         sample_2d_linear(ctx, tObj, images[level+1], newCoord, t1);
         lerp_rgba(rgba[i], f, t0, t1);
      }
   }
}

 

如何指定纹理坐标

          1. 使用vertex的法线作为uv坐标;   (GL_NORMAL_MAP)

               用于天空盒贴图

          2. 使用法线和相机到vertex的向量,推导出入射光向量作为uv坐标 (GL_REFLECTION_MAP)

              用于物体反射周围环境颜色

 

Relfect模式shader:

// 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);
    }


运行截图:



下面的图为6个面的纹理贴图,注意图像是上下倒置的哦!(看上面的s,t,r的代码)

POS_X:

NEG_X:

POS_Y:

NEG_Y:

POS_Z:

NEG_Z:

  • 0
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
以下是一个简单的立方体纹理映射的源文件和头文件示例,供您参考: 头文件 cube_map.h: ```c++ #ifndef CUBE_MAP_H #define CUBE_MAP_H #include <glad/glad.h> #include <glm/glm.hpp> class CubeMap { public: CubeMap(const char* front, const char* back, const char* top, const char* bottom, const char* left, const char* right); ~CubeMap(); void bind() const; void unbind() const; void set_uniform_location(GLuint program, const char* uniform_name); private: GLuint m_texture_id; }; #endif ``` 源文件 cube_map.cpp: ```c++ #include "cube_map.h" #include "stb_image.h" #include <iostream> CubeMap::CubeMap(const char* front, const char* back, const char* top, const char* bottom, const char* left, const char* right) { glGenTextures(1, &m_texture_id); glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_id); int width, height, nr_channels; unsigned char* data; // load front face data = stbi_load(front, &width, &height, &nr_channels, 0); if (data) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); stbi_image_free(data); } else { std::cout << "Failed to load front face of cube map" << std::endl; } // load back face data = stbi_load(back, &width, &height, &nr_channels, 0); if (data) { glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); stbi_image_free(data); } else { std::cout << "Failed to load back face of cube map" << std::endl; } // load top face data = stbi_load(top, &width, &height, &nr_channels, 0); if (data) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); stbi_image_free(data); } else { std::cout << "Failed to load top face of cube map" << std::endl; } // load bottom face data = stbi_load(bottom, &width, &height, &nr_channels, 0); if (data) { glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); stbi_image_free(data); } else { std::cout << "Failed to load bottom face of cube map" << std::endl; } // load left face data = stbi_load(left, &width, &height, &nr_channels, 0); if (data) { glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); stbi_image_free(data); } else { std::cout << "Failed to load left face of cube map" << std::endl; } // load right face data = stbi_load(right, &width, &height, &nr_channels, 0); if (data) { glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); stbi_image_free(data); } else { std::cout << "Failed to load right face of cube map" << std::endl; } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_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); } CubeMap::~CubeMap() { glDeleteTextures(1, &m_texture_id); } void CubeMap::bind() const { glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture_id); } void CubeMap::unbind() const { glBindTexture(GL_TEXTURE_CUBE_MAP, 0); } void CubeMap::set_uniform_location(GLuint program, const char* uniform_name) { GLint location = glGetUniformLocation(program, uniform_name); if (location >= 0) { glUniform1i(location, 0); } } ``` 使用示例: ```c++ CubeMap cube_map("front.png", "back.png", "top.png", "bottom.png", "left.png", "right.png"); // ... glActiveTexture(GL_TEXTURE0); cube_map.bind(); cube_map.set_uniform_location(shader_program, "cube_map"); // ... // in the fragment shader: uniform samplerCube cube_map; // ... vec3 reflect_dir = reflect(-incident_dir, normal); color = texture(cube_map, reflect_dir); ``` 效果图: ![Cube Mapping效果图](https://i.imgur.com/6z1w4ZT.png)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值