Рассмотрим особенности рисования трехмерных объектов средствами XNA на примере проекта P14_1.
Здесь мы рассматриваем два подхода к выводу трехмерных примитивов. Первый заключается в использовании вершинного буфера и вывода объектов из него, второй – с использованием матриц вершин, которые указываются в качестве одного из параметров при выводе объектов.
В этом примере мы выведем на экран следующие объекты:
В листинге 19.1. вы можете найти код класса Game1 проекта P14_1. Код подробно прокомментирован.
Отметим, что для вывода изображения нам необходимо выполнить следующие шаги:
Установить мировую, проекционную и видовую матрицы.
Создать и настроить объект типа BasicEffect для вывода изображений.
Создать наборы вершин, которые мы будем использовать при выводе
Создать и заполнить вершинный буфер, который нужно будет загрузить в один из элементов коллекции Vertices объекта, используемого для вывода изображений
Вывести изображение из буфера, при необходимости вывести изображения, сгенерированные на основе массивов вершин, не внесенных в вершинный буфер.
Массив вершин может быть интерпретирован по-разному. Например, при интерпретации его в качестве PointList массив выводится в виде списка точек, при интерпретации в качестве TriangleList – как набор треугольников, при интерпретации в качестве TriangleFan – как "веер" из треугольников, одна из вершин которых совпадает, при интерпретации как LineList – в качестве набора линий.
При выводе изображения в методе Draw необходимо очищать экран от предыдущего вывода – иначе он покроется копиями изображений.
Мы используем мировую матрицу для вращения выведенной сцены, модифицируя ее на 1 градус при каждом проходе цикла Update.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace P14_1
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
//Вывод изображений
BasicEffect basicEffect;
//Мировая матрица
Matrix worldMatrix;
//Матрица вида
Matrix viewMatrix;
//Проекционная матрица
Matrix projectionMatrix;
//Вершинный буфер
VertexBuffer vertBuffer;
//Массивы для хранения координат вершин
//Которые используются для вывода изображения
//без использования вершинного буфера
VertexPositionColor[] vert1;
VertexPositionColor[] vert2;
VertexPositionColor[] vert3;
VertexPositionColor[] vert4;
VertexPositionColor[] vert5;
//Переменная для хранения текущего значения
//поворота мировой матрицы
float wM = 0;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
//Настройка матриц
SetMatrix();
//Настройка эффектов вывода
TuneUpEff();
//Создание объектов для вывода
CreateFigures();
}
void SetMatrix()
{
//мировая матрица, содержащая 1 по диагонали
//она не влияет на состояние объекта
worldMatrix = Matrix.Identity;
//матрица вида
//При ее создании задаем следующие параметры
//1 - положение камеры
//2 - направление камеры
//3 - что считать "верхом" для камеры
viewMatrix = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 10.0f), Vector3.Zero, Vector3.Up);
//Находим соотношение сторон пикселей для корректного вывода
//изображений на экран
float aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width / (float)graphics.GraphicsDevice.Viewport.Height;
//Матрица проекции
//При ее создании задаем следующие параметры:
//1 - угол зрения в радианах
//Соотношение сторон пикселей экрана
//Ближний план пространства
//Дальний план пространства
projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), aspectRatio, 1.0f, 19.0f);
}
void TuneUpEff()
{
//Создаем экземпляр класса BasicEffect
//Он используется для вывода изображений - это напоминает
//SpriteBatch при работе с двумерной графикой
basicEffect = new BasicEffect(graphics.GraphicsDevice, null);
//Настраиваем параметры basicEffect
//Освещение
basicEffect.LightingEnabled = true;
basicEffect.EnableDefaultLighting();
//Установка матриц
basicEffect.World = worldMatrix;
basicEffect.View = viewMatrix;
basicEffect.Projection = projectionMatrix;
}
void CreateFigures()
{
//Массив вершин для построения треугольника
VertexPositionColor [] vert = new VertexPositionColor[3];
//Массив для построения линий, расположенных в виде прямоугольника
vert1 = new VertexPositionColor[5];
//Массив для построения второго прямоугольника, расположенного выше, чем
//первый
vert2 = new VertexPositionColor[5];
//Массив для построения линии
vert3 = new VertexPositionColor[2];
//Массив для построения точек со случайными координатами
vert4 = new VertexPositionColor[1000];
//Массив для построения группы треугольников со случайными координатами
vert5 = new VertexPositionColor[200];
//Генераратор случайных чисел
Random rnd = new Random();
//Задаем параметры для построения треугольника
vert[0] = new VertexPositionColor(new Vector3(1.0f, 2.0f, -5.0f), Color.White);
vert[1] = new VertexPositionColor(new Vector3(2.0f, 0.0f, -5.0f), Color.White);
vert[2] = new VertexPositionColor(new Vector3(1.0f, -2.0f, -5.0f), Color.White);
//Задаем параметры для построения прямоугольника
//его центр расположен в начале координат
vert1[0] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, 0.0f), Color.White);
vert1[1] = new VertexPositionColor(new Vector3(-1.0f, 1.0f, 0.0f), Color.White);
vert1[2] = new VertexPositionColor(new Vector3(1.0f, 1.0f, 0.0f), Color.White);
vert1[3] = new VertexPositionColor(new Vector3(1.0f, -1.0f, 0.0f), Color.White);
vert1[4] = new VertexPositionColor(new Vector3(-1.0f, -1.0f, 0.0f), Color.White);
//Задаем параметры для второго прямоугольника - он перпендикулярен первому
//и смещен вверх
vert2[0] = new VertexPositionColor(new Vector3(0.0f, 0.0f, 1.0f), Color.White);
vert2[1] = new VertexPositionColor(new Vector3(0.0f, 0.0f, -1.0f), Color.White);
vert2[2] = new VertexPositionColor(new Vector3(0.0f, 2.0f, -1.0f), Color.White);
vert2[3] = new VertexPositionColor(new Vector3(0.0f, 2.0f, 1.0f), Color.White);
vert2[4] = new VertexPositionColor(new Vector3(0.0f, 0.0f, 1.0f), Color.White);
//Параметры для построения линии
vert3[0] = new VertexPositionColor(new Vector3(2.0f, 2.0f, 2.0f), Color.White);
vert3[1] = new VertexPositionColor(new Vector3(-2.0f, -2.0f, -2.0f), Color.White);
//Генерируем случайные координаты для построения точек
for (int i = 0; i < 1000; i++)
{
//Диапазон координат от -3 до 3
float x = (float)(rnd.NextDouble() - rnd.NextDouble()) * 3;
float y = (float)(rnd.NextDouble() - rnd.NextDouble()) * 3;
float z = (float)(rnd.NextDouble() - rnd.NextDouble()) * 3;
vert4[i] = new VertexPositionColor(new Vector3(x, y, z), Color.White);
}
//Генерируем случайные координаты для построения треугольников
for (int i = 0; i < 200; i++)
{
//Координаты изменяются в пределах от -1 до 1
float x = (float)(rnd.NextDouble() - rnd.NextDouble());
float y = (float)(rnd.NextDouble() - rnd.NextDouble());
//группа треугольников сдвинута на 3 по оси Z
float z = (float)(rnd.NextDouble() - rnd.NextDouble())-3;
vert5[i] = new VertexPositionColor(new Vector3(x, y, z), Color.White);
}
//Создаем вершинный буфер
//При создании указываем графическое устройство, размер буфера и способ работы с буфером
vertBuffer = new VertexBuffer(graphics.GraphicsDevice, 3 * VertexPositionColor.SizeInBytes,BufferUsage.WriteOnly);
//Загружаем в буфер массив вершин vert
vertBuffer.SetData<VertexPositionColor>(vert);
}
protected override void UnloadContent()
{
if (vertBuffer != null)
{
vertBuffer.Dispose();
vertBuffer = null;
}
if (basicEffect != null)
{
basicEffect.Dispose();
basicEffect = null;
}
}
protected override void Update(GameTime gameTime)
{
//Уменьшаем на 1 градус значение поворота матрицы
wM = wM - 1f;
//Модифицируем мировую матрицу
worldMatrix = Matrix.CreateRotationY(MathHelper.ToRadians(wM));
//Меняем мировую матрицу
basicEffect.World = worldMatrix;
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
//Очищаем окно вывода
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
//Устанавиливаем объект VertexDeclaration - он используется для вывода изображения
graphics.GraphicsDevice.VertexDeclaration = new VertexDeclaration
(graphics.GraphicsDevice, VertexPositionColor.VertexElements);
//Устанавливаем в качестве источника для вывода ранее созданный вершинный буфер
graphics.GraphicsDevice.Vertices[0].SetSource(vertBuffer, 0, VertexPositionColor.SizeInBytes);
//Начинаем вывод изображения
basicEffect.Begin();
//Для каждого прохода эффекта в коллекции примененных эффектов
//выведем изображение. В нашем случае вывод осуществляется в 1 проход
foreach (EffectPass CurrentPass in basicEffect.CurrentTechnique.Passes)
{
//Начинаем вывод для текущего прохода
CurrentPass.Begin();
//Выводим треугольник, пользуясь параметрами созданного вершинного буфера
//Тип графического примитива - список треугольников, отсчет от 0 элемента буфера
//Количество треугольников - 1. По умолчанию задняя часть объекта не видна
graphics.GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
//Выводим набор линий для рисования первого прямоугольника, используя
//массив вершин vert1
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineStrip, vert1, 0, 4);
//Выводим второй прямоугольник
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineStrip, vert2, 0, 4);
//Выводим линию - она проходит через начало координат
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineStrip, vert3, 0, 1);
//Выводим группу точек
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.PointList, vert4, 0, 1000);
//Выводим набор треугольников, одна из вершин которых совпадает с начальной точкой
//Количество треугольников на 2 меньше, чем количество вершин, заданных в массиве Vert5
graphics.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleFan, vert5, 0, 198);
//Окончание текущего прохода
CurrentPass.End();
}
//Окончание вывода изображений
basicEffect.End();
base.Draw(gameTime);
}
}
}
На рис. 19.1. вы можете видеть окно проекта P14_1.
(рис 19.1) Окно проекта P14_1Выводя графические примитивы, рассмотренные в предыдущем примере, довольно сложно и трудоемко создавать игровые сцены. Гораздо большими возможностями обладает подход к работе с трехмерной графикой, использующий вывод заранее подготовленных трехмерных моделей. Само по себе создание трехмерных моделей требует немало времени и искусства, для этого применяются специальные программы. В деле создания игр выделяется отдельная группа сотрудников – 3D-моделеров, которые занимаются исключительно созданием трехмерных моделей.
Мы использовали готовую бесплатную трехмерную модель Free Lowpoly Round
Для вывода модели на экран необходимо добавить в проект соответствующие ей ресурсы, в нашем случае – модель в формате .FBX и текстуру в формате .JPG. Далее следует загрузить модель в игру, настроить ее свойства и вывести на экран.
В трехмерной графике существует такое понятие, как Mesh (Сеть, иногда пользуются русской калькой с этого слова – мэш). Трехмерные модели состоят из сетей – линий, соединяющих вершины. Модель может состоять из нескольких взаимодействующих сетей, каждую из которых нужно обработать при выводе модели.
Создадим новый проект – P14_2 для демонстрации техники вывода трехмерной модели. На рис. 19.2. вы можете видеть окно Project Explorer этого проекта и окно Properties для текстуры, предназначенной для наложения на модель. Трехмерные модели, которые предусматривают использование текстур, содержат в своих файлах указание на то, каким образом накладывать текстуру на объект, а так же – на файл текстуры. В нашем случае адрес файла текстуры задан в относительном выражении – то есть система будет искать этот файл в той же папке, в которой расположен файл трехмерной модели. Текстура подвергается преобразованиям в соответствии с командами, записанными в файле трехмерной модели, поэтому мы отключили параметр Build Action в свойствах текстуры.
(рис 19.2) Окна Solution Explorer и PropertiesЛистинг 19.2. содержит код класса Game1, реализующего вывод модели на экран.
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
namespace P14_2
{
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
// Модель для вывода
Model myModel;
//Мировая матрица
Matrix WorldMatrix;
//Соотношение сторон окна вывода
float aspectRatio;
//Угол поворота для вращения модели
float angle;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
}
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
}
protected override void LoadContent()
{
//загрузка модели
myModel = Content.Load<Model>("RoundShield");
//Установка соотношения сторон окна вывода
aspectRatio = (float)graphics.GraphicsDevice.Viewport.Width /
(float)graphics.GraphicsDevice.Viewport.Height;
}
protected override void UnloadContent()
{
// TODO: Unload any non ContentManager content here
}
protected override void Update(GameTime gameTime)
{
//увеличим угол поворота на 1
angle++;
//установим новую мировую матрицу
//поворот по оси Y равен углу angle, поворот по X -
//angle, деленному на 5
WorldMatrix = Matrix.CreateRotationY(MathHelper.ToRadians(angle))*
Matrix .CreateRotationX (MathHelper .ToRadians (angle /5.0f));
//Для каждой сети в модели
foreach (ModelMesh mesh in myModel.Meshes)
{
//Для каждого эффекта в сети
foreach (BasicEffect effect in mesh.Effects)
{
//Установить освещение по умолчанию
effect.LightingEnabled = true;
effect.EnableDefaultLighting();
//установить матрицы
effect.World = WorldMatrix;
effect.View = Matrix.CreateLookAt(new Vector3(0.0f, 0.0f, 119.0f), Vector3.Zero, Vector3.Up);
effect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f),
aspectRatio, 1.0f, 1000.0f);
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
graphics.GraphicsDevice.Clear(Color.CornflowerBlue);
// Вывод модели
foreach (ModelMesh mesh in myModel.Meshes)
{
mesh.Draw();
}
base.Draw(gameTime);
}
}
}
На рис. 19.3. вы можете видеть окно проекта P14_2.
(рис 19.3) Окно проекта P14_2 Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.