Главная » Статьи » Языки программирования » С# |
Введение в меши---------------------------------------------------------------------------------------------------------------------------- Приступать к изучению этого материала желательно после знакомства с уроком: С исходного кода этого урока мы и начнем. Также для работы понадобятся некоторые файлы, которые можно скачать здесь. ---------------------------------------------------------------------------------------------------------------------------- В 3D графике мешем является любой рисуемый трехмерный объект. Получил он свое название от английского mesh (сетка), потому что трехмерный объект состоит из точек, вершин, соединенных линиями, в результате выглядит как сеть. С простыми мешами мы уже работали на предыдущих уроках, создавая куб.
//Создаем куб TEntity cube = LE.CreateCube();
Здесь созданный куб присваивался переменной, имеющей тип TEntity. Но ничто не мешает нам явно указать, что это меш, подставив тип TMesh.
//Создаем куб TMesh cube = LE.CreateCube();
Постольку TEntity является базовым для TMesh, никаких проблем в коде такое переименование не вызовет, а мы будем точно знать, что работаем с мешем. Помимо создания графических примитивов, вроде куба, Leadwerks engine позволяет загружать ранее созданные с помощью 3D редакторов меши из файлов или же собирать их вручную из вершин и полигонов. Изучением всех этих возможностей мы сейчас и займемся. Leadwerks Engine умеет загружать такие форматы трехмерной графики: OBJ, MD3, 3DW, GMF. Разработчики движка рекомендуют GMF. Распакуйте из указанной в шапке этой статьи ссылки файлы и поместите их в свой проект к исполняемому файлу. В архиве находятся 4 файла:
Чтобы загрузить box.gmf нужно добавить в код перед главным циклом следующую функцию:
//Загружаем меш из файла TMesh cube2 = LE.LoadMesh("box.gmf");
Будьте осторожны. Если вы случайно поставите функцию загрузки в главный цикл, то меш будет загружаться в каждом кадре, игра начнет тормозить и, в конце концов, повиснет. Скомпилировав и запустив программу, мы увидим следующее: Кроме уже имеющегося вращающегося куба появился еще один. Получилась интересная фигура, но такое совмещение нам не нужно. Сдвинем немного вращающийся куб, добавив в код сразу после его создания функцию изменения позиции меша:
LE.PositionEntity(cube, LE.Vec3(-2,0,0));
Теперь объекты не накладываются друг на друга: Хватит уже наблюдать за невзрачными серыми кубиками, пора делать их красивее. Для этого загрузим файл материалов brick.mat.
// Загружаем материал TMaterial mat = LE.LoadMaterial("brick.mat");
Материалы в движке представлены типом TMaterial. И применяем его на оба наших куба, не забыв при этом проверить, действительно ли материал загрузился:
if (mat!=null) { //Применяем материал к мещам LE.PaintEntity(cube, mat); LE.PaintEntity(cube2, mat); }
Если вы все сделали правильно, то при запуске вас ждет такая картина: Ну и весь код, который имеется на текущий момент:
class Program { static void Main(string[] args) { // подключение dll движка LE.Initialize(); //Создание окна для вивода графики LE.Graphics(640, 480, 0, 0, LE.GRAPHICS_BACKBUFFER + LE.GRAPHICS_DEPTHBUFFER); //Создаем мир. Это делается в первую очередь. LE.CreateWorld(); //Создаем камеру TEntity cam = LE.CreateCamera(); // Устанавливаем координаты камеры LE.MoveEntity(cam, LE.Vec3(0, 0, -5)); //Создаем куб TMesh cube = LE.CreateCube(); LE.PositionEntity(cube, LE.Vec3(-2,0,0));
//Загружаем меш из файла TMesh cube2 = LE.LoadMesh("box.gmf");
// Загружаем материал TMaterial mat = LE.LoadMaterial("brick.mat"); if (mat!=null) { //Применяем материал к мещам LE.PaintEntity(cube, mat); LE.PaintEntity(cube2, mat); }
//Создаем источник света TEntity light = LE.CreateSpotLight(); //устанавливаем позицию LE.PositionEntity(light, LE.Vec3(2, 2, -2)); LE.RotateEntity(light, LE.Vec3(45, 45, 0));
//создаем буфер TBuffer buffer = LE.CreateBuffer(800, 600, LE.BUFFER_COLOR0 | LE.BUFFER_DEPTH | LE.BUFFER_NORMAL);
//Создаем куб TMesh ground = LE.CreateCube(); //Меняем размеры и позицию LE.ScaleMesh(ground, LE.Vec3(10, 0.1f, 10)); LE.PositionEntity(ground, LE.Vec3(0, -2, 0));
//Визуализация источников света // LE.DebugLights(1);
//Главный цикл while (!LE.KeyHit(Keys.KEY_ESCAPE)) // пока не нажата ESCAPE { //Вращаем куб LE.TurnEntity(cube, LE.Vec3(0.5f)); //Обновляем мир LE.UpdateWorld(1);
//Сделать созданный буфер активным. LE.SetBuffer(buffer); //Рисуем мир LE.RenderWorld(LE.RENDER_ALL); //Деактивировать свой буфер, вернув предыдущий LE.SetBuffer(LE.BackBuffer()); //Провести расчет и отрисовку изображения на основе своего буфера LE.RenderLights(buffer);
//Переключаем буфер LE.Flip(1); } //Отключаем движок и выгружаем dll из памяти LE.Terminate(); } }
Ручное создание мешей Ну а теперь приступим к довольно сложной теме – созданию мешей вручную. В реальных приложениях она не особо затребована, предпочитают пользоваться готовыми мешами, но все же бывают ситуации, что делать это приходится. Например нужно немного изменить существующий меш, также таким способом в играх создается след от взмаха оружием, генерируется случайный ландшафт и многое другое. Как вы уже знаете, меш строится из точек называемых вершинами(или вертексами), три таких вершины образуют плоскость - полигон. У полигона имеются такие параметры как текстурные координаты, используемые при наложении текстур, и нормаль – перпендикуляр к плоскости полигона, указывающий направление отражения света. Более подробное объяснение терминов 3d графики советую поискать в интернете. Так вот, самое сложное в ручной генерации – правильно задать все вершины с их параметрами. Для начала сдвинем загруженный куб, чтобы он не загораживал обзов.
LE.PositionEntity(cube2, LE.Vec3(2, 0, 0));
Теперь создадим меш.
//Создаем пустой меш TMesh cubScratch = LE.CreateMesh();
Этот меш полностью пуст, и не имеет никакой информации для отображения. Необходимо в меше создать поверхность (surface), к которой будут добавляться вершины и применятся материалы. Меш может содержать несколько поверхностей. Все полигоны одной поверхности используют один материал и рисуются одним пакетом за одно обращение к GPU.
//создаем поверхность TSurface surf = LE.CreateSurface(cubScratch);
Теперь добавим к поверхности вершины:
//Добавляем вершины LE.AddVertex(surf, LE.Vec3(-0.5f, 0, 0)); LE.AddVertex(surf, LE.Vec3(0.5f, 1, 0)); LE.AddVertex(surf, LE.Vec3(0.5f, 0, 0));
Вершина это всего лишь точка, поэтому она задается тремя координатами Vec3(x, y, z). Далее объединяем вершины в полигон:
// Создаем полигон LE.AddTriangle(surf, 0, 1, 2);
Эта функция принимает номер вершины. Вершины нумеруются в порядке их создания, отсчет начинается от 0. После редактирования меша нужно вызвать функцию UpdateMesh. //Обновляем меш LE.UpdateMesh(cubScratch);
Эта функция обновляет вспомогательные внутренние данные меша, например такие как ограничивающий прямоугольник. Запустив код мы увидим невзрачный треугольник.
Применим к созданному мешу загруженный ранее материал и запустим программу.
LE.PaintEntity(cubScratch, mat);
Почти ничего не изменилось, разве что цвет треугольника, а вот красивой текстуры кирпича нет. Это потому, что меш не имеет текстурных координат и нормалей. Добавьте этот код перед обновлением созданного меша:
//Добавляем нормали LE.SetVertexNormal(surf, 0, LE.Vec3(0, 0, -1)); LE.SetVertexNormal(surf, 1, LE.Vec3(0, 0, -1)); LE.SetVertexNormal(surf, 2, LE.Vec3(0, 0, -1)); // Добавляем текстурные координаты LE.SetVertexTexCoords(surf, 0, LE.Vec2(0, 1)); LE.SetVertexTexCoords(surf, 1, LE.Vec2(1, 0)); LE.SetVertexTexCoords(surf, 2, LE.Vec2(1, 1));
Нормали в движке представлены трехмерным вектором, так как размещаются в трехмерном пространстве, а текстурные координаты двухмерным, поскольку используются для наложения плоских двухмерных текстур. Вершина, для которой они применяются, задается порядковым номером, как и при создании полигона. После внесенных изменений текстура будет наложена правильно.
Далее мы можем полностью построить куб. Для этого понадобится 24 вершины. Код довольно большой и однообразный. Главное правильно задать координаты. Его я приводить здесь не буду, скачивайте по этой ссылке. После его запуска можно увидеть три вращающиеся кирпичных куба. Я добавил всем код вращения.
На скриншоте можно увидеть три одинаковых куба, но все они были созданы разными способами. Первый – функцией создания примитивов, второй – вручную из вершин, третий был загружен из файла, созданного в 3d редакторе. | |
Просмотров: 883 | | |
Всего комментариев: 0 | |