Линии рендеринга - Метод 1 (Примитивы)
Для простых линий в трехмерном пространстве вы можете нарисовать их, используя LineListили LineStripпримитив. Вот минимальный объем кода, который вы должны добавить в пустой проект XNA, чтобы нарисовать линию от (0,0,0) до (0,0, -50). Линия должна иметь примерно одинаковую ширину независимо от того, где находится камера.
// Inside your Game class
private BasicEffect basicEffect;
private Vector3 startPoint = new Vector3(0, 0, 0);
private Vector3 endPoint = new Vector3(0, 0, -50);
// Inside your Game.LoadContent method
basicEffect = new BasicEffect(GraphicsDevice);
basicEffect.View = Matrix.CreateLookAt(new Vector3(50, 50, 50), new Vector3(0, 0, 0), Vector3.Up);
basicEffect.Projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45f), GraphicsDevice.Viewport.AspectRatio, 1f, 1000f);
// Inside your Game.Draw method
basicEffect.CurrentTechnique.Passes[0].Apply();
var vertices = new[] { new VertexPositionColor(startPoint, Color.White), new VertexPositionColor(endPoint, Color.White) };
GraphicsDevice.DrawUserPrimitives(PrimitiveType.LineList, vertices, 0, 1);
Я в основном создал простое, BasicEffectчтобы хранить преобразования вида и проекции, и передал две вершины (положение и цвет) GraphicsDevice.DrawUserPrimitivesметоду, который будет отображаться как LineList.
Конечно, есть много способов его оптимизации, большинство из которых включает создание a VertexBufferдля хранения всех вершин и пакетирование как можно большего количества строк в один вызов Draw, но это не имеет отношения к вопросу.
Точки рендеринга - метод 1 (SpriteBatch)
Что касается рисования точек, раньше было легко использовать точечные спрайты, но они были удалены из XNA 4.0 . Хотя есть несколько альтернатив. Самый простой способ - создать белый Texture2Dобъект 1x1 и отобразить его, используя SpriteBatchправильное расположение экрана, которое вы можете легко найти с помощью метода Viewport.Project .
Вы можете создать необходимый Texture2Dобъект следующим образом:
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });
И отрендерить его в местоположении (x, y, z) следующим образом:
// Find screen equivalent of 3D location in world
Vector3 worldLocation = new Vector3(0, 0, 50);
Vector3 screenLocation = GraphicsDevice.Viewport.Project(worldLocation, projectionMatrix, viewMatrix, Matrix.Identity);
// Draw our pixel texture there
spriteBatch.Begin();
spriteBatch.Draw(pixel, new Vector2(screenLocation.X, screenLocation.Y), Color.White);
spriteBatch.End();
Рендеринг линий - Метод 2 (SpriteBatch)
Кроме того, вы также можете рисовать линии, SpriteBatchиспользуя технику, описанную здесь . В этом случае вам просто нужно найти координаты экранного пространства для обоих концов 3D-линии (снова используя Viewport.Project), а затем нарисовать регулярную линию между ними.
Точки рендеринга - Метод 2 (Малая линия с примитивами)
В комментариях eBusiness поднял следующий вопрос:
Как насчет линии с одинаковыми начальной и конечной точкой, разве это не даст точку? Или это будет просто невидимым?
Я попробовал, и рендеринг с LineListиспользованием одинаковых начальных и конечных точек ничего не нарисовал. Я нашел способ обойти это, хотя, поэтому я опишу это здесь для полноты.
Хитрость заключается не в том, чтобы использовать одинаковые начальную и конечную точки, а в том, чтобы нарисовать линию, настолько маленькую, что при рисовании она выглядит как один пиксель . Итак, чтобы выбрать правильную конечную точку, я сначала спроецировал точку мирового пространства в пространство экрана, переместил ее на один пиксель в пространстве экрана и, наконец, спроецировал ее обратно в мировое пространство. Это конечная точка вашей линии, чтобы она выглядела как точка. Что-то вроде этого:
Vector3 GetEndPointForDot(Vector3 start)
{
// Convert start point to screen space
Vector3 screenPoint = GraphicsDevice.Viewport.Project(start, projection, view, Matrix.Identity);
// Screen space is defined in pixels so adding (1,0,0) moves it right one pixel
screenPoint += Vector3.Right;
// Finally unproject it back into world space
return GraphicsDevice.Viewport.Unproject(screenPoint, projection, view, Matrix.Identity);
}
Затем следует преобразовать его в обычный примитив строки.
демонстрация
Вот что я получил, нарисовав белую линию в трехмерном пространстве, используя примитив списка линий, и красные точки на обоих концах линии, используя текстуру 1x1 и SpriteBatch. Используемый код в значительной степени соответствует тому, что я написал выше. Я также увеличил масштаб, чтобы вы могли убедиться, что они имеют ширину ровно в один пиксель:
