# Drawing a one pixel wide line in 3D space

I'd like to draw a line in 3D space that is always exactly one pixel wide on screen, no matter how far away from the camera it is. (And the same for single points too).

Any hints on how I could do that?

-

Rendering Lines - Method 1 (Primitives)

For simple lines in 3D space you can draw them using a `LineList` or `LineStrip` primitive. Here's the minimal amount of code you have to add to an empty XNA project to have it draw a line from (0,0,0) to (0,0,-50). The line should appear to have roughly the same width no matter where the camera is located.

``````// Inside your Game class
private BasicEffect basicEffect;
private Vector3 startPoint = new Vector3(0, 0, 0);
private Vector3 endPoint = new Vector3(0, 0, -50);

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);

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);
``````

I basically created a simple `BasicEffect` to hold my view and projection transformations, and passed two vertices (storing position and color) to the `GraphicsDevice.DrawUserPrimitives` method to be rendered as a`LineList`.

Of course there are many ways to optimize it, most of which involve the creation of a `VertexBuffer` to store all of the vertices, and batching as many lines as possible into a single Draw call but that's irrelevant to the question.

Rendering Points - Method 1 (SpriteBatch)

As for drawing points, this used to be easy using point sprites but they were removed from XNA 4.0. There's a few alternatives though. The easiest way is to create a 1x1 white `Texture2D` object, and render it using `SpriteBatch` in the correct screen location, which you can easily find using the Viewport.Project method.

You can create the required `Texture2D` object like this:

``````Texture2D pixel = new Texture2D(GraphicsDevice, 1, 1);
pixel.SetData(new [] { Color.White });
``````

And render it at location (x,y,z) like this:

``````// 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();
``````

Rendering Lines - Method 2 (SpriteBatch)

Alternatively, you can also draw lines using a `SpriteBatch` using the technique described here. In this case you'd simply need to find the screen space coordinate for both ends of the 3D line (once again using `Viewport.Project`) and then draw a regular line between them.

Rendering Points - Method 2 (Small Line with Primitives)

What about a line with the same start and end point, wouldn't that produce a point? Or would it simply be invisible?

I gave it a try and rendering a `LineList` using the same start and end points resulted in nothing being drawn. I found a way around it though so I'll describe it here for completeness.

The trick is not to use the same start and end points, but instead to draw a line so small, that it only appears as one pixel when drawn. So, in order to choose the correct end point, I first projected the world space point into screen space, moved it right one pixel in screen space, and finally projected it back into world space. That's the end point of your line in order to make it look like a dot. Something like this:

``````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);
}
``````

Followed by rendering it as a normal line primitive.

Demonstration

Here's what I got drawing a white line in 3D space using a line list primitive, and red dots at both ends of the line using a 1x1 texture and SpriteBatch. The code used is pretty much what I wrote above. I've also zoomed in so you can confirm that they're exactly one pixel wide:

-
What about a line with the same start and end point, wouldn't that produce a point? Or would it simply be invisible? – aaaaaaaaaaaa Jan 30 '12 at 10:37
@eBusiness Good question! I just gave it a try, and indeed it doesn't render anything. – David Gouveia Jan 30 '12 at 10:50
@eBusiness I just found a way though, but I think it's a bit silly. I'll add it for completeness anyway. – David Gouveia Jan 30 '12 at 10:57
I wish I could accept this as "Truly outstanding answer". Thanks! – danbystrom Jan 30 '12 at 13:50

This is tagged as XNA so I'm assuming that's what you're asking about?

http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.40).aspx

Of course you can use your own view/projection matrices instead of theirs. Basically, `PrimitiveType.LineList` or `LineStrip` is how to draw lines at the GPU level.

As for points, you can no longer use PrimitiveType.PointList to draw points anymore in XNA 4.0. Instead you would have to make very small triangles. This sample provides a good baseline:

http://create.msdn.com/education/catalog/sample/primitives_3d

For previous versions of XNA, if you're using one of those, you can go ahead and read the Point part of the XNA 3.0 version of the article posted above:

http://msdn.microsoft.com/en-us/library/bb196414(v=xnagamestudio.30).aspx

``````graphics.GraphicsDevice.RenderState.PointSize = 10;
Obviously change that to `1`.