Here’s some (Java) code for that (~~let me know if you need help converting to .NET~~ I converted it myself, see end of post):

```
public void drawAxesProjected(float canvasWidth, float canvasHeight) {
// calculate reasonably scaled axes size
float drawScale = Math.min(canvasHeight, canvasWidth) / 30;
// disable lighting - lighting tends to screw with this process
glDisable(GL_LIGHTING);
// preserve projection matrix
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, canvasWidth, canvasHeight, 0, -1, 1);
// preserve modelview matrix
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// get modelview matrix
FloatBuffer fbuf = ByteBuffer
.allocateDirect(4 * 4 * 4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
glGetFloat(GL_MODELVIEW_MATRIX, fbuf);
// reset modelview matrix
glLoadIdentity();
glTranslatef(drawScale * 2f, canvasHeight - drawScale * 2f, 0f);
// calculate projected axes
Matrix4f m = new Matrix4f();
m.load(fbuf);
Vector4f x = Matrix4f.transform(m, new Vector4f(1, 0, 0, 0), null);
Vector4f y = Matrix4f.transform(m, new Vector4f(0, 1, 0, 0), null);
Vector4f z = Matrix4f.transform(m, new Vector4f(0, 0, 1, 0), null);
// begin drawing axes
glBegin(GL_LINES);
// draw x-axis
glColor4f(0f, 0f, 1f, 1f);
glVertex2f(0f, 0f);
glVertex2f(x.x * drawScale, -x.y * drawScale);
// draw y-axis
glColor4f(0f, 1f, 0f, 1f);
glVertex2f(0f, 0f);
glVertex2f(y.x * drawScale, -y.y * drawScale);
// draw z-axis
glColor4f(1f, 0f, 0f, 1f);
glVertex2f(0f, 0f);
glVertex2f(z.x * drawScale, -z.y * drawScale);
// done drawing
glEnd();
// restore views
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
// re-enable lighting
glEnable(GL_LIGHTING);
}
```

I don’t remember exactly which corner of the screen it draws at, but if I remember correctly, I think it’s the lower-left corner.

I realized OpenTK doesn’t have a Matrix4.Transform function, so here is the one that works in Java:

```
/**
* Transform a Vector by a matrix and return the result in a destination
* vector.
* @param left The left matrix
* @param right The right vector
* @param dest The destination vector, or null if a new one is to be created
* @return the destination vector
*/
public static Vector4f transform(Matrix4f left, Vector4f right, Vector4f dest) {
if (dest == null)
dest = new Vector4f();
float x = left.m00 * right.x + left.m10 * right.y + left.m20 * right.z + left.m30 * right.w;
float y = left.m01 * right.x + left.m11 * right.y + left.m21 * right.z + left.m31 * right.w;
float z = left.m02 * right.x + left.m12 * right.y + left.m22 * right.z + left.m32 * right.w;
float w = left.m03 * right.x + left.m13 * right.y + left.m23 * right.z + left.m33 * right.w;
dest.x = x;
dest.y = y;
dest.z = z;
dest.w = w;
return dest;
}
```

But it does have `OpenTK.Vector4.Transform(Vector4 vec, Matrix4 mat)`

– I just don’t know what results that gives…

VB Code (untested, but *should* (theoretically) work):

```
Public Sub DrawAxesProjected(CanvasWidth As Single, CanvasHeight As Single) {
' calculate reasonably scaled axes size
Dim DrawScale As Single = Math.Min(CanvasWidth, CanvasHeight) / 30!
' disable lighting - lighting tends to screw with this process
GL.Disable(EnableCap.Lighting)
' preserve projection matrix
GL.MatrixMode(MatrixMode.Projection)
GL.PushMatrix()
GL.LoadIdentity()
GL.Ortho(0!, CanvasWidth, CanvasHeight, 0!, -1!, 1!)
' preserve modelview matrix
GL.MatrixMode(MatrixMode.ModelView)
GL.PushMatrix()
' get modelview matrix
Dim buffer(0 To 15) As Single
GL.GetFloat(GetPName.ModelviewMatrix, buffer)
' reset modelview matrix
GL.LoadIdentity()
GL.Translate(DrawScale * 2!, CanvasHeight - DrawScale * 2!, 0!)
' calculate projected axes
Dim m As OpenTK.Matrix4 = New OpenTK.Matrix4(
buffer(0), buffer(1), buffer(2), buffer(3),
buffer(4), buffer(5), buffer(6), buffer(7),
buffer(8), buffer(9), buffer(10), buffer(11),
buffer(12), buffer(13), buffer(14), buffer(15)
)
Dim x As Vector4 = Vector4.Transform(Vector4.UnitX, m)
Dim y As Vector4 = Vector4.Transform(Vector4.UnitY, m)
Dim z As Vector4 = Vector4.Transform(Vector4.UnitZ, m)
' begin drawing axes
GL.Begin(BeginMode.Lines)
' draw x-axis
GL.Color4(0!, 0!, 1!, 1!)
GL.Vertex2(0!, 0!)
GL.Vertex2(x.x * DrawScale, -x.y * DrawScale)
' draw y-axis
GL.Color4(0!, 1!, 0!, 1!)
GL.Vertex2(0!, 0!)
GL.Vertex2(y.x * DrawScale, -y.y * DrawScale)
' draw z-axis
GL.Color4(1!, 0!, 0!, 1!)
GL.Vertex2(0!, 0!)
GL.Vertex2(z.x * DrawScale, -z.y * DrawScale)
' done drawing
Gl.End()
' restore views
GL.MatrixMode(MatrixMode.Projection)
GL.PopMatrix()
GL.MatrixMode(MatrixMode.ModelView)
GL.PopMatrix()
' re-enable lighting
GL.Enable(EnableCap.Lighting)
End Sub
```