netlib.narod.ru< Назад | Оглавление | Далее >

13.3. Текстурирование

Класс Terrain предоставляет два способа текстурирования ландшафта. Наиболее очевидный способ — загрузить ранее подготовленную текстуру из файла и использовать ее. Показанный ниже метод, реализованный в классе Terrain, загружает текстуру из файла в член данных _tex, являющийся указателем на интерфейс IDirect3DTexture9. Внутри метода Terrain::draw перед визуализацией ландшафта устанавливается текстура _tex.

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

bool Terrain::loadTexture(std::string fileName)
{
     HRESULT hr = 0;

     hr = D3DXCreateTextureFromFile(
                      _device,
                      fileName.c_str(),
                      &_tex);

     if(FAILED(hr))
          return false;

     return true;
}

13.3.1. Процедурный подход

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

Программная генерация текстуры выполняется в методе Terrain::genTexture. Сперва мы создаем пустую текстуру с помощью метода D3DXCreateTexture. Затем мы блокируем текстуру верхнего уровня (помните, что это детализируемая текстура и у нее есть несколько уровней детализации). После этого мы в цикле перебираем тексели и назначаем их цвет. Цвета текселей зависят от высоты вершин квадрата сетки, которому они принадлежат. Идея заключается в том, что низкие участки ландшафта окрашиваются в цвет песчанного пляжа, участки со средней высотой — в цвет травы, а высокие части ландшафта — в цвет снежных вершин. Мы считаем, что высота квадрата это высота его верхнего левого угла.

Назначив цвета всем текселям, мы должны сделать некоторые из них темнее или светлее в зависимости от того, под каким углом солнечный свет (моделируемый с помощью источника направленного света) падает на квадрат ландщафта, соответствующий данному текселю. Все это делается в методе Terrain::lightTerrain, реализация которого будет обсуждаться в следующием разделе.

В конце метода Terrain::genTexture осуществляется вычисление текселей остальных уровней детализируемой текстуры. Это делается с помощью функции D3DXFilterTexture. Вот как выглядит код генерации текстуры:

bool Terrain::genTexture(D3DXVECTOR3* directionToLight)
{
     // Метод программно заполняет текстуру верхнего уровня.
     // Затем выполняется ее освещение. И, в конце, заполняются 
     // остальные уровни детализируемой текстуры с помощью
     // D3DXFilterTexture.

     HRESULT hr = 0;

     // Тексель для каждого квадрата сетки
     int texWidth  = _numCellsPerRow;
     int texHeight = _numCellsPerCol;

     // Создаем пустую текстуру
     hr = D3DXCreateTexture(
            _device,
            texWidth, texHeight, // размеры
            0,                   // создаем полную
                                 // цепочку детализации
            0,                   // использование - нет
            D3DFMT_X8R8G8B8,     // формат 32-разрядный XRGB
            D3DPOOL_MANAGED,     // пул памяти
            &_tex);

     if(FAILED(hr))
          return false;

     D3DSURFACE_DESC textureDesc;
     _tex->GetLevelDesc(0 /* уровень */, &textureDesc);

     // Проверяем, что получена текстура требуемого формата,
     // поскольку наш код заполнения текстуры работает только
     // с 32-разрядными пикселями
     if(textureDesc.Format != D3DFMT_X8R8G8B8)
          return false;

     D3DLOCKED_RECT lockedRect;
     _tex->LockRect(0,           // блокируем верхнюю поверхность
                    &lockedRect,
                    0,           // блокируем всю текстуру
                    0);          // флаги

     // Заполняем текстуру
     DWORD* imageData = (DWORD*)lockedRect.pBits;
     for(int i = 0; i < texHeight; i++)
     {
          for(int j = 0; j < texWidth; j++)
          {
               D3DXCOLOR c;
               // Получаем высоту верхней левой вершины квадрата
               float height = (float)getHeightmapEntry(i, j)/_heightScale;

               // Устанавливаем цвет текселя на основе высоты
               // соответствующего ему квадрата
               if( (height) < 42.5f )       c = d3d::BEACH_SAND;
               else if( (height) < 85.0f )  c = d3d::LIGHT_YELLOW_GREEN;
               else if( (height) < 127.5f ) c = d3d::PUREGREEN;
               else if( (height) < 170.0f ) c = d3d::DARK_YELLOW_GREEN;
               else if( (height) < 212.5f ) c = d3d::DARKBROWN;
               else                         c = d3d::WHITE;

               // Заполняем заблокированный буфер. Обратите внимание, что мы
               // делим шаг на четыре, поскольку шаг измеряется в байтах
               // а одно значение DWORD занимает 4 байта
               imageData[i * lockedRect.Pitch / 4 + j] = (D3DCOLOR)c;
          }
     }
     _tex->UnlockRect(0);

     // Освещаем ландшафт
     if(!lightTerrain(directionToLight))
     {
          ::MessageBox(0, "lightTerrain() - FAILED", 0, 0);
          return false;
     }

     // Заподняем цепочку детализации
     hr = D3DXFilterTexture(
             _tex,   // текстура, для которой заполняются уровни детализации
             0,      // палитра по умолчанию
             0,      // используем в качестве источника верхний уровень
             D3DX_DEFAULT); // фильтр по умолчанию

     if(FAILED(hr))
     {
          ::MessageBox(0, "D3DXFilterTexture() - FAILED", 0, 0);
          return false;
     }
     return true;
}

Обратите внимание, что константы цветов, BEACH_SAND и т.п., определены в файле d3dUtility.h.


netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz