Данные текстуры Mipmap повреждены при сборке релиза

Я делаю карту высот Raytracer на основе Максимальная структура Mipmap.

Короче говоря, я вручную создал текстуру с уровнями mipmap, используя «Максимальный фильтр». В режиме отладки программа работает нормально и с текстурой все в порядке, но в режиме выпуска, следующий за последним уровнем mipmap содержит значения мусора, которые вызывают серьезные визуальные проблемы в моей трассировке лучей.


Немного информации о максимальных мипмапах:

Maximum Mipmap — это структура обхода лучей, почти как квадродерево для высот. На самом нижнем уровне mipmap (уровень 0) каждый пиксель будет содержать значение максимальной высоты соответствующего патча (4 выборки высоты) в карте высот. На каждом последующем уровне каждый тексель будет содержать максимальное значение 4 соответствующих текселей на предыдущем уровне. Это будет «Максимальный фильтр» вместо обычного линейного фильтра.

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

В моей программе карта высот предварительно обрабатывается в формате, где каждый пиксель представляет один патч, а каждый канал (RGBA) содержит выборку высоты из одного из углов патча. Таким образом, это избыточный формат, два соседних пикселя будут разделять два значения.


Теперь для проблемы, которую я имею. Я использую Visual Studio 2015 Community и OpenGL версии 4.5 и компилирую с настройками по умолчанию для режима отладки и выпуска, за исключением включения каталогов для дополнительных библиотек и их данных компоновщика.

Когда я запускаю свою программу с помощью Debug Build, программа работает нормально. Когда я запускаю его в Release Build, у карты трассировки лучей есть очень странные артефакты, как будто у mipmaps неправильные значения.

Поэтому я попытался выделить проблему. И действительно, по какой-то причине уровень mipmap, следующий за последним, имеет неправильные значения в сборке выпуска, а не в сборке отладки. Но только этот уровень. Все остальные уровни, кажется, в порядке.

Наиболее вероятным местом, где у меня могут быть проблемы, будет та часть, где я создаю мипмапы. Насколько я знаю, не существует «Максимальный фильтр» для автоматической генерации мипмапов, поэтому я генерирую их вручную.

Вот код, который я использую для генерации максимальной текстуры mipmap:

// Read heightfield texture into 'hfPixels'
// Texture dimensions must be Power-Of-Two+1 (Ex: 1025x1025 )

int nWidth = width - 1;
int nHeight = height - 1;

// Convert heightfield into a compact format
std::unique_ptr< Color4C[] > compactHf{ new Color4C[ nWidth * nHeight ] };
for ( int x = 0; x < nWidth; ++x ) {
for ( int y = 0; y < nHeight; ++y ) {
Color4C& patch = compactHf[ y * nWidth + x ];
patch.setColor(
hfPixels[ y * width + x ].red,
hfPixels[ y * width + x + 1 ].red,
hfPixels[ (y+1) * width + x ].red,
hfPixels[ (y+1) * width + x  + 1].red );
}
}
hfTexPixels.deletePixelArray();
if ( !_hfCompact.loadTexture( compactHf.get(), nWidth, nHeight ) ) {
return false;
}

// Generate the finest mipmap level
std::unique_ptr<GLubyte[]> previousMipmapLevel{ new GLubyte[ nWidth * nHeight ] };

for ( int x = 0; x < nWidth; ++x ) {
for ( int y = 0; y < nHeight; ++y ) {
Color4C& patch = compactHf[ y* nWidth + x ];
previousMipmapLevel[ y*nWidth + x ] =
max( max( patch.red, patch.green ),
max( patch.blue, patch.alpha ) );
}
}
if ( !_maximumMipmaps.createSpecialTexture( nWidth, nHeight, GL_R8, GL_RED, previousMipmapLevel.get() ) ) {
std::cout << "Error loading mipmap texture" << std::endl;
return false;
}

int maxLevel = (int)log2( nWidth );
std::cout << "Max LOD: " << maxLevel << std::endl;

// Generate remaining mipmap levels
for ( int level = 1; level <= maxLevel; ++level ) {
int prevWidth = nWidth;
int prevHeight = nHeight;
nWidth /= 2;
nHeight /= 2;

std::unique_ptr<GLubyte[]> nextMipmapLevel{ new GLubyte[ nWidth * nHeight ] };

for ( int x = 0; x < nWidth; ++x ) {
for ( int y = 0; y < nHeight; ++y ) {
int pix = x * 2;

nextMipmapLevel[ y * nWidth + x ] =
max(
max( previousMipmapLevel[ (y*2) * prevWidth + pix ], previousMipmapLevel[ (y*2) * prevWidth + pix + 1 ] ),
max( previousMipmapLevel[ (y*2 + 1 ) * prevWidth + pix ], previousMipmapLevel[ (y*2+1) * prevWidth + pix + 1 ] ) );
}
}

_maximumMipmaps.bindTexture();
glTexImage2D( GL_TEXTURE_2D, level, GL_R8, nWidth, nHeight, 0, GL_RED, GL_UNSIGNED_BYTE, nextMipmapLevel.get() );
if ( getOpenGLError( "Error loading mipmap level." ) ) {
std::cout << "Error loading mipmap level(" << level << ")" << std::endl;
return false;
}
_maximumMipmaps.unbindTexture();

previousMipmapLevel.swap( nextMipmapLevel );
}
_lastLevel = maxLevel;

_maximumMipmaps.setMinMagFilter( GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST );
_maximumMipmaps.setWrapMode( GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE );return true;

Если вам интересно, функция ‘createSpecialTexture’ будет использовать этот код:

bool Texture::createSpecialTexture( int width, int height, GLenum internalFormat, GLenum format, void* data ) {
glGenTextures( 1, &textureId );

if ( getOpenGLError( "Unable to generate TextureID." ) ) {
return false;
}

glBindTexture( GL_TEXTURE_2D, textureId );
glTexImage2D( GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, data );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

Вот как выглядят уровни mipmap, построенные из карты высот 1025×1025 (1024×1024 после предварительной обработки):

Отладка MIPMAP
Debug Build

Выпуск MipMap
Release Build — обратите внимание, что на следующем уровне (2×2 mipmap) есть два черных текселя. Последний уровень не отображается.

Этот код, кажется, работает в режиме отладки, но не в режиме выпуска, где второй-последний уровень mipmap содержит значения мусора в двух текселях.

Я пытался жестко закодировать данные, отправленные на этот конкретный уровень MIPMAP, но это не имеет никакого эффекта. Даже дошел до того, что перекодировал эту функцию, происходит то же самое. Я пропустил какую-то инициализацию? Я использовал неправильную функцию OpenGL? Я попал в одну из этих так называемых ловушек? Может ли это быть ошибка компилятора / opengl ..?

Любой намек на то, что может быть не так, будет очень кстати.

РЕДАКТИРОВАТЬ 1: Сегодня я попытался изменить формат текстуры на обычный, используя GL_RGBA. Повреждение mipmap больше не происходит, но теперь моему mipmap требуются все 4 цветовых канала для хранения, когда мне нужен только один.
Есть ли какая-либо несовместимость между mipmaps и GL_R8 / GL_RED?

1

Решение

Вы смотрели на glPixelStore? Похоже, что есть опция GL_UNPACK_ALIGNMENT, которая может влиять на то, как загружаются данные. В ней говорится, что начальное значение равно 4, что приведет к переносу вашей второй строки в другое место для вашего конкретного случая. Не уверен, почему он будет работать в режиме отладки, но не в этом случае, хотя.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]