При создании трехмерного объекта в прошлой теме мы использовали треугольник. Треугольник является базовым элементом, из которого создаются все остальные трехмерные объекты. Например, для создания прямоугольника нам потребуется два треугольника, для создания куба - 6 прямоугольников и так далее.
Но по факту мы имеем дело не просто с треугольником, а с определенным графическим примитивом, который определяется через перечисление PrimitiveType. Выбор примитива указывает, как будут соединяться вершины в буфере вершин, который передается графическому устройству. В MonoGame есть следующие виду графических примитивов:
PrimitiveType.LineList: список линий, по всем вершинам строятся замкнутые линии
PrimitiveType.LineStrip: лента линий. Все вершины соединяются одной линией
PrimitiveType.TriangleList: список треугольников, из верши создаются замкнутые треугольники
PrimitiveType.TriangleStrip: лента треугольников, все вершины последовательно соединяются в треугольники
Рассмотрим се эти примитивы на примере:
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(0f, 0f, 0f), new Vector3(0, 0, -1), Vector3.Up); // создаем набор вершин triangleVertices = new VertexPositionColor[4]; triangleVertices[0] = new VertexPositionColor(new Vector3(-1, 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); triangleVertices[3] = new VertexPositionColor(new Vector3(1, -1, 0), Color.Yellow); vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), triangleVertices.Length, BufferUsage.None); vertexBuffer.SetData(triangleVertices); effect = new BasicEffect(GraphicsDevice); effect.VertexColorEnabled = true; RasterizerState rasterizerState = new RasterizerState(); rasterizerState.CullMode = CullMode.None; GraphicsDevice.RasterizerState = rasterizerState; 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); 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.LineList, triangleVertices, 0, 2); } base.Draw(gameTime); } } }
Здесь мы определяем четыре вершины в буфере вершин. А в качестве примитива использован LineStrip:
// отрисовка примитива GraphicsDevice.DrawUserPrimitives<VertexPositionColor> (PrimitiveType.LineList, triangleVertices, 0, 2);
Этот примитив создает набор замкнутых линий. Для создания линии нужно две вершины. Поэтому из четырех вершин в буфере, которые у нас есть,
мы получим две изолированные линии. То есть первая и вторая вершина составят первую линию, а третья и четвертая - вторую линию. Поэтому в метод
GraphicsDevice.DrawUserPrimitives
в качестве последнего параметра передается число 2 - число отрисовываемых линий. Больше этого числа, например, 3,
мы не можем указать, так как у нас нет столько вершин для создания изолированных линий. Можно лишь указать меньшее число, если нам надо меньше линий.
Теперь изменим тип примитива при выводе на LineStrip (вся остальная часть программы остается той же):
GraphicsDevice.DrawUserPrimitives<VertexPositionColor> (PrimitiveType.LineStrip, triangleVertices, 0, 3);
LineStrip последовательно соединяет все вершины в связанные линии, то есть первая вершина соединяется во второй, вторая с третьей, третья с четвертой. И, таким образом, образуется три линии:
Опять же в качестве последнего параметра мы не можем передать число большее, чем максимально возможное количество линий, то есть три в данном случае.
Изменим тип примитива на TriangleStrip:
GraphicsDevice.DrawUserPrimitives<VertexPositionColor> (PrimitiveType.TriangleStrip, triangleVertices, 0, 2);
TriangleStrip последовательно соединяет вершины в соединенные треугольники. Так, первая соединяется со второй и третьей вершиной, образуя первый треугольник. Вторая вершина соединяется с третьей и четвертой вершинами, образуя второй треугольник. Больше вершин у нас нет, поэтому в данном случае у нас может быть только два треугольника, которые вместе образуют прямоугольник:
И последний тип - TriangleList соединяет вершины в замкнутые треугольники. Так, первая соединяется со второй и третьей вершиной, образуя первый треугольник. Четвертая вершина соединяется с пятой и шестой вершинами, образуя второй треугольник. То есть теперь треугольники не соединяются. И поскольку у нас только четыре вершины, то с помощью данного примитива мы можем создать только один треугольник:
GraphicsDevice.DrawUserPrimitives<VertexPositionColor> (PrimitiveType.TriangleList, triangleVertices, 0, 1);