У меня есть рендерер на основе SDL2 и OpenGL (профиль ядра 3.3), который дает ожидаемые результаты в отношении преобразований и обработки текстур (2D).
Однако, когда я пытаюсь отобразить скайбокс, используя кубическую карту, созданную из эти текстуры (хотя я пробовал и другие), в процессе есть два шага, которые, по-видимому, не нужно делать ни в одном другом руководстве или примере, с которым я сталкивался. и я не могу объяснить:
1, Верхние/нижние грани при загрузке меняются местами, т.е.: верхняя загружается как GL_TEXTURE_CUBEMAP_NEGATIVE_Y
, а нижняя как GL_TEXTURE_CUBEMAP_POSITIVE_Y
;
2, при выборке карты куба я должен инвертировать позиции вершин по y, но также по z;
Без этого я получаю следующий результат:
(Обратите внимание: левая нижняя дальняя вершина была масштабирована на 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;
Что может быть причиной двух проблем, описанных выше?
Проблема вызвана сопоставлением координат текстуры .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 изображений кубической карты перед их загрузкой в сэмплер кубической карты или путем поворота координат текстуры.
Эта кубическая карта используется как карта окружения в сцене, а координаты текстуры получаются вектором направления, тогда имеет смысл вращать изображения. Если кубическая карта обернута в сетку, то координаты текстуры могут быть указаны правильным образом.
@zyndor Это зависит от исходных изображений. Исходные изображения можно правильно «повернуть» и загрузить как есть. Либо изображения можно поворачивать («фотошоп»), либо они должны вращаться приложением.
Я проголосовал за это, потому что рассуждения основаны на цитируемой спецификации. текст неверный. Фигура креста вводит в заблуждение. Изображения кубических карт находятся в массиве и имеют одинаковую ориентацию. Я опубликую другой ответ ниже с более подробной информацией.
@msc Это просто цитата из спецификации. Вы имеете в виду, что спецификация неверна?
@msc «Крест вводит в заблуждение» - это способ, которым вы должны положить стороны кубической карты на лист бумаги, чтобы сложить куб. Ничего, кроме моей аргументации, неверно.
@ Rabbid76 Раббид76 Что я считаю неправильным, так это утверждение: «Это означает, что боковые текстуры должны быть повернуты перед их загрузкой в сэмплер кубической карты». Их не нужно вращать. Кубические карты прекрасно работают со всеми изображениями x и z, имеющими одинаковую ориентацию сверху вниз, где «верх» — это логическая вершина сцены, при условии, что вы преобразуете координаты куба в левостороннюю систему кубической карты. Вращение изображений может быть другим способом достижения той же цели, но это делает ваши кубические карты нестандартными.
@msc «Что я считаю неправильным, так это утверждение» - чувство не оправдывает отрицательный голос. Их нужно вращать, если вы читаете 6 отдельных тайлов из файлов или если у вас есть один битмап, где тайлы расположены крестом (как изображение в текстуре). Если вы не повернете их, результатом будет изображение в вопросе. Вращение может быть выполнено путем поворота изображения или координат. В любом случае в документации упоминается, что координаты текстуры кубической карты обрабатываются как трехмерный вектор из центра куба.
Кубические карты @msc были введены для карт окружения, где у вас нет координат текстуры. Если координаты получены из вектора направления, то изображения должны быть повернуты. Кубические карты были введены для карт окружения, а не для кубов Minecraft. Я упоминал об этом в своем ответе.
Аргументация предыдущего ответа из цитируемой спецификации. текст неправильный.
Что происходит, так это то, что цитируемый текст, если вы внимательно посмотрите на математику, требует, чтобы изображения кубической карты имели ориентация сверху вниз и были расположены в левой системе координат с +Y вверх. Это означает, что небо находится в +Y, и если вы стоите лицом к +Z, -X должен быть слева от вас, а +X справа. Очевидно, это было унаследовано от Renderman, где впервые появились кубические карты.
Координаты куба, который вы визуализируете как скайбокс, который будет использоваться для выборки карты куба, находятся в системе координат OpenGL, которая является правосторонней системой. Они должны быть преобразованы в левостороннюю систему кубической карты перед сэмплированием. Это делается простым масштабированием координаты Z на -1. Невыполнение этого требования означает, что сцена будет зеркальным отражением того, чем она должна быть. Очень распространенный сбой в образцах, на которые я смотрел.
Изображения OP перевернуты, потому что они имеют стандартную ориентацию OpenGL снизу вверх.
Если вы используете Vulkan, у него левосторонняя система, но Y не работает. Таким образом, чтобы правильно отобразить кубическую карту на Vulkan, вам все равно нужно преобразовать координаты куба скайбокса, в данном случае повернув их на 180° вокруг оси X. Если этого не сделать, у вас будут перевернутые изображения.
Это: "Таким образом, чтобы правильно отобразить кубическую карту на Vulkan, вам все равно нужно преобразовать координаты куба скайбокса, в данном случае повернув их на 180° вокруг оси X." и это: "Это означает, что боковые текстуры должны быть повернуты перед их загрузкой в сэмплер кубической карты." в конечном итоге приводят к одному и тому же результату. Один преобразует координаты текстуры в пространство кубической карты, другой преобразует изображения кубической карты в пространство координат текстуры. Поэтому я не понимаю, почему предыдущий ответ был неправильным.
Ладно, может быть, неправильно, э-э, неправильный выбор слова. Если вы создаете кубическую карту для использования в нескольких API, вам придется манипулировать изображениями при загрузке в один или несколько API, что я не считаю желательным. Гораздо проще преобразовать координаты текстуры.
Плюс оригинальная спецификация расширения. говорит, что внутренняя часть куба (то есть кубическая карта) имеет левостороннюю систему координат. Поворачивая изображения, вы больше не имеете этого, и другие люди, наткнувшиеся на вашу кубическую карту, могут не знать, что изображения были повернуты. Лучше соответствовать спецификации.
«Это: «Итак, чтобы правильно отобразить кубическую карту на Vulkan, вам все равно нужно преобразовать координаты куба скайбокса, в данном случае повернув их на 180 ° вокруг оси X». и это: «Это означает, что боковые текстуры должны быть повернуты перед загрузка их в сэмплер кубических карт." в конечном итоге приводит к тому же самому." На самом деле это не так. Поворот координат на 180° вокруг оси x также эффективно меняет местами изображения +y и -y, поэтому вы можете использовать точно такую же кубическую карту в OpenGL или Vulkan.
Вы можете подумать, что я изменил аргументацию в своем ответе. Во всяком случае, ответ не был неправильным. Вариант использования отличается от вашего. Ваша причина отрицательного голосования немного странная.
Спасибо за ваш ответ, это отличная информация. Извините за отсутствие скорости, но вы в основном говорите, что мои лица Y на самом деле в порядке, и все мои лица X и Z нужно повернуть перед загрузкой? Хотя это правдоподобно / имеет смысл, библиотеки (bgfx, DALi), которые я рассматривал для справки, похоже, не нуждаются в этом, и мне интересно, почему? Если вы будете достаточно любезны, чтобы уточнить, я был бы очень признателен.