VR
Virtual Reality On-line   OpenGL
Новости   |     Журнал    |    Хаkер   |     Магазин   |   Проекты
[   Вход    ]
[Kарта сайтa]
[ Download  ]
[  Конкурс  ]
[  Анекдоты ]
[  Ссылки   ]
[  Реклама  ]
[ Почтальон ]
[ О проекте ]






TopList
OpenGL+Delphi.
Работа с текстурами
:

Сегодня нам предстоит изучить достаточно сложный материал - текстуры. Мы научимся их загружать и натягивать на объекты. Работать с текстурами, это тебе не шубу в трусы запихивать. Приготовься к достаточно сложной работе.
Logo
Рис 1. Результат

Посмотри на рисунок 1. Здесь ты можешь увидеть результат сегодняшней работы. Я не смог подобрать более удачную позицию, но если ты запустишь пример, то сможешь увидеть все прелести текстуры. Для этого я сделал сферу вращающейся.

Как ты видишь, для примера используется сфера обтянутая текстурой. В качестве текстуры я использую системную иконку, так что ты сегодня научишься ещё и превращать иконы в bmp формат. Я не буду объяснять всю прогу, а остановлюсь только на том, что относится к текстуре.

Теперь бросим свой зоркий взгляд на функцию рисования:

procedure TForm1.FormPaint(Sender: TObject);
var
 ps:TPaintStruct;
begin
 BeginPaint(Handle,ps);
 glClearColor(0,0,0,1);

 glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

 glEnable(GL_DEPTH_TEST);

 glPushMatrix;

 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
 glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
 glTexImage2d(GL_TEXTURE_2D,0,3,TextureW,TextureH,0,GL_RGB,
      GL_UNSIGNED_BYTE,Texture^);
 glEnable(GL_TEXTURE_GEN_S);
 glEnable(GL_TEXTURE_GEN_T);
 glEnable(GL_TEXTURE_2D);
 glHint(GL_PERSPECTIVE_CORRECTION_HINT,GL_NICEST);
 gluQuadricTexture(quadObj,GL_TRUE);

 glTranslatef(TX,TY,0);
 glRotatef(RX,1,0,0);
 glRotatef(RY,0,1,0);
 glRotatef(RZ,0,0,1);
 gluSphere(quadObj,2.7, 15, 10);

 TX:=TX+SX;
 TY:=TY+SY;
 if (TX<-10) or (TX>10) then
  SX:=-SX;
 if (TY<-10) or (TY>10) then
  SY:=-SY;

 glDisable(GL_TEXTURE_2D);
 glPopMatrix;
 glDisable(GL_DEPTH_TEST);

 glFlush();
 swapBuffers(dc);
 EndPaint(Handle,ps);
end;

Посмотри внимательно на эту процедуру. Большинство тебе должно быть уже понятно.

glTexParameteri - устанавливает параметры текстуры. Первый параметр - тип, который может быть GL_TEXTURE_1D или GL_TEXTURE_2D. Второй параметр - символическое имя параметры, который нужно установить. Мы можем изменять: GL_TEXTURE_MIN_FILTER, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T и GL_TEXTURE_BORDER_COLOR . Третий параметр - значение, которое мы хотим установить, указанному в предыдущем параметре. Может не совсем понятно, но сейчас всё будет ясно. Давай рассмотрим каждый параметр в отдельности:

GL_TEXTURE_MIN_FILTER - устанавливает тип функции, которая будет использоваться при уменьшении текстуры. Если ты решил изменить этот параметр, то ты должен указать GL_TEXTURE_MIN_FILTER вторым в функции glTexParameteri. В этом случае, третий параметр сможет принимать значения:

  • GL_NEAREST - возвращает значение элемента текстуры, который является самым близким.
  • GL_LINEAR - возвращает среднее значение из четырёх ближайших к центру тестируемого пиксела.
  • GL_NEAREST_MIPMAP_NEAREST - выбирает ближайший MIPMAP и дальше использует тип NEAREST.
  • GL_LINEAR_MIPMAP_NEAREST - выбирает ближайший MIPMAP и дальше использует тип LINEAR.
  • GL_NEAREST_MIPMAP_LINEAR - выбирает два MIPMAP и дальше использует тип NEAREST.
  • GL_LINEAR_MIPMAP_LINEAR - выбирает два MIPMAP и дальше использует тип LINEAR.

    GL_TEXTURE_MAG_FILTER - устанавливает функцию используемую при увеличении текстуры. Если ты решил её изменить, то ты должен установить GL_TEXTURE_MAG_FILTER вторым параметром в glTexParameteri, а третий сможет принимать значения:

  • GL_NEAREST
  • GL_LINEAR

    GL_TEXTURE_WRAP_S - устанавливает повторения текстуры по координате S. Может принимать значения:

  • GL_CLAMP - запрещает повторение текстуры. Одна её копия будет натянута на весь объект.
  • GL_REPEAT - разрешает повторение текстуры.

    GL_TEXTURE_WRAP_Т - то же самое, что и GL_TEXTURE_WRAP_S, только для координаты Т. Возможные значения третьего параметра те же.

    GL_TEXTURE_BORDER_COLOR - устанавливает цвет обрамления текстуры. При этом параметре, третий сможет принимать значение массива из четырёх значений, которые интерпретируются как цвет (RGBA). Пор умолчанию (0,0,0,0).

    Теперь перейдём к функции glTexEnvf. Она устанавливает параметры среды текстуры. Первый параметр должен быть GL_TEXTURE_ENV. Второй должен быть GL_TEXTURE_ENV_MODE. Третий может принимать значения GL_MODULATE, GL_DECAL или GL_BLEND. Я использую второй параметр, а ты можешь попробовать другие и посмотреть на результат.

    Функция glTexImage2d устанавливает 2D текстуру. Первый параметр должен быть GL_TEXTURE_2D. Второй параметр - уровень детализации текстуры (0 - основной). Третий - количество цветовых компонент в текстуре (может быть 1,2,3 или 4). Дальше идёт ширина и высота. Дальше идёт обрамление (может быть 0 или 1). Я использую 0, чтобы не было никаких обрамлений. Далее - формат, в котором хранятся цветовые данные в массиве. Здесь могут быть значения GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE или GL_LUMINANCE_ALPHA. Предпоследний параметр - тип в котором хранятся цветовые данные (может быть GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT или GL_FLOAT). Последний параметр - указатель на массив текстуры.

    Надо заметить, что в качестве последнего параметра должна передаватся реальная ссылка на текстуру. Прежде чем вызывать glTexImage2d, текстура должна быть уже загружена и подготовлена в этой переменной. Чуть позже я покажу, как загружается текстура.

    После всех этих настроек, можно включить текстуру. Я это дулаю с помощью:

     glEnable(GL_TEXTURE_GEN_S);
     glEnable(GL_TEXTURE_GEN_T);
     glEnable(GL_TEXTURE_2D);
    

    Первые две необязательны. Они просто включают использование определённых функций текстуры. Я их привёл только для примера, и в большинстве случаев они вам не понадобятся. Последний непосредственно включает показ текстуры. Теперь, все объекты которые мы будем рисовать, будут обтянуты выбранной текстурой. Это будет происходить, пока мы не отключим текстуру с помощью glDisable(GL_TEXTURE_2D) .

    Всё остальное должно быть понятно. Так что давай ещё рассмотрим процедуру для загрузки текстуры из системной иконки.

    procedure TForm1.GetTexture;
    var
     BMInfo      :TBitmapInfo;
     I,ImageSize :Integer;
     Temp        :Byte;
     Bitmap      :Graphics.TBitmap;
     TempImage   :TBitmap;
     MemDC       : HDC;
    begin
     //Подготавливаю переменные, для работы с картинками.
     Bitmap:=TBitmap.Create;
     TempImage:=TBitmap.Create;
     TempImage.Width:=32;
     TempImage.Height:=32;
     //Прорисовываю системную иконку (Icon) в TempImage
     //Если захочешь использовать текстуру из BMP файла
     //то можно его напрямую засунуть в TempImage.
     //Для этого достаточно написать TempImage.LoadFromFile('filename.bmp');
     TempImage.Canvas.Draw(0,0,Icon);
     //Определяю ближайшие размеры текстуры которые воспримет OpenGL.
     Bitmap.Width:=RoundUpToPowerOf2(TempImage.Width);
     Bitmap.Height:=RoundUpToPowerOf2(TempImage.Height);
     //Копирую текстуру из TempImage в Bitmap с учётом размеров 
     //воспринимаемых OpenGL
     Bitmap.Canvas.CopyRect(Rect(0,0,Bitmap.Width,Bitmap.Height), 
            TempImage.Canvas, Rect(0,0,32,32));
     //Создаю контекст в памяти.
     MemDC:=CreateCompatibleDC(0);
     try
      with bitmap do
       begin
        ImageSize:=bitmap.Width*bitmap.Height;
        TextureW:=bitmap.Width;
        TextureH:=bitmap.Height;
    //Выделяю память для переменной Texture, в которой будет
    //хранится преобразованная текстура. Обрати внимание, как она
    //объявлена.
        GetMem(Texture,ImageSize*3);
        MemDC:=CreateCompatibleDC(0);
        FillChar(BMInfo,SizeOf(BMInfo),0);
    //Заполняю BMInfo информацией о текстуре.
        With BMInfo.bmiHeader do
         begin
          biSize:=sizeof(TBitmapInfoHeader);
          biBitCount:=24;
          biWidth:=bitmap.Width;
          biHeight:=-bitmap.Height;
          biPlanes:=1;
          biCompression:=BI_RGB;
         end;
    //Копирую данные из Bitmap в Texture
        GetDIBits(MemDC,Bitmap.Handle,0,bitmap.Height,
            Texture,BMInfo,DIB_RGB_COLORS);
      {$R-}
    //Запускаю цикл, в котором меняются местами цветовые
    //компоненты красного и голубого т.е. идёт перевод из RGB в BGR
        for i:=0 to ImageSize-1 do
         begin
          Temp:=Texture^[i*3];
          Texture^[I*3]:=Texture^[I*3+2];
          Texture^[I*3+2]:=Temp;
         end;
      {$R-}
        glPixelStorei(GL_UNPACK_ALIGNMENT,0);
        glPixelStorei(GL_UNPACK_ROW_LENGTH,0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS,0);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);
       end;
     finally
    //Освобождаю всё не нужное.
      Bitmap.Free;
      TempImage.Free;
      DeleteDC(MemDC);
     end;
    end;
    

    Я не буду её расписывать, потому что она не совсем относится к OpenGL, но я постарался снабдить текст комментариями, чтобы можно было разобраться. Обязательно посмотри на них, там я описал много интересного. Для большей ясности я дам ещё несколько заметок:

  • Формат изображения нужного OpenGL очень похож на BMP. Только в BMP используется цвет RGB (красный, зелёный, голубой), а в OpenGL используется BGR (голубой, зелёный, красный). Это значит, что нам нужно каждый третий байт цвета поменять местами с первым.
  • У картинки должно быть определённое отношение ширины к высоте (ширина=2^n + 2, а высота=2^m + 2. Двойку нужно прибавлять при использовании обромлений). Чтобы не забивать особо голову этими функциями я написал небольшую функцию, которая поможет нам в определёнии размеров, так что используй её в своих творениях:

    function TForm1.RoundUpToPowerOf2(Value: Integer): Integer;
    var
      LogTwo : Extended;
    begin
     LogTwo:=log2(Value);
     if Trunc(LogTwo) < LogTwo then
      Result:=Trunc(Power(2,Trunc(LogTwo)+1))
     else
      Result:=value;
    end;
    

    На сегодня всё. Можешь качать и играться с исходниками.

     Исходники примера забирай здесь Заголовочные файлы возьми на моей страничке в разделе "Полезности".


  • Copyright©: Horrific aka Флёнов Михаил
    Design by FMk group©