Lignes de rendu - Méthode 1 (primitives)
Pour les lignes simples dans l'espace 3D, vous pouvez les dessiner à l'aide d'un LineList
ou LineStrip
primitif. Voici la quantité minimale de code que vous devez ajouter à un projet XNA vide pour qu'il trace une ligne de (0,0,0) à (0,0, -50). La ligne devrait sembler avoir à peu près la même largeur, peu importe où se trouve la caméra.
// 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);
J'ai essentiellement créé un simple BasicEffect
pour conserver mes transformations de vue et de projection, et passé deux sommets (stockage de la position et de la couleur) à la GraphicsDevice.DrawUserPrimitives
méthode à rendre en tant que LineList
.
Bien sûr, il existe de nombreuses façons de l'optimiser, dont la plupart impliquent la création d'un VertexBuffer
pour stocker tous les sommets et le regroupement d'autant de lignes que possible dans un seul appel Draw, mais cela n'a rien à voir avec la question.
Points de rendu - Méthode 1 (SpriteBatch)
Quant aux points de dessin, cela était facile à utiliser avec les sprites ponctuels mais ils ont été supprimés de XNA 4.0 . Il existe cependant quelques alternatives. Le moyen le plus simple consiste à créer un Texture2D
objet blanc 1x1 et à le rendre SpriteBatch
à l'emplacement de l'écran correct, que vous pouvez facilement trouver à l'aide de la méthode Viewport.Project .
Vous pouvez créer l' Texture2D
objet requis comme ceci:
Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });
Et rendez-le à l'emplacement (x, y, z) comme ceci:
// 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();
Lignes de rendu - Méthode 2 (SpriteBatch)
Alternativement, vous pouvez également tracer des lignes en utilisant un en SpriteBatch
utilisant la technique décrite ici . Dans ce cas, il vous suffit de trouver les coordonnées d'espace d'écran pour les deux extrémités de la ligne 3D (en utilisant à nouveau Viewport.Project
), puis de tracer une ligne régulière entre elles.
Points de rendu - Méthode 2 (petite ligne avec des primitives)
Dans les commentaires, eBusiness a soulevé la question suivante:
Qu'en est-il d'une ligne avec le même point de départ et de fin, cela ne produirait-il pas un point? Ou serait-il simplement invisible?
Je l'ai essayé et le rendu en LineList
utilisant les mêmes points de début et de fin n'a entraîné aucun dessin. J'ai trouvé un moyen de contourner cela, alors je vais le décrire ici pour être complet.
L'astuce n'est pas d'utiliser les mêmes points de début et de fin, mais de tracer une ligne si petite qu'elle n'apparaît que comme un pixel lorsqu'elle est dessinée. Donc, afin de choisir le bon point de fin, j'ai d'abord projeté le point de l'espace mondial dans l'espace d'écran, je l'ai déplacé d'un pixel vers la droite dans l'espace d'écran , et finalement je l'ai projeté de nouveau dans l'espace mondial. C'est le point final de votre ligne afin de la faire ressembler à un point. Quelque chose comme ça:
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);
}
Suivi en le rendant comme une primitive de ligne normale.
Manifestation
Voici ce que j'ai obtenu en dessinant une ligne blanche dans l'espace 3D en utilisant une primitive de liste de lignes et des points rouges aux deux extrémités de la ligne en utilisant une texture 1x1 et SpriteBatch. Le code utilisé est à peu près ce que j'ai écrit ci-dessus. J'ai également zoomé pour que vous puissiez confirmer qu'ils mesurent exactement un pixel de large: