OpenGL立方体贴图的面序和采样问题

时间:2019-04-07 11:00:44

标签: c++ opengl

我有一个基于SDL2和OpenGL(3.3核心配置文件)的渲染器,可以为我带来有关转换和纹理(2D)处理的预期结果。

但是,当我尝试使用从these textures创建的立方体贴图显示天空盒时(尽管我也尝试了其他方法),在此过程中有两个步骤,我没有其他教程或示例遇到似乎必须这样做,而我无法解释:

1,上传时必须交换顶面/底面,即:顶面以GL_TEXTURE_CUBEMAP_NEGATIVE_Y的形式上传,底面以GL_TEXTURE_CUBEMAP_POSITIVE_Y的形式上传; 2,在采样立方体贴图时,我必须沿y反转顶点位置,但沿z还要

没有这个,我得到以下结果:

enter image description here

(N.B。将左下角顶点缩放为0.8,以表明我的坐标系是正确的方向)

图像文件的命名正确。

立方体是我正在执行的唯一绘制。

如果我删除任一侧的[索引],我将得到预期的结果(即,没有交换/镜像)。

我的集成和专用GPU似乎得到了相同的结果。

我的OpenGL常量,来自glLoadGen生成的标头:

#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519

纹理上传代码(与LearnOpenGL's tutorial相同):

GLuint name;
glGenTextures(1, &name);
glBindTexture(GL_TEXTURE_CUBE_MAP, name);

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

glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR));

GLint target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
for (uint8_t i = 0; i < 6; ++i)
{
  glTexImage2D(target + i, 0, GL_RGB8, width, height, 0, GL_RGB,
    GL_UNSIGNED_BYTE, pixelData[i]));
}

顶点着色器:

#version 330

precision mediump float;
uniform mat4 uModelViewProjection;
in vec3 aPosition;
out vec3 vTexCoord;

void main()
{
  vec4 position = uModelViewProjection * vec4(aPosition, 1.f);
  gl_Position = position.xyww;

  vTexCoord = aPosition;
}

片段着色器:

#version 330

precision mediump float;
uniform samplerCube uTexture0;
in vec3 vTexCoord;
out vec4 FragColor;

void main()
{
  FragColor = texture(uTexture0, vTexCoord);
  // using textureCube() yields a compile error asking for #extension  GL_NV_shadow_samplers_cube : enable, but even with that, the issue perists.
}

网状设置(半伪代码):

//    4----5
//   /|   /|
//  6----7 |
//  | |  | |
//  | 0--|-1
//  |/   |/
//  2----3
VertexType vertices[8] = {
  Vector3(-1.f, -1.f, -1.f) * .8f, // debug coordinate system
  Vector3(1.f, -1.f, -1.f),

  Vector3(-1.f, -1.f, 1.f),
  Vector3(1.f, -1.f, 1.f),

  Vector3(-1.f, 1.f, -1.f),
  Vector3(1.f, 1.f, -1.f),

  Vector3(-1.f, 1.f, 1.f),
  Vector3(1.f, 1.f, 1.f),
};

uint16_t indices[] = {
  4, 0, 5,
  0, 1, 5,

  6, 2, 4,
  2, 0, 4,

  7, 3, 6,
  3, 2, 6,

  5, 1, 7,
  1, 3, 7,

  0, 2, 1,
  2, 3, 1,

  5, 7, 4,
  7, 6, 4,
};

// create buffers & upload data

渲染(伪代码):

// -clear color & depth buffers;
// -set the model transform to a translation of -10 units along z; 
//   view transform is identity; projection is perspective with .25
//   radians vertical FOV, zNear of .1, zFar of 100.; viewport is full screen
// -set shader program;
// -bind texture (same name, same target as upon uploading);
// -enable backface culling only (no depth test / write);
// -draw the cube
// -glFlush() and swap buffers;

到底是什么导致了上述两个问题?

2 个答案:

答案 0 :(得分:1)

此问题是由于.str纹理坐标到立方体贴图的映射所致:

OpenGL 4.6 API Core Profile Specification, 8.13 Cube Map Texture Selection, page 253

  

当采样一个立方体贴图纹理时,(s,t,r)纹理坐标被视为方向向量(rx,ry,rz)立方体的中心。 q 坐标将被忽略。在纹理应用时,内插的每个片段方向向量会根据最大量值坐标方向(长轴方向)选择立方体贴图的二维图像之一。如果两个或多个坐标具有相同的幅度,则实现可以定义规则以消除这种情况的歧义。该规则必须是确定性的,并且仅取决于(rx,ry,rz)。表8.19中的目标列说明了主轴方向如何映射到特定立方体贴图目标的二维图像。   使用表8.19中指定的主轴方向确定的 sc tc ma ,更新了(s,t )计算如下:

     

s = 1/2 (sc / |m_a| + 1)

     

t = 1/2 (tc / |m_a| + 1)

Major Axis Direction|        Target             |sc |tc |ma |
--------------------+---------------------------+---+---+---+
       +rx          |TEXTURE_CUBE_MAP_POSITIVE_X|−rz|−ry| rx|
       −rx          |TEXTURE_CUBE_MAP_NEGATIVE_X| rz|−ry| rx|
       +ry          |TEXTURE_CUBE_MAP_POSITIVE_Y| rx| rz| ry|
       −ry          |TEXTURE_CUBE_MAP_NEGATIVE_Y| rx|−rz| ry|
       +rz          |TEXTURE_CUBE_MAP_POSITIVE_Z| rx|−ry| rz|
       −rz          |TEXTURE_CUBE_MAP_NEGATIVE_Z|−rx|−ry| rz|
--------------------+---------------------------+---+---+---+
     

表8.19:基于纹理的长轴方向选择立方体贴图图像   坐标

这意味着在将侧面纹理加载到立方体贴图采样器之前必须对其进行旋转。

答案 1 :(得分:1)

引用的规范中先前答案的原因。文字错误。

发生的情况是,如果您仔细看一下数学运算,引用的文本要求立方体贴图的图像具有自上而下的方向,并以左手坐标系排列, + Y起。这表示天空为+ Y,如果您面对+ Z,则-X应该在您的左侧,而+ X在您的右侧。这显然是从Renderman继承的,Renderman首次出现了立方体贴图。

您要渲染为天空盒的多维数据集的坐标(将用于采样多维数据集贴图)位于OpenGL的坐标系中,该坐标系是惯用的系统。在采样之前,必须将它们转换为立方体贴图的左手系统。这可以通过简单地将Z坐标缩放-1来完成。如果不这样做,则意味着该场景将是其应有的镜像。我看过的样本中很常见的一个失败。

OP上下颠倒的图像是因为它们具有标准的OpenGL自下而上的方向。

如果您使用的是Vulkan,则该系统使用左手系统,但Y向下。因此,要在Vulkan上正确渲染立方体贴图,您仍然需要变换天空盒立方体的坐标,在这种情况下,是将它们绕X轴旋转180°。否则,您将获得颠倒的图像。