Файлы к лабораторной работе Вы можете скачать здесь.
Для сложных объектов нерационально задавать их координаты
и индексы в программном коде. Разумнее с помощью специальных
инструментов заранее подготовить данные объекта в отдельном
файле, а управление этими данными организуется приложением.
обычно называют X-файлом по
его расширению.
В управляемом есть класс Microsoft.,
который находится в библиотеке Microsoft.
Этот класс обеспечивает загрузку и управление X-файлами.
Программные экземпляры этого класса с загруженными из файлов
графическими данными называются Mesh-объектами.
Объекты Mesh могут использоваться для сохранения любого
типа графических данных, но в основном используются для формирования
сложных моделей. Технология Mesh увеличивает эффективность
рендеринга отображаемых объектов за счет встроенных в класс Mesh методов. Все Mesh -объекты имеют вершинный и индексный
буферы, а также буфер атрибутов.
Попробуем вначале применить Mesh -объект
для рисования 9 вращающихся кубов, чтобы ознакомиться
с возможностью его применения. В дальнейшем Mesh -объекты
будем использовать для рендеринга более сложных фигур.
Выберите
каталог для размещения нового проекта и создайте пустой
проект C# с именем RenderMesh
Выполните
команду меню Project/Add Reference и добавьте
к проекту ссылки на следующие библиотечные сборки .NETSystem.dllSystem.Drawing.dllSystem.Windows.Forms.dllMicrosoft.DirectX .dllMicrosoft.DirectX .Direct3D .dllMicrosoft.Directx .Direct3DX.dllПримечание. В трех последних сборках выбирайте более свежие версии.
Здесь мы добавили ссылку на новую библиотеку, расширяющую и содержащую класс Mesh.
Добавьте
к проекту файл Form3.cs из
лабораторной работы №13 -
RenderBest,
выполнив команду Project/Add Existing Item
В
панели Solution Explorer переименуйте файл Form3.cs на
Form1.cs
Вызовите
комбинацией клавиш Ctrl-H окно
замены, настройте его в соответствии со снимком и замените
все вхождения Form3 на Form1 для
всего проекта, щелкнув на кнопке Replace All.
Точно также выполните замену пространств имен с RenderBest на RenderMesh,
чтобы все соответствовало между собой
Обратите внимание, что мы не добавляем в проект using -директиву
для новой библиотеки Microsoft.,
потому что она расширяющая и в ней используется пространство
имен Microsoft.,
которое уже подключено в нашем проекте.

Отключите
в приложении консольное окно через команду меню Project/RenderMesh
Properties, установив во вкладке Application опцию Output type в значение Windows
Application
Постройте
проект, чтобы убедиться в работоспособности данной заготовки.
Результат должен соответствовать варианту Form3 лабораторной
работы №13Теперь мы уберем из полученной заготовки все лишнее, что
не понадобится при использовании Mesh -объектов.
Учитывая, что Mesh -объект имеет свои встроенные
вершинный и индексный буферы и сам определяет свойства формата
вершин, удалим соответствующий код из заготовки приложения.
Далее мы будем приводить секции кода, выделенные
красным цветом, именно их необходимо удалять
из заготовки приложения. Для быстрого редактора
оболочки.
Найдите
в коде класса Form1 описание ссылочных переменных вершинного
и индексного буфера и удалите ихprivate Device device = null;
private VertexBuffer vb = null;
private IndexBuffer ib = null;
Отредактируйте
функцию InitializeGraphics(), удалив из нее код, связанный
с вершинным и индексным буферомpublic void InitializeGraphics()
{
// Создание объекта и настройка параметров представления
// Создать объект параметров представления
PresentParameters presentParams = new PresentParameters();
// Установить оконный режим
presentParams.Windowed = true;
// Сбрасывать содержимое буфера, если он не готов к представлению
presentParams.SwapEffect = SwapEffect.Discard;
// Настройка буфера глубины для параметров устройства
presentParams.EnableAutoDepthStencil = true;
presentParams.AutoDepthStencilFormat =
Microsoft.DirectX.Direct3D.DepthFormat.D16;
// Создать объект устройства и сохранить ссылку на него
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
// Создать вершинный буфер
vb = new VertexBuffer(typeof(CustomVertex.PositionColored),
8,
device,
Usage.Dynamic | Usage.WriteOnly,
CustomVertex.PositionColored.Format,
Pool.Default);
// Регистрация события Created вершинного буфера
vb.Created += new EventHandler(vb_Created);
// Принудительный вызов создания треугольника
// и заполнения вершинного буфера при первом
// создании формы
vb_Created(vb, null);
// Создать индексный буфер для координат вершин куба
ib = new IndexBuffer(typeof(short),
indices.Length,
device,
Usage.WriteOnly,
Pool.Default);
// Регистрация события Created индексного буфера
// Код написать вручную (для создания обработчика)!!!
ib.Created += new EventHandler(ib_Created);
// Принудительный вызов обработчика при первом запуске
ib_Created(ib, null);
}
Удалите
целиком функцию vb_Created() -обработчик события
повторного заполнения вершинного буфераvoid vb_Created(object sender, EventArgs e)
{
// Определить внутреннюю ссылку на вершинный буфер
VertexBuffer buffer = (VertexBuffer)sender; // Явное приведение типов
// Создать локальный массив структур непреобразованных координат
CustomVertex.PositionColored[] verts =
new CustomVertex.PositionColored[8];
// Задать параметры вершин куба в соответствии с рисунком
//
verts[0] = new CustomVertex.PositionColored(-1.0F, 1.0F, 1.0F, Color.Purple.ToArgb());
verts[1] = new CustomVertex.PositionColored(-1.0F, -1.0F, 1.0F, Color.Red.ToArgb());
verts[2] = new CustomVertex.PositionColored(1.0F, 1.0F, 1.0F, Color.Blue.ToArgb());
verts[3] = new CustomVertex.PositionColored(1.0F, -1.0F, 1.0F, Color.Yellow.ToArgb());
verts[4] = new CustomVertex.PositionColored(-1.0F, 1.0F, -1.0F, Color.Gold.ToArgb());
verts[5] = new CustomVertex.PositionColored(1.0F, 1.0F, -1.0F, Color.Green.ToArgb());
verts[6] = new CustomVertex.PositionColored(-1.0F, -1.0F, -1.0F, Color.Black.ToArgb());
verts[7] = new CustomVertex.PositionColored(1.0F, -1.0F, -1.0F, Color.WhiteSmoke.ToArgb());
// Заполнить вершинный буфер данными треугольников
buffer.SetData(verts, 0, LockFlags.None);
}
Удалите
код // Определение индексного массива вершин треугольных примитивов
private static readonly short[] indices = {
2,0,1,// Задняя грань: треугольник 2-0-1 (невидимая сторона - обход левый)
2,1,3,// Задняя грань: треугольник 2-1-3 (невидимая сторона - обход левый)
5,6,4,// Передняя грань: треугольник 5-6-4 (лицевая сторона - обход правый)
5,7,6,// Передняя грань: треугольник 5-7-6 (лицевая сторона - обход правый)
0,5,4,// Верхняя грань: треугольник 0-5-4 (лицевая сторона - обход правый)
0,2,5,// Верхняя грань: треугольник 0-2-5 (лицевая сторона - обход правый)
1,6,7,// Нижняя грань: треугольник 1-6-7 (невидимая сторона - обход левый)
1,7,3,// Нижняя грань: треугольник 1-7-3 (невидимая сторона - обход левый)
0,6,1,// Левая грань: треугольник 0-6-1 (невидимая сторона - обход левый)
0,4,6,// Левая грань: треугольник 0-4-6 (невидимая сторона - обход левый)
2,3,7,// Правая грань: треугольник 2-3-7 (лицевая сторона - обход правый)
2,7,5 // Правая грань: треугольник 2-7-5 (лицевая сторона - обход правый)
};
Удалите
функцию ib_Created() -обработчик события
повторного заполнения индексного буфера// Обработчик события повторного заполнения индексного буфера
void ib_Created(object sender, EventArgs e)
{
IndexBuffer buffer = (IndexBuffer)sender;
buffer.SetData(indices, 0, LockFlags.None);
}
Объект Mesh сам следит за восстановлением вершинного, индексного
буферов и формата вершин всякий раз, когда объект подвергается
рендерингу.
Удалите
из функции DrawCubes() код рисования трех
дополнительных кубовprivate void DrawCubes()
{
//
// Средний ряд
//
//........................................................
// Дополнительные кубы
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0f,
angle / (float)Math.PI / 4.0f) *
Matrix.Translation(
0.0f,
(float)Math.Cos(angle),
(float)Math.Sin(angle));
device.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI / 2.0f,
angle / (float)Math.PI * 4.0f) *
Matrix.Translation(
4.0f,
(float)Math.Sin(angle),
(float)Math.Cos(angle));
device.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0f,
angle / (float)Math.PI / 2.0f) *
Matrix.Translation(
-4.0f,
(float)Math.Cos(angle),
(float)Math.Sin(angle));
device.DrawIndexedPrimitives(
PrimitiveType.TriangleList, 0, 0, 8, 0, indices.Length / 3);
if (flagRotate)
angle += 0.02F;
}
Удалите
в функции OnPaint() секцию кода, подключающую
к устройству вершинный и индексный буферыprotected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target
| ClearFlags.ZBuffer,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Вызов нашей функции установки камеры
SetupCamera();
// Сформировать сцену с учетом параметров
// "положение-нормаль-цвет"
device.BeginScene();
// Установить формат обработки вершин при отображении
device.VertexFormat = CustomVertex.PositionColored.Format;
// Нарисовать треугольник по данным из буфера
device.SetStreamSource(0, vb, 0);
device.Indices = ib;
DrawCubes();
device.EndScene();
// Показать буфер кадра
device.Present();
// Принудительно перерисовать
this.Invalidate();
}
Теперь пришла пора добавить код, реализующий Mesh -технологию.
Добавьте
в класс создание ссылки на Mesh -объект.
Ее можно разместить сразу после создания ссылки устройстваprivate Device device = null;
private Mesh mesh=null;
public void InitializeGraphics()
{
...........................................
}
Имеются три метода создания самого объекта Mesh,
но на данном этапе нам не понадобится ни один из них. Мы
воспользуемся статическим методом создания куба Mesh..
Кроме этого метода класс Mesh содержит еще
ряд перегружаемых методов для создания примитивных объектов:
Microsoft.DirectX .Direct3D .Mesh.Box () - создание кубаMicrosoft.DirectX .Direct3D .Mesh.Cylinder () - создание
цилиндраMicrosoft.DirectX .Direct3D .Mesh.Polygon () - создание
полигонаMicrosoft.DirectX .Direct3D .Mesh.Sphere () - создание сферыMicrosoft.DirectX .Direct3D .Mesh.Torus () - создание тораMicrosoft.DirectX .Direct3D .Mesh.Teapot() - создание
изображения заварочного чайникаЭтими методами мы воспользуемся в лабораторной работе №17 для создания препятствий на дороге.
Добавьте
в конец функции InitializeGraphics() после
кода создания устройства следующую строку генерации кубаpublic void InitializeGraphics()
{
// Создание объекта и настройка параметров представления
// Создать объект параметров представления
PresentParameters presentParams = new PresentParameters();
// Установить оконный режим
presentParams.Windowed = true;
// Сбрасывать содержимое буфера, если он не готов к представлению
presentParams.SwapEffect = SwapEffect.Discard;
// Создать объект устройства и сохранить ссылку на него
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
// Генерация и подключение к устройству куба
// с помощью статического метода класса Mesh
mesh = Mesh.Box(device, 2.0F, 2.0F, 2.0F);
}
Статический метод Mesh. имеет две
public static Microsoft.DirectX .Direct3D .Mesh Box (Microsoft.DirectX .Direct3D .Device
device, float width,
float height, float depth)public static Microsoft.DirectX .Direct3D .Mesh Box (Microsoft.DirectX .Direct3D .Device
device, float width,
float height, float depth,
out Microsoft.DirectX .Direct3D .GraphicsStream
adjacency ) Он создает новый Mesh-объект, который содержит вершины и индексы, необходимые
для рендеринга куба с заданной шириной, высотой и глубиной
(значение 2.0F ). Этот куб того же размера,
что и созданный нами вручную в Form3 лабораторной
работы №13.
Теперь нужно
отобразить Mesh -объект на экране с помощью
функции DrawSubset() экземплярного объекта mesh.
Измените
в функции DrawCubes() все вызовы метода DrawIndexedPrimitives() устройства
на вызовы метода DrawSubset(0) объекта meshprivate void DrawCubes()
{
//
// Средний ряд
//
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0f,
angle / (float)Math.PI / 4.0f) *
Matrix.Translation(0.0f, 0.0f, 0.0f); // По центру
mesh.DrawSubset(0);
//
// .......................................................
//
if (flagRotate)
angle += 0.02F;
}
Обратите внимание на то, сколько много кода мы удалили,
а добавили совсем чуть-чуть. Прямая выгода в использовании Mesh -технологии налицо!
Запустите
приложение - должен получиться такой результат
Итак, мы получили девять вращающихся кубов, но все они оказались
бесцветными. Это происходит потому, что цвета Mesh -объекта
не были определены и, поскольку у нас выключена подсветка
сцены, кубы остались неокрашенными и неосвещенными. Давайте
будем это исправлять. Освещение в устройстве device установлено
по умолчанию, поэтому можно удалить код выключения освещения
или задать соответствующему параметру значение true.
Найдите
в классе функцию SetupCamera() и замените
в секции выключения освещения значение false на true// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 15.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение
device.RenderState.Lighting = true;
}
Запустите
приложение, получится такой результат
Теперь наши вращающиеся кубы превратились в черные. В конце
лабораторной работы №10 говорилось о том,
что не
может освещать объект, не имея нормали к каждой его поверхности.
Нормаль представляет собой
Познакомимся с термином " общее освещение " или " общий
свет ".
Общий свет обеспечивается постоянным источником света для
сцены. При этом все объекты на сцене будут освещены равномерно,
поскольку общее освещение не зависит ни от местоположения
источника, его направленности, ослабления и др. Но несмотря
на свою эффективность, такой свет не позволяет добиться реалистичности
картины. Но на данном этапе мы воспользуемся общим освещением.
Добавьте
в конец функции SetupCamera() строку,
описывающую состояние рендера подсветки// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 15.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение
device.RenderState.Lighting = true;
// Установить красный свет
device.RenderState.Ambient = Color.Red;
}
Общий свет и расцветка в сцене определяются состоянием рендера общего освещения. Здесь мы хотим, чтобы наш общий свет стал красным. Если сейчас запустить приложение, то ничего не изменится - кубы будут черными.
Для того, чтобы правильно вычислял
цвет в отдельных точках на трехмерном объекте, кроме цвета
источника света нужно еще указать, как объект будет отражать
свет определенного цвета. Нам необходимо описать, как поверхность
кубов будет отражать свет от источника. Эту особенность задают
с помощью материалов. Материалы определяют,
каким образом объект будет отражать общий диффузионный свет,
какие участки будут освещены больше или меньше, и отражает
ли объект свет вообще.
Добавьте
в начало функции DrawCubes() секцию кода
создания материалаprivate void DrawCubes()
{
// Создаем материал поверхности отражения
// и добавляем его в устройство
Material boxMaterial = new Material();
boxMaterial.Ambient = Color.White;
boxMaterial.Diffuse = Color.White;
device.Material = boxMaterial;
//
// .................................................
//
if (flagRotate)
angle += 0.02F;
}
Здесь мы создаем новый материал и настраиваем в нем значения общего и диффузионного освещения, выбрав белый цвет. Использование белого означает, что мы отразим весь общий и диффузный свет, падающий на объекты. Затем мы передаем этот материал в устройство для рендеринга.
Запустите
приложение и появятся красные кубы
Если изменить цвет источника общего света, то изменится и цвет кубов. А если изменить цвет материала на отличный от белого, то отражаемый свет будет смесью цвета материала и цвета источника.
Полученные на данном этапе кубы выглядят цветными силуэтами.
Мы не можем различить их центальные вершины и грани. Оказывается,
все зависит от того, как общий свет освещает сцену. Сейчас
отраженный свет вычисляется одинаково для всех вершин в сцене,
независимо от нормали к
Добавьте
в конец функции SetupCamera() следующую
секцию кода// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
100.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 15.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение
device.RenderState.Lighting = true;
// Установить красный свет
device.RenderState.Ambient = Color.Red;
// Настроить общий свет
device.Lights[0].Type = LightType.Directional;
device.Lights[0].Diffuse = Color.White;
device.Lights[0].Direction = new Vector3(0, -1, -1);
device.Lights[0].Commit();
device.Lights[0].Enabled = true;
}
Мы создали источник направленного белого света и задали направление освещения.
Запустите
приложение и убедитесь, что направленые к наблюдателю грани
кубов освещены полностью, а повернутые грани кажутся более
затененными
Попробуйте создать с теми же настройками света изображение заварочного чайника. Для этого:
Замените
в функции InitializeGraphics() создание
куба на код создания заварочного чайникаpublic void InitializeGraphics()
{
// .................................................
//mesh = Mesh.Box(device, 2.0F, 2.0F, 2.0F);
mesh = Mesh.Teapot(device);
}
Постройте
приложение и получите следующую картинку
Некоторые части объекта проступают на передний план из-за того, что ранее мы удалили буфер глубины.
Добавьте
в функцию InitializeGraphics() буфер глубины,
а в функцию OnPaint() флаг существования
буфера глубины, как мы это делали в Form3 лабораторной
работы №13 или будем делать в конце этой
лабораторной работы №14
Запустите
приложение с заварочными чайниками и убедитесь, что буфер
глубины работает
Уберите
код буфера глубины и код заварочного чайника и вновь
включите код генерации кубовОтображение заварочных чайников выглядит вполне реалистичным,
но большинство Mesh -объектов создают художники и редко используются
рассмотренные выше примитивы (куб, тор, сфера и т.д.). Существуют
вспомогательные программы-утилиты, которые позволяют создавать
и сохранять Mesh -объекты в файлах X -форматов. Затем класс Mesh с помощью своих методов может загружать в приложение
эти объекты из файлов и управлять ими. В X -файл можно поместить
все необходимые данные для реалистичного рендеринга объекта,
включая вершинные и индексные данные, информацию о материале
и
Для быстрой и реалистичной обработки трехмерных графических
объектов существуют файлы с программным кодом, который напрямую
работает с графическим устройством. В этих файлах находится
код, который написан на специальном языке, называемом HLSL ( - высокоуровневый язык программирования
для построения теней). Программы, написанные на этом языке,
называются шейдерами,
а файлы, в которых хранятся шейдеры - файлами шейдеров.
Кроме статических методов создания графических
примитивов (куб, тор, ...) в классе Mesh содержатся еще два
статических метода Mesh.FromFile() и Mesh.FromStream(). Эти
методы имеют большое количество перегрузок, но корневые
public static Microsoft.DirectX.Direct3D.Mesh FromFile (
System.String filename , // Источник данных
Microsoft.DirectX.Direct3D.MeshFlags options , // Как нужно загружать данные
Microsoft.DirectX.Direct3D.Device device , // Устройство
Microsoft.DirectX.Direct3D.GraphicsStream adjacency , // Смежные вершины
out Microsoft.DirectX.Direct3D.ExtendedMaterial[] materials , // Сохраненные материалы
Microsoft.DirectX.Direct3D.EffectInstance effects // Файл шейдера для поддержки Mesh-объекта
)
public static Microsoft.DirectX.Direct3D.Mesh FromStream (
System.IO.Stream stream , // Источник данных
System.Int32 readBytes , // Сколько байт загружать из потока
Microsoft.DirectX.Direct3D.MeshFlags options , // Как нужно загружать данные
Microsoft.DirectX.Direct3D.Device device , // Устройство
Microsoft.DirectX.Direct3D.GraphicsStream adjacency , // Смежные вершины
out Microsoft.DirectX.Direct3D.ExtendedMaterial[] materials , // Сохраненные материалы
Microsoft.DirectX.Direct3D.EffectInstance effects // Файл шейдера для поддержки Mesh-объекта
)
Параметр options может быть представлен
поразрядной комбинацией значений. Из множества перегрузок нужно выбирать такой метод загрузки
данных, для которого имеется вся необходимая информация.
Для демонстрации загрузки Mesh -данных из
файла создадим форму Form2
Закройте
все документы текущего редактирования командой оболочки Window/Close All Documents
Через
панель Solution Explorer скопируйте файл Form1.cs и
переименуйте его в файл Form2.cs
Откройте
файлы Form2.cs (в режиме View
Code )
и Form2.designer.cs и
замените в них все вхождения Form1 на Form2 с
помощью окна замены, вызываемого комбинацией клавиш Ctrl-H (окно
замены должно быть настроено в соответствии со снимком:
на поиск вхождений в открытых документах)
Установите
через меню Project/RenderMesh Properties форму Form2 стартовой,
постройте приложение и убедитесь, что форма Form2 сохранила
функциональность Form1Теперь пришла пора добавить в форму Form2 код,
который будет загружать сложный Mesh -объект
из X-файла.
Добавьте
в класс Form2 объявления полей-ссылок
объектов материалов и private Device device = null;
private Mesh mesh = null;
// Ссылки на массивы для загрузки из X-файла
private Material[] meshMaterials;
private Texture[] meshTextures;
public void InitializeGraphics()
{
// .....................................................
}
Создайте
функцию-член класса Form2 для загрузки Mesh -объекта
из файла (аргументом функции будет имя файла). Назовите
функцию LoadMesh(),
она будет возвращать ссылку на загруженный Mesh -объект.// Функция загрузки Mesh-объекта из файла
private Mesh LoadMesh(string file)
{
ExtendedMaterial[] data; // Создаем ссылку на загружаемые данные
// Загружаем объект из файла
Mesh localMesh = Mesh.FromFile(file, MeshFlags.Managed, device, out data);
// Если есть данные - разделяем и сохраняем их
if ((data != null) (data.Length > 0))
{
// Создаем массив материалов
meshMaterials = new Material[data.Length];
// Создаем массив текстур
meshTextures = new Texture[data.Length];
// Заполняем массив материалами и текстурами
for (int i = 0; i < data.Length; i++)
{
meshMaterials[i] = data[i].Material3D;
if ((data[i].TextureFilename != null)
(data[i].TextureFilename != string.Empty))
{
// Структура существует, попробуем ее загрузить
meshTextures[i] = TextureLoader.FromFile(
device, data[i].TextureFilename);
}
}
}
return localMesh;
}
Удалите
из класса функцию DrawCubes() на ее
место вставьте новую функцию рисования объекта DrawMesh()private void DrawMesh()
{
// Вращаем объект
device.Transform.World = Matrix.RotationYawPitchRoll(
angle / (float)Math.PI,
angle / (float)Math.PI * 2.0f,
angle / (float)Math.PI / 4.0f) *
Matrix.Translation(0.0f, 0.0f, 0.0f);
// Загружаем в устройство материал и текстуру поверхности отражения
for (int i = 0; i < meshMaterials.Length; i++)
{
device.Material = meshMaterials[i];
device.SetTexture(0, meshTextures[i]);
mesh.DrawSubset(0);
}
if (flagRotate)
angle += 0.02F;
}
Измените
в функции OnPaint() вызов функции рисованияprotected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Вызов нашей функции установки камеры
SetupCamera();
// Сформировать сцену
device.BeginScene();
DrawMesh();
device.EndScene();
// Показать буфер кадра
device.Present();
// Принудительно перерисовать
this.Invalidate();
}
Чтобы
отображаемый объект не казался слишком большим, замените
в функции SetupCamera() настройки масштаба
изображения камеры следующими значениями// Установка камеры в сцену
private void SetupCamera()
{
//Создание перспективы
device.Transform.Projection = Matrix.PerspectiveFovLH(
(float)Math.PI / 4, // Угол зрения равен 45 градусов
// Форматное соотношение сторон
(float)this.ClientSize.Width / (float)this.ClientSize.Height,
1.0F, // Ближний план
1000.0F); // Дальний план
//Добавление камеры
device.Transform.View = Matrix.LookAtLH(
new Vector3(0, 0, 700.0F), // Положение камеры
new Vector3(), // Положение объекта текущее
new Vector3(0, 1, 0)); // Направление камеры
// Освещение
device.RenderState.Lighting = true;
// Установить красный свет
device.RenderState.Ambient = Color.Red;
// Настроить общий свет
device.Lights[0].Type = LightType.Directional;
device.Lights[0].Diffuse = Color.White;
device.Lights[0].Direction = new Vector3(0, -1, -1);
device.Lights[0].Commit();
device.Lights[0].Enabled = true;
}
Удалите
из функции InitializeGraphics() код генерации
куба и вместо него поставьте вызов функции LoadMesh() загрузки Mesh -объекта
из файлаpublic void InitializeGraphics()
{
// Создание объекта и настройка параметров представления
// Создать объект параметров представления
PresentParameters presentParams = new PresentParameters();
// Установить оконный режим
presentParams.Windowed = true;
// Сбрасывать содержимое буфера, если он не готов к представлению
presentParams.SwapEffect = SwapEffect.Discard;
// Создать объект устройства и сохранить ссылку на него
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
// Генерация и подключение к устройству куба
// с помощью статического метода класса Mesh
mesh = Mesh.Box(device, 2.0F, 2.0F, 2.0F);
// Загрузить Mesh-объект из файла tiny.x
mesh = LoadMesh("tiny.x");
}
В
панели Solution Explorer вызовите контекстное
меню для узла проекта и командой Add/Existing Item добавьте
к проекту из прилагаемого к работе каталога Source файлы tiny.x и Tiny_skin.bmp,
предварительно настроив фильтр окна подкачки
В
панели Solution Explorer выделите одновременно
скопированные оболочкой в проект файлы и щелчкните по пиктограмме Properties, чтобы вызвать для них панель настройки свойств
оболочки
Настройте
панель свойств в соответствии со снимком, чтобы оболочка
при компиляции копировала в каталог bin размещения
сборки самые свежие версии указанных файлов
Запустите
приложение и обратите внимание, что некоторые части объекта
не закрываются передним планомЭто происходит потому, что мы ранее удалили буфер глубины из параметров устройства. Исправим это:
Добавьте
буфер глубины в функцию InitializeGraphics() перед
созданием устройстваpublic void InitializeGraphics()
{
// Создание объекта и настройка параметров представления
// Создать объект параметров представления
PresentParameters presentParams = new PresentParameters();
// Установить оконный режим
presentParams.Windowed = true;
// Сбрасывать содержимое буфера, если он не готов к представлению
presentParams.SwapEffect = SwapEffect.Discard;
// Настройка буфера глубины для параметров устройства
presentParams.EnableAutoDepthStencil = true;
presentParams.AutoDepthStencilFormat =
Microsoft.DirectX.Direct3D.DepthFormat.D16;
// Создать объект устройства и сохранить ссылку на него
device = new Device(0, DeviceType.Hardware, this,
CreateFlags.SoftwareVertexProcessing, presentParams);
// Генерация и подключение к устройству куба
// с помощью статического метода класса Mesh
mesh = Mesh.Box(device, 2.0F, 2.0F, 2.0F);
// Загрузить Mesh-объект из файла tiny.x
mesh = LoadMesh("tiny.x");
}
Добавьте
в функцию OnPaint() флаг очистки устройства
с учетом существования буфера глубиныprotected override void OnPaint(PaintEventArgs e)
{
// Очистить цветом клиентскую область формы
device.Clear(ClearFlags.Target
| ClearFlags.ZBuffer,
System.Drawing.Color.CornflowerBlue,
1.0F, 0);
// Вызов нашей функции установки камеры
SetupCamera();
// Сформировать сцену
device.BeginScene();
DrawMesh();
device.EndScene();
// Показать буфер кадра
device.Present();
// Принудительно перерисовать
this.Invalidate();
}
Запустите
приложение и
полюбуйтесь на сложный вращающийся Mesh -объект,
который мы загрузили из внешнего X-файла 
Сдайте
работу преподавателю
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.