OpenGL中的立方体贴图

6

我尝试使用6个位图来映射立方体以实现天空盒效果。我的问题是每个面都将一个纹理映射到了其中。我已经通过gDEBugger检查了立方体纹理内存,发现只有一幅图像(尽管我尝试加载了六幅图像)。

准备纹理的代码:

bool Texture::LoadCubicTexture(vector<string> filenameTable)
{
  glGenTextures(1,&texID);
  glBindTexture(GL_TEXTURE_CUBE_MAP,texID);

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

  int i = 0;
  vector<string>::iterator vsit;

  // There is always six filenames
  for(vsit=filenameTable.begin();vsit!=filenameTable.end();++vsit)
  {
    string filename = *vsit;
    BMPData* bmpData = LoadTextureBMPData_custom(filename);
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X+i,0,GL_RGB,bmpData->width,bmpData->height,0,GL_BGR,GL_UNSIGNED_BYTE,&(bmpData->data[0]));
    i++;
    delete daneObrazu;
  }
  glGenerateMipmap(GL_TEXTURE_CUBE_MAP);

  return true;
}

VS:

#version 330 core

in vec3 vVertexPos;
in vec3 vertexUV;

out vec3 vCoords;
uniform mat4 MVP;

void main()
{
  vCoords = normalize(vertexUV);
  gl_Position = MVP * vec4(vVertexPos,1.0);
}

FS:

#version 330 core

in vec3 vCoords;
uniform samplerCube cube;

out vec4 vFragColor;

void main()
{
  vFragColor = texture(cube, vCoords);
}

OBJ文件:

# Blender v2.62 (sub 0) OBJ File: 'skybox.blend'
# www.blender.org
mtllib skybox.mtl
o Cube
v 10.487665 -10.487666 -10.487665
v 10.487665 -10.487666 10.487665
v -10.487667 -10.487666 10.487664
v -10.487662 -10.487666 -10.487670
v 10.487671 10.487666 -10.487660
v 10.487659 10.487666 10.487673
v -10.487670 10.487666 10.487662
v -10.487665 10.487666 -10.487666
vt 0.990480 0.014286
vt 0.993478 0.991259
vt 0.016505 0.994256
vt 0.013507 0.017283
vt 0.988479 0.008111
vt 0.985457 0.993412
vt 0.000157 0.990390
vt 0.003179 0.005089
vt 0.002693 1.001082
vt -0.000347 0.009939
vt 0.990796 0.006898
vt 0.993837 0.998041
vt 0.004581 0.999210
vt 0.001535 0.006444
vt 0.994302 0.003398
vt 0.997347 0.996165
vt 0.004172 -0.000587
vt 0.996320 -0.003630
vt 0.999364 0.988517
vt 0.007216 0.991561
vt 0.000632 0.000140
vt 0.983846 -0.002921
vt 0.986862 0.995017
vt 0.003648 0.998078
vn 0.000000 -1.000000 0.000000
vn 0.000000 1.000000 0.000000
vn 1.000000 0.000000 0.000000
vn -0.000000 -0.000000 1.000000
vn -1.000000 -0.000000 -0.000000
vn 0.000000 0.000000 -1.000000
usemtl Skybox
s off
f 1/1/1 2/2/1 3/3/1
f 1/1/1 3/3/1 4/4/1
f 5/5/2 8/6/2 7/7/2
f 5/5/2 7/7/2 6/8/2
f 1/9/3 5/10/3 6/11/3
f 1/9/3 6/11/3 2/12/3
f 2/13/4 6/14/4 7/15/4
f 2/13/4 7/15/4 3/16/4
f 3/17/5 7/18/5 8/19/5
f 3/17/5 8/19/5 4/20/5
f 5/21/6 1/22/6 4/23/6
f 5/21/6 4/23/6 8/24/6

我的问题:

  • 我在这段代码中使用的技术看起来还可以吗?
  • 当只有2个UV时,立方体(在GL_TEXTURE_CUBE_MAP纹理中)的纹理是如何映射的?(我指的是一般情况下。)
  • 在这种情况下,我可以使用自动生成UV吗(我是否需要对着色器进行许多更改)?
  • 有人可以建议我在哪里寻找问题吗?(有一定的概率;缓冲区,着色器,网格;只是建议)?

[编辑]:我尝试在单独的源文件中硬编码顶点和uv,并且我遇到了相同的问题-一个纹理适用于立方体的所有面。硬编码数据似乎是正确的:

#include "TestCube.h"

vector<vec3> GetTestCubeVertices()
{
  vector<vec3> vrtx;

  const float xd = 1.0f;
  const float yd = 1.0f;
  const float zd = 1.0f;

  const float testCubeVertices[] = 
  {
   -xd, -yd,  zd,   xd, -yd,  zd,   -xd,  yd,  zd,  // ABE
    xd, -yd,  zd,  -xd,  yd,  zd,    xd,  yd,  zd,  // BEF
    xd, -yd,  zd,   xd, -yd, -zd,    xd,  yd,  zd,  // BCF
    xd, -yd, -zd,   xd,  yd,  zd,    xd,  yd, -zd,  // CFG
    xd, -yd, -zd,  -xd, -yd, -zd,    xd,  yd, -zd,  // CDG
   -xd, -yd, -zd,   xd,  yd, -zd,   -xd,  yd, -zd,  // DGH
   -xd, -yd, -zd,  -xd, -yd,  zd,   -xd,  yd, -zd,  // DAH
   -xd, -yd,  zd,  -xd,  yd, -zd,   -xd,  yd,  zd,  // AHE
   -xd,  yd,  zd,   xd,  yd,  zd,   -xd,  yd, -zd,  // EFH
    xd,  yd,  zd,  -xd,  yd, -zd,    xd,  yd, -zd,  // FHG
    xd, -yd,  zd,  -xd, -yd,  zd,    xd, -yd, -zd,  // BAC
   -xd, -yd,  zd,   xd, -yd, -zd,   -xd, -yd, -zd,  // ACD
  };

  for(int i=0;i<108;i=i+3)
    vrtx.push_back(vec3(testCubeVertices[i],testCubeVertices[i+1],testCubeVertices[i+2]));

  return vrtx;
}

vector<vec2> GetTestCubeUVs()
{
  vector<vec2> uv;

  const float testCubeUV[] = 
  {
    0,0,  1,0,  0,1, // ABE
    1,0,  0,1,  1,1, // BEF
    0,0,  1,0,  0,1, // BCF
    1,0,  0,1,  1,1, // CFG
    0,0,  1,0,  0,1, // CDG
    1,0,  0,1,  1,1, // DGH
    0,0,  1,0,  0,1, // DAH
    1,0,  0,1,  1,1, // AHE
    0,0,  1,0,  0,1, // EFH
    1,0,  0,1,  1,1, // FHG
    0,0,  1,0,  0,1, // BAC
    1,0,  0,1,  1,1, // ACD
  };

  for(int i=0;i<72;i=i+2)
    uv.push_back(vec2(testCubeUV[i],testCubeUV[i+1]));

  return uv;
}

仍有两个补充问题,我需要调用OpenGL:
glTexParameteri(GL_TEXTURE_CUBE_MAP,GL_TEXTURE_WRAP_R,GL_CLAMP_TO_EDGE);
  • 我理解OpenGL会自动处理r坐标,因为在glTexImage2D()中有GL_TEXTURE_CUBE_MAP_POSITIVE_X常量的信息?
  • 在顶点着色器中是否需要修改r坐标?

下面是结果屏幕(禁用写入深度缓冲区并未设置缩放,但这不是我的问题):

enter image description here

我注意到重复的贴图是第五个加载的纹理(GL_TEXTURE_CUBE_MAP_POSITIVE_Z)。

enter image description here

[最后编辑]: 在Skybox VS中UV坐标存在问题(r坐标只有一个值),Skybox VS应该如下:

void main()
{
  vCoords = normalize(vVertexPos);
  gl_Position = MVP * vec4(vVertexPos,1.0);
}

在Skybox技术中存在一些问题,但这不是本主题的讨论重点。已解决。


如果您不使用.obj模型,而是在代码中创建6个四边形,会发生什么? - Display Name
我在单独的头文件中硬编码了顶点和UV,但是问题仍然存在。 - CppMonster
1个回答

5
纹理立方体贴图使用3D纹理坐标:它用于确定实际选择的立方体面,然后推导出用于访问立方体贴图面纹素的实际2D纹理坐标。
你的纹理坐标是2D(错误的),实际上你的纹理坐标vertexUV(因此vCoords)的Z坐标始终为0,无法完整映射纹理(缺少的组件由默认属性值vec4(0,0,0,1)复制)。
要获得所需的结果,请修改顶点着色器以使用有意义的坐标。
vCoords = normalize(vVertexPos);

没错,我一开始使用的是<vec2> UV,现在要将其转换为<vec2> UV。好吧,我想我必须从一开始就使用<vec3> UV。那么我从哪里获取第三个坐标到UV表中呢? - CppMonster
1
请看上面的代码,提供一种解决方案:从顶点位置(正确归一化)。立方体必须在重心处于(0,0,0)的条件下。在这种情况下,您可以直接在顶点着色器中计算它。 - Luca
我理解你的意思是我需要遵循某些规则(而不是这行代码)。当我将此行代码写入着色器时,我会断开与纹理坐标流的连接(因此基本上我不需要VBO UV)。我尝试修改这行代码,结果是一个带有纹理的四边形(我使用了上面呈现的硬编码顶点的重心立方体)。 - CppMonster

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接