Порядок граней кубической карты OpenGL и проблема с выборкой

У меня есть рендерер на основе SDL2 и OpenGL (профиль ядра 3.3), который дает ожидаемые результаты в отношении преобразований и обработки текстур (2D).

Однако, когда я пытаюсь отобразить скайбокс, используя кубическую карту, созданную из эти текстуры (хотя я пробовал и другие), в процессе есть два шага, которые, по-видимому, не нужно делать ни в одном другом руководстве или примере, с которым я сталкивался. и я не могу объяснить:

1, Верхние/нижние грани при загрузке меняются местами, т.е.: верхняя загружается как GL_TEXTURE_CUBEMAP_NEGATIVE_Y, а нижняя как GL_TEXTURE_CUBEMAP_POSITIVE_Y; 2, при выборке карты куба я должен инвертировать позиции вершин по y, но также по z;

Без этого я получаю следующий результат:

Порядок граней кубической карты OpenGL и проблема с выборкой

(Обратите внимание: левая нижняя дальняя вершина была масштабирована на 0,8, чтобы уточнить, что моя система координат правильная)

Файлы изображений названы правильно.

Куб — единственная розыгрыш, которую я делаю.

Если я удалю [индексы для] любой из сторон, я получу ожидаемые результаты (т.е. там нет подкачки/зеркалирования).

Кажется, я получаю одинаковые результаты с моими интегрированными и выделенными графическими процессорами.

Мои константы 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):

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;

Что может быть причиной двух проблем, описанных выше?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
2 884
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Проблема вызвана сопоставлением координат текстуры .str с кубической картой:

Спецификация основного профиля API OpenGL 4.6, 8.13 Выбор текстуры кубической карты, стр. 253:

When a cube map texture is sampled, the (s, t, r) texture coordinates are treated as a direction vector (rx, ry, rz) emanating from the center of a cube. The q coordinate is ignored. At texture application time, the interpolated per-fragment direction vector selects one of the cube map face’s two-dimensional images based on the largest magnitude coordinate direction (the major axis direction). If two or more coordinates have the identical magnitude, the implementation may define the rule to disambiguate this situation. The rule must be deterministic and depend only on (rx, ry, rz). The target column in table 8.19 explains how the major axis direction maps to the two-dimensional image of a particular cube map target. Using the sc, tc, and ma determined by the major axis direction as specified in table 8.19, an updated (s, t) is calculated as follows:

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|
--------------------+---------------------------+---+---+---+

Table 8.19: Selection of cube map images based on major axis direction of texture coordinates

Вращение может быть достигнуто путем поворота 6 изображений кубической карты перед их загрузкой в ​​сэмплер кубической карты или путем поворота координат текстуры.

Эта кубическая карта используется как карта окружения в сцене, а координаты текстуры получаются вектором направления, тогда имеет смысл вращать изображения. Если кубическая карта обернута в сетку, то координаты текстуры могут быть указаны правильным образом.

Спасибо за ваш ответ, это отличная информация. Извините за отсутствие скорости, но вы в основном говорите, что мои лица Y на самом деле в порядке, и все мои лица X и Z нужно повернуть перед загрузкой? Хотя это правдоподобно / имеет смысл, библиотеки (bgfx, DALi), которые я рассматривал для справки, похоже, не нуждаются в этом, и мне интересно, почему? Если вы будете достаточно любезны, чтобы уточнить, я был бы очень признателен.

zyndor 07.04.2019 18:11

@zyndor Это зависит от исходных изображений. Исходные изображения можно правильно «повернуть» и загрузить как есть. Либо изображения можно поворачивать («фотошоп»), либо они должны вращаться приложением.

Rabbid76 07.04.2019 18:23

Я проголосовал за это, потому что рассуждения основаны на цитируемой спецификации. текст неверный. Фигура креста вводит в заблуждение. Изображения кубических карт находятся в массиве и имеют одинаковую ориентацию. Я опубликую другой ответ ниже с более подробной информацией.

msc 06.03.2020 08:02

@msc Это просто цитата из спецификации. Вы имеете в виду, что спецификация неверна?

Rabbid76 06.03.2020 08:07

@msc «Крест вводит в заблуждение» - это способ, которым вы должны положить стороны кубической карты на лист бумаги, чтобы сложить куб. Ничего, кроме моей аргументации, неверно.

Rabbid76 24.04.2020 22:49

@ Rabbid76 Раббид76 Что я считаю неправильным, так это утверждение: «Это означает, что боковые текстуры должны быть повернуты перед их загрузкой в ​​сэмплер кубической карты». Их не нужно вращать. Кубические карты прекрасно работают со всеми изображениями x и z, имеющими одинаковую ориентацию сверху вниз, где «верх» — это логическая вершина сцены, при условии, что вы преобразуете координаты куба в левостороннюю систему кубической карты. Вращение изображений может быть другим способом достижения той же цели, но это делает ваши кубические карты нестандартными.

msc 27.04.2020 00:54

@msc «Что я считаю неправильным, так это утверждение» - чувство не оправдывает отрицательный голос. Их нужно вращать, если вы читаете 6 отдельных тайлов из файлов или если у вас есть один битмап, где тайлы расположены крестом (как изображение в текстуре). Если вы не повернете их, результатом будет изображение в вопросе. Вращение может быть выполнено путем поворота изображения или координат. В любом случае в документации упоминается, что координаты текстуры кубической карты обрабатываются как трехмерный вектор из центра куба.

Rabbid76 27.04.2020 07:30

Кубические карты @msc были введены для карт окружения, где у вас нет координат текстуры. Если координаты получены из вектора направления, то изображения должны быть повернуты. Кубические карты были введены для карт окружения, а не для кубов Minecraft. Я упоминал об этом в своем ответе.

Rabbid76 27.04.2020 08:07

Аргументация предыдущего ответа из цитируемой спецификации. текст неправильный.

Что происходит, так это то, что цитируемый текст, если вы внимательно посмотрите на математику, требует, чтобы изображения кубической карты имели ориентация сверху вниз и были расположены в левой системе координат с +Y вверх. Это означает, что небо находится в +Y, и если вы стоите лицом к +Z, -X должен быть слева от вас, а +X справа. Очевидно, это было унаследовано от Renderman, где впервые появились кубические карты.

Координаты куба, который вы визуализируете как скайбокс, который будет использоваться для выборки карты куба, находятся в системе координат OpenGL, которая является правосторонней системой. Они должны быть преобразованы в левостороннюю систему кубической карты перед сэмплированием. Это делается простым масштабированием координаты Z на -1. Невыполнение этого требования означает, что сцена будет зеркальным отражением того, чем она должна быть. Очень распространенный сбой в образцах, на которые я смотрел.

Изображения OP перевернуты, потому что они имеют стандартную ориентацию OpenGL снизу вверх.

Если вы используете Vulkan, у него левосторонняя система, но Y не работает. Таким образом, чтобы правильно отобразить кубическую карту на Vulkan, вам все равно нужно преобразовать координаты куба скайбокса, в данном случае повернув их на 180° вокруг оси X. Если этого не сделать, у вас будут перевернутые изображения.

Это: "Таким образом, чтобы правильно отобразить кубическую карту на Vulkan, вам все равно нужно преобразовать координаты куба скайбокса, в данном случае повернув их на 180° вокруг оси X." и это: "Это означает, что боковые текстуры должны быть повернуты перед их загрузкой в ​​сэмплер кубической карты." в конечном итоге приводят к одному и тому же результату. Один преобразует координаты текстуры в пространство кубической карты, другой преобразует изображения кубической карты в пространство координат текстуры. Поэтому я не понимаю, почему предыдущий ответ был неправильным.

Nicol Bolas 06.03.2020 08:23

Ладно, может быть, неправильно, э-э, неправильный выбор слова. Если вы создаете кубическую карту для использования в нескольких API, вам придется манипулировать изображениями при загрузке в один или несколько API, что я не считаю желательным. Гораздо проще преобразовать координаты текстуры.

msc 06.03.2020 08:29

Плюс оригинальная спецификация расширения. говорит, что внутренняя часть куба (то есть кубическая карта) имеет левостороннюю систему координат. Поворачивая изображения, вы больше не имеете этого, и другие люди, наткнувшиеся на вашу кубическую карту, могут не знать, что изображения были повернуты. Лучше соответствовать спецификации.

msc 06.03.2020 08:36

«Это: «Итак, чтобы правильно отобразить кубическую карту на Vulkan, вам все равно нужно преобразовать координаты куба скайбокса, в данном случае повернув их на 180 ° вокруг оси X». и это: «Это означает, что боковые текстуры должны быть повернуты перед загрузка их в сэмплер кубических карт." в конечном итоге приводит к тому же самому." На самом деле это не так. Поворот координат на 180° вокруг оси x также эффективно меняет местами изображения +y и -y, поэтому вы можете использовать точно такую ​​же кубическую карту в OpenGL или Vulkan.

msc 27.04.2020 00:57

Вы можете подумать, что я изменил аргументацию в своем ответе. Во всяком случае, ответ не был неправильным. Вариант использования отличается от вашего. Ваша причина отрицательного голосования немного странная.

Rabbid76 25.07.2020 09:48

Другие вопросы по теме