Пропадает фоновая картинка
Как обычно загружаю картинку в формате bmp, но большого размера (это карта города).
image1 = auxDIBImageLoad("карта.bmp");
glRasterPos2d(0,0);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glPixelZoom(1.0, 1.0);
glDrawPixels(image1->sizeX, image1->sizeY,
GL_RGB, GL_UNSIGNED_BYTE,
image1->data);
Прекрасно все отображается.
Далее в программе предусмотрено панарамирование путем перемещения мыши при нажатой средней кнопке (как в автокаде). Этого я достигаю путем изменения параметров функции gluLookAt(), т.е. двигаю изображение.
Так вот, когда левый нижний угол картинки выходит за пределы экрана, картинка просто пропадает с экрана. Как с этим бороться. Хотелось бы достигнуть такого же эффекта как в Автокаде при загрузке и работе с фоновыми изображениями. Спасибо.
Технология известна.
1. Разбиваешь картинку на небольшие фрагменты, например 256x256. Строишь для каждого фрагмента пирамиду mipmap. Сохраняешь это все в каком-либо виде. Для упрощения понимания и обработки, я бы сохранил каждый фрагмент с его мипмапами в отдельном файле. Тем более, если проект некоммерческий и "для внутреннего пользования", а доработать это в некую БД можно потом. Даже с компрессией фрагментов. ;)
2. Строишь quadtree. Структура позволит загружать только те участки карты, которые надо отобразить.
Ну, а движочек простой. По frustum culling определяешь фрагменты, попавшие в зону видимости и рендеришь их, с соответствующим LOD из массива mipmap каждого фрагмента.
Излишне говорить, что в этом случае карта может быть сколь угодно большая, и скорость при её обработке останется высокой. Главное, продумать удобную структуру для хранения и обработки каждого фрагмента изображения.
Полного исходника нет, но отдельные участки кода, как например, mipmapping для изображения, построение quadtree и работа с камерой - в сети найти нетрудно.
P.S. Это один из вариантов, применяемый в игрульках и т.д. Альтернативы тоже есть, но этот, имхо, самый простой для понимания и реализации вариант.
P.P.S. Объяснил я, конечно, фантастично. :D Особенно, про пирамиду mipmap'ов.
Пиши, чуть - что.
upd: Писал не так давно нечто подобное для телевизионщиков. Попросили сделать плавное перемещение между двумя достаточно удаленными участками карты. Было реализовано так, что камера от строго вертикального положение наклонялась и с ускорением перемещалась к другой точке. Типа, пролет над картой. Там, правда, еще модельки домов, деревьев и прочих объектов были. Вот именно по такой схеме и сделано. Достаточно эффектно выглядело, а кода добавилось немного. Да и то, простой - как мыло хозяйственное. :)
Создает файлы с текстурами пирамиды, на основе файла с исходной текстурой. Режим текстуры RGB, компрессия соответственно - GL_COMPRESSED_RGB_S3TC_DXT1_EXT. Используются библиотеки GLEW и DevIL.
{
ILuint handle;
ilGenImages( 1, &handle );
ilBindImage( handle );
ILboolean ilResult = ilLoadImage( filename );
if (!ilResult)
return -1;
GLint tex_max_size;
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &tex_max_size );
ILint width = ilGetInteger( IL_IMAGE_WIDTH );
ILint height = ilGetInteger( IL_IMAGE_HEIGHT );
if ((width > tex_max_size) || (height > tex_max_size))
return -2;
GLuint texture_id;
glGenTextures( 1, &texture_id );
glBindTexture( GL_TEXTURE_2D, texture_id );
int i = 0;
GLubyte* texture;
GLint compressed, tex_size;
while (true)
{
std::stringstream ss;
ILubyte* data = ilGetData();
glTexImage2D( GL_TEXTURE_2D, i, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGetTexLevelParameteriv( GL_TEXTURE_2D, i, GL_TEXTURE_COMPRESSED_ARB, &compressed );
if (compressed)
glGetTexLevelParameteriv( GL_TEXTURE_2D, i, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &tex_size );
else
{
tex_size = width * height * 3;
ss << "un";
}
texture = (GLubyte*)malloc( tex_size );
if (compressed)
glGetCompressedTexImage( GL_TEXTURE_2D, i, texture );
else
glGetTexImage( GL_TEXTURE_2D, i, GL_RGB, GL_UNSIGNED_BYTE, texture );
ss << "pack_" << i << "." << filename << ".raw";
std::ofstream out( ss.str().c_str() );
out.write( (const char*)texture, tex_size );
out.close();
free( texture );
if (!(width /= 2) || !(height /= 2))
break;
else
i++;
ilResult = iluScale( width, height, 1 );
if (ilResult != IL_NO_ERROR)
return (int)ilResult;
}
glDeleteTextures( 1, &texture_id );
ilDeleteImages( 1, &handle );
return 1;
}
Примечание: не работает, если размер исходной текстуры больше, чем размер поддерживаемый драйвером и картой. Ну, и проверка возможности non_power_of_two для текстур и прочего, производится до вызова функции.