Líneas de renderizado - Método 1 (primitivas)
Para líneas simples en el espacio 3D, puede dibujarlas usando a LineList
o LineStrip
primitivo. Aquí está la cantidad mínima de código que debe agregar a un proyecto XNA vacío para que dibuje una línea de (0,0,0) a (0,0, -50). La línea debería tener aproximadamente el mismo ancho sin importar dónde se encuentre la cámara.
// 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);
Básicamente, creé un simple BasicEffect
para mantener mi vista y las transformaciones de proyección, y pasé dos vértices (almacenando la posición y el color) al GraphicsDevice.DrawUserPrimitives
método que se representará como a LineList
.
Por supuesto, hay muchas formas de optimizarlo, la mayoría de las cuales implican la creación de un VertexBuffer
para almacenar todos los vértices y agrupar tantas líneas como sea posible en una sola llamada de Draw, pero eso es irrelevante para la pregunta.
Puntos de renderizado - Método 1 (SpriteBatch)
En cuanto a los puntos de dibujo, esto solía ser fácil usando sprites de puntos, pero se eliminaron de XNA 4.0 . Sin embargo, hay algunas alternativas. La forma más fácil es crear un Texture2D
objeto blanco 1x1 y renderizarlo SpriteBatch
en la ubicación correcta de la pantalla, que puede encontrar fácilmente con el método Viewport.Project .
Puede crear el Texture2D
objeto requerido de esta manera:
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });
Y renderízalo en una ubicación (x, y, z) como esta:
// 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();
Líneas de renderizado - Método 2 (SpriteBatch)
Alternativamente, también puede dibujar líneas SpriteBatch
usando la técnica descrita aquí . En este caso, simplemente necesitaría encontrar la coordenada del espacio de la pantalla para ambos extremos de la línea 3D (una vez más usando Viewport.Project
) y luego dibujar una línea regular entre ellos.
Puntos de renderizado - Método 2 (línea pequeña con primitivas)
En los comentarios, eBusiness planteó la siguiente pregunta:
¿Qué pasa con una línea con el mismo punto inicial y final, no produciría un punto? ¿O simplemente sería invisible?
Lo intenté y renderizar LineList
usando los mismos puntos de inicio y final no resultó en nada . Sin embargo, encontré una forma de evitarlo, así que lo describiré aquí para completarlo.
El truco no es utilizar los mismos puntos de inicio y final, sino dibujar una línea tan pequeña que solo aparece como un píxel cuando se dibuja. Entonces, para elegir el punto final correcto, primero proyecté el punto del espacio mundial en el espacio de la pantalla, lo moví a la derecha un píxel en el espacio de la pantalla y finalmente lo proyecté nuevamente en el espacio mundial. Ese es el punto final de su línea para que parezca un punto. Algo como esto:
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);
}
Seguido por representarlo como una línea normal primitiva.
Demostración
Esto es lo que obtuve dibujando una línea blanca en el espacio 3D usando una lista de líneas primitiva, y puntos rojos en ambos extremos de la línea usando una textura 1x1 y SpriteBatch. El código utilizado es más o menos lo que escribí anteriormente. También he ampliado para que pueda confirmar que tienen exactamente un píxel de ancho: