netlib.narod.ru | < Назад | Оглавление | Далее > |
Класс 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; }
Альтернативным способом текстурирования ландшафта является программное вычисление текстуры; это означает, что мы создаем «пустую» текстуру и вычисляем цвет каждого ее текселя в коде на основании некоторых предопределенных параметров. В нашем примере таким параметром является высота вершины ландшафта.
Программная генерация текстуры выполняется в методе 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 | < Назад | Оглавление | Далее > |