В прошлой теме мы рассмотрели, как настроить матрицы для установки камеры, видимого пространства сцены и положения объекта в пространстве. Теперь нам собственно надо создать объекты. Для этого изменим код программы следующим образом:
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace First3DGame { public class Game1 : Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; Matrix projectionMatrix; Matrix viewMatrix; Matrix worldMatrix; VertexPositionColor[] triangleVertices; VertexBuffer vertexBuffer; BasicEffect effect; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { viewMatrix = Matrix.CreateLookAt(new Vector3(0, 0, 6), Vector3.Zero, Vector3.Up); projectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, (float)Window.ClientBounds.Width / (float)Window.ClientBounds.Height, 1, 100); worldMatrix = Matrix.CreateWorld(new Vector3(0, 0, 0), new Vector3(0, 0, -1), Vector3.Up); // создаем набор вершин triangleVertices = new VertexPositionColor[3]; triangleVertices[0] = new VertexPositionColor(new Vector3(0, 1, 0), Color.Red); triangleVertices[1] = new VertexPositionColor(new Vector3(1, -1, 0), Color.Green); triangleVertices[2] = new VertexPositionColor(new Vector3(-1, -1, 0), Color.Blue); // Создаем буфер вершин vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), triangleVertices.Length, BufferUsage.None); // установка буфера вершин vertexBuffer.SetData(triangleVertices); // Создаем BasicEffect effect = new BasicEffect(GraphicsDevice); effect.VertexColorEnabled = true; base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); } protected override void UnloadContent() { } protected override void Update(GameTime gameTime) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape)) Exit(); base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // установка буфера вершин GraphicsDevice.SetVertexBuffer(vertexBuffer); //установка матриц эффекта effect.World = worldMatrix; effect.View = viewMatrix; effect.Projection = projectionMatrix; foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionColor> (PrimitiveType.TriangleStrip, triangleVertices, 0, 1); } base.Draw(gameTime); } } }
В итоге нам отобразится разноцветный треугольник:
Кроме переменных матриц здесь определяются еще три переменных:
VertexPositionColor[] triangleVertices; VertexBuffer vertexBuffer; BasicEffect effect;
Массив объектов VertexPositionColor представляет массив точек нашего объекта - треугольника. Кроме того, нам необходим объект VertexBuffer, представляющий буфер вершин (в который помещаются вершины VertexPositionColor) и передаваемый графическому устройству для отрисовки.
А объект BasicEffect управляет отрисовкой объекта по ранее определенным вершинам.
В методе Initialize()
создается три вершины - объекта VertexPositionColor, ровно столько, сколько нам необходимо для отрисовки треугольника:
triangleVertices = new VertexPositionColor[3]; triangleVertices[0] = new VertexPositionColor(new Vector3(0, 1, 0), Color.Red); triangleVertices[1] = new VertexPositionColor(new Vector3(1, -1, 0), Color.Green); triangleVertices[2] = new VertexPositionColor(new Vector3(-1, -1, 0), Color.Blue);
Причем каждая вершина определяет не только положение в виде вектора Vector3, но и цвет.
Далее создается и устанавливается буфер вершин:
// Создаем буфер вершин vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), triangleVertices.Length, BufferUsage.None); vertexBuffer.SetData(triangleVertices);
Конструктор VertexBuffer
принимает два четыре параметра:
Графическое устройство - в данном случае объект GraphicsDevice
Тип вершин - здесь VertexPositionColor
Количество вершин
Дополнительная опция поведения в виде перечисления BufferUsage. Оно имеет два значения: None
и WriteOnly
(буфер вершин только для запис, не для чтения)
И далее с помощью метода SetData()
ранее созданный массив объектов VertexPositionColor добавляется в буфер вершин.
И в конце метода Initialize()
создается объект BasicEffect:
effect = new BasicEffect(GraphicsDevice);effect.VertexColorEnabled = true;
Свойство VertexColorEnabled позволяет использовать цвета вершин. Если бы оно имело значение false, то мы бы увидели белый треугольник.
Сама отрисовка объекта происходит в методе Draw()
. Чтобы отрисовать объект в соответствии с матрицами, нам надо их установить для объекта BasicEffect:
effect.World = worldMatrix; effect.View = viewMatrix; effect.Projection = projectionMatrix;
Далее передаем буфер вершин графическому устройству для отрисовки:
GraphicsDevice.SetVertexBuffer(vertexBuffer);
Далее происходит непосредственно отрисовка:
foreach (EffectPass pass in effect.CurrentTechnique.Passes) { pass.Apply(); GraphicsDevice.DrawUserPrimitives<VertexPositionColor> (PrimitiveType.TriangleStrip, triangleVertices, 0, 1); }
Объект BasicEffect имеет одну или несколько техник (объект EffectTechnique). А каждая техника имеет один или несколько проходов (EffectPass).
В цикле foreeach проходим по коллекции проходов текущей техники (effect.CurrentTechnique.Passes). Чтобы начать проход для отрисовки техники,
нам надо вызвать у каждого прохода метод Apply()
.
Сам вывод треугольника происходит с помощью метода GraphicsDevice.DrawUserPrimitives. Он типизирован типом вершин - в данном случае типом VertexPositionColor. Он принимает четыре параметра:
тип графического примитива. В данном случае PrimitiveType.TriangleStrip
, то есть треугольники
массив вершин, по которым будет составляться графический примитив
номер вершины в массиве, с которой надо начинать отрисовку, в данном случае число 0
количество графических примитивов, в данном случае число 1, так как по трем вершинам последовательно мы можем составить только один треугольник