Лабораторная работа №14. Вывод трехмерных объектов на экран
В этой лабораторной работе мы рассмотрим вывод трехмерных объектов. В частности – формирование объектов средствами XNA Framework и работу с загружаемыми трехмерными моделями. Так же здесь мы поговорим о текстурировании объектов.
Цель работы
Научиться выводить трехрмерные объекты на игровой экран
Задачи работы
Научиться рисовать трехмерные объекты средствами XNA
Научиться выводить трехмерные модели
Научиться текстурировать трехмерные модели
Рисование трехмерных объектов средствами XNA
Рассмотрим особенности рисования трехмерных объектов средствами XNA на примере проекта P14_1. Здесь мы рассматриваем два подхода к выводу трехмерных примитивов. Первый заключается в использовании вершинного буфера и вывода объектов из него, второй – с использованием матриц вершин, которые указываются в качестве одного из параметров при выводе объектов.
В этом примере мы выведем на экран следующие объекты:
Треугольник
Два прямоугольника
Прямую линию
1000 точек со случайными координатами
200 треугольников со случайными координатами, одна из вершин каждого из которых расположена в одной точке.
В листинге 14.1. вы можете найти код класса Game1 проекта P14_1. Код подробно прокомментирован.
Отметим, что для вывода изображения нам необходимо выполнить следующие шаги:
Установить мировую, проекционную и видовую матрицы.
Создать и настроить объект типа BasicEffect для вывода изображений.
Создать наборы вершин, которые мы будем использовать при выводе.
Создать и заполнить вершинный буфер, который нужно будет загрузить в один из элемент коллекции Vertices объекта, используемого для вывода изображений
Вывести изображение из буфера, при необходимости вывести изображения, сгенерированные на основе массивов вершин, не внесенных в вершинный буфер.
Массив вершин может быть интерпретирован по-разному. Например, при интерпретации его в качестве PointList массив выводится в виде списка точек, при интерпретации в качестве TriangleList – как набор треугольников, при интерпретации в качестве TriangleFan – как «веер» из треугольников, одна из вершин которых совпадает, при интерпретации как LineList – в качестве набора линий. При выводе изображения в методе Draw необходимо очищать экран от предыдущего вывода – иначе он покроется копиями изображений.
Мы используем мировую матрицу для вращения выведенной сцены, модифицируя её на 1 градус при каждом проходе цикла Update.
usingSystem;usingSystem.Collections.Generic;usingMicrosoft.Xna.Framework;usingMicrosoft.Xna.Framework.Audio;usingMicrosoft.Xna.Framework.Content;usingMicrosoft.Xna.Framework.Graphics;usingMicrosoft.Xna.Framework.Input;namespace P14_1{publicclass 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";}protectedoverridevoid 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, 20.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 до 3float 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 до 1float x =(float)(rnd.NextDouble()- rnd.NextDouble());float y =(float)(rnd.NextDouble()- rnd.NextDouble());//группа треугольников сдвинута на 3 по оси Zfloat 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);}protectedoverridevoid UnloadContent(){if(vertBuffer !=null){ vertBuffer.Dispose(); vertBuffer = null;}if(basicEffect !=null){ basicEffect.Dispose(); basicEffect = null;}}protectedoverridevoid Update(GameTime gameTime){//Уменьшаем на 1 градус значение поворота матрицы wM = wM - 1f;//Модифицируем мировую матрицу worldMatrix = Matrix.CreateRotationY(MathHelper.ToRadians(wM));//Меняем мировую матрицу basicEffect.World= worldMatrix;base.Update(gameTime);}protectedoverridevoid 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);}}}
На рис. 14.1. вы можете видеть окно проекта P14_1.
Рис. 14.1. Окно проекта P14_1
Вывод трехмерных моделей
Выводя графические примитивы, рассмотренные в предыдущем примере, довольно сложно и трудоемко создавать игровые сцены. Гораздо большими возможностями обладает подход к работе с трехмерной графикой, использующий вывод заранее подготовленных трехмерных моделей. Само по себе создание трехмерных моделей требует немало времени и искусства, для этого применяются специальные программы. В деле создания игр выделяется отдельная группа сотрудников – 3D-моделеров, которые занимаются исключительно созданием трехмерных моделей.
Мы использовали готовую бесплатную трехмерную модель Free Lowpoly Round Shield. Для вывода модели на экран необходимо добавить в проект соответствующие ей ресурсы, в нашем случае – модель в формате .FBX и текстуру в формате .JPG. Далее следует загрузить модель в игру, настроить её свойства и вывести на экран.
В трехмерной графике существует такое понятие, как Mesh (Сетка, иногда пользуются русской калькой с этого слова – мэш). Трехмерные модели состоят из сетей – линий, соединяющих вершины. Модель может состоять из нескольких взаимодействующих сетей, каждую из которых нужно обработать при выводе модели.
Создадим новый проект – P14_2 для демонстрации техники вывода трехмерной модели. На рис. 14.2. вы можете видеть окно Project Explorer этого проекта и окно Properties для текстуры, предназначенной для наложения на модель. Трехмерные модели, которые предусматривают использование текстур, содержат в своих файлах указание на то, каким образом накладывать текстуру на объект, а так же – на файл текстуры. В нашем случае адрес файла текстуры задан в относительном выражении – то есть система будет искать этот файл в той же папке, в которой расположен файл трехмерной модели. Текстура подвергается преобразованиям в соответствии с командами, записанными в файле трехмерной модели, поэтому мы отключили параметр Build Action в свойствах текстуры.
Рис. 14.2. Окна Solution Explorer и Properties
Листинг 14.2. содержит код класса Game1, реализующего вывод модели на экран.
usingSystem;usingSystem.Collections.Generic;usingMicrosoft.Xna.Framework;usingMicrosoft.Xna.Framework.Audio;usingMicrosoft.Xna.Framework.Content;usingMicrosoft.Xna.Framework.Graphics;usingMicrosoft.Xna.Framework.Input;namespace P14_2{publicclass Game1 : Microsoft.Xna.Framework.Game{ GraphicsDeviceManager graphics;// Модель для вывода Model myModel;//Мировая матрица Matrix WorldMatrix;//Соотношение сторон окна выводаfloat aspectRatio;//Угол поворота для вращения моделиfloat angle;public Game1(){ graphics =new GraphicsDeviceManager(this); Content.RootDirectory="Content";}protectedoverridevoid LoadContent(){//загрузка модели myModel = Content.Load<Model>("RoundShield");//Установка соотношения сторон окна вывода aspectRatio =(float)graphics.GraphicsDevice.Viewport.Width/(float)graphics.GraphicsDevice.Viewport.Height;}protectedoverridevoid 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, 120.0f), Vector3.Zero, Vector3.Up); effect.Projection= Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), aspectRatio, 1.0f, 1000.0f);}}base.Update(gameTime);}protectedoverridevoid Draw(GameTime gameTime){ graphics.GraphicsDevice.Clear(Color.CornflowerBlue);// Вывод моделиforeach(ModelMesh mesh in myModel.Meshes){ mesh.Draw();}base.Draw(gameTime);}}}
На рис. 14.3. вы можете видеть окно проекта P14_2.
Рис. 14.3. Окно проекта P14_2
Вопросы
1) Какой метод объекта Matrix позволяет создать мировую матрицу, не изменяющую состояние объекта в пространстве
a. Matrix.CreateScale
b. Matrix.CreateLookAt
c. Matrix.Identity
d. Matrix. CreatePerspectiveFieldOfView
2) Какой метод объекта Matrix позволяет изменять размер объекта в пространстве?
a. Matrix.CreateScale
b. Matrix.CreateLookAt
c. Matrix.Identity
d. Matrix. CreatePerspectiveFieldOfView
3) Какой метод объекта Matrix позволяет создавать видовую матрицу?
a. Matrix.CreateScale
b. Matrix.CreateLookAt
c. Matrix.Identity
d. Matrix. CreatePerspectiveFieldOfView
4) Какой метод объекта Matrix позволяет создавать перспективную проекционную матрицу?
a. Matrix.CreateScale
b. Matrix.CreateLookAt
c. Matrix.Identity
d. Matrix. CreatePerspectiveFieldOfView
5) Объект какого класса используется для вывода трехмерных изображений?
a. Matrix
b. VertexPosition
c. BasicEffect
d. Random
6) Объекты какого класса используются для представления в игре трехмерных моделей?
a. Texture2D
b. Model
c. Float
d. Matrix
7) Объекты какого класса позволяют работать с отдельными сетями в объектах?
a. Matrix
b. Model
c. ModelMesh
d. BasicEffect
3178 Прочтений • [Вывод моделей на экран] [08.08.2012] [Комментариев: 0]