I'm using code which tries to work like Glu.Project() since OpenTK doesn't support Glu.
Vector4 p开发者_如何学Goos = new Vector4(s.Position.X, 0.0f, s.Position.Y, 1.0f);
Matrix4 mov = new Matrix4();
Matrix4 prj = new Matrix4();
Matrix4 mpj = new Matrix4();
float[] vp = new float[4];
GL.GetFloat(GetPName.ModelviewMatrix, out mov);
GL.GetFloat(GetPName.ProjectionMatrix, out prj);
GL.GetFloat(GetPName.Viewport, vp);
Matrix4.Mult(ref prj, ref mov, out mpj);
Vector4.Transform(ref pos, ref mpj, out pos);
// Final mathematics as described in OpenGL 2.1 Glu specs
s.set2DPos(new Vector2f( (vp[0] + (vp[2] * (pos.X + 1) / 2.0f)),
(vp[1] + (vp[3] * (pos.Y + 1) / 2.0f)) ));
// Final mathematics as described in OpenGL 3 Vector specs
s.set2DPos(new Vector2f( (view[2] / 2 * pos.X + view[0]),
(view[3] / 2 * pos.X + view[1]) ));
// Neither of them work, but in relation OpenGL 3 vector specs work better.
s is a class which primary exists as a model in 3D space at s.Position. But the values I'm getting from this are astronomically far beyond the window boundaries.
The ModelView matrix from a breakpoint:
{(1, 0, 0, 0)
(0, 0.7071068, 0.7071068, 0)
(0, -0.7071068, 0.7071068, 0)
(0, -141.4214, -141.4214, 1)}
The Projection matrix from a breakpoint:
{(1.931371, 0, 0, 0)
(0, 2.414213, 0, 0)
(0, 0, -1.0002, -1)
(0, 0, -2.0002, 0)}
Am I doing something wrong or did I get something wrong? Am I missing something?
Vector2 GetScreenCoordinates(Vector3 ObjectCoordinate)
{
// ref: http://www.songho.ca/opengl/gl_transform.html
Vector4 obj = new Vector4(ObjectCoordinate.X, ObjectCoordinate.Y, ObjectCoordinate.Z, 1.0f);
Matrix4 projection = new Matrix4();
Matrix4 modelView = new Matrix4();
Vector4 viewPort = new Vector4();
GL.GetFloat(GetPName.ModelviewMatrix, out modelView);
GL.GetFloat(GetPName.ProjectionMatrix, out projection);
GL.GetFloat(GetPName.Viewport, out viewPort);
Vector4
eye = Vector4.Transform(obj, modelView),
clip = Vector4.Transform(eye, projection);
Vector3
ndc = new Vector3(clip.X / clip.W, clip.Y / clip.W, clip.Z / clip.W);
Vector2
w = new Vector2(viewPort.Z / 2 * ndc.X + viewPort.X + viewPort.Z / 2,
viewPort.W / 2 * ndc.Y + viewPort.Y + viewPort.W / 2);
return w;
}
Have you sanity checked the s.Position value before using it? What about the projection and transformation matrices you apply to the vector, are they sane looking?
I'm not familiar with OpenTK, but the mathematics prior to set2DPos() look sensible enough.
Here is how it works:
GL.GetFloat(GetPName.ModelviewMatrix, out model);
GL.GetFloat(GetPName.ProjectionMatrix, out proj);
GL.GetFloat(GetPName.Viewport, view);
Matrix4.Transpose(ref model, out model);
Matrix4.Transpose(ref proj, out proj);
Vector4 posa = new Vector4(0.0f, s.Position.Y, 1.0f, s.Position.X);
Vector4 posb = new Vector4(s.Position.Y, 1.0f, s.Position.X, 0.0f);
Vector4 posc = new Vector4(1.0f, s.Position.X, 0.0f, s.Position.Y);
Vector4 one = new Vector4(1.0f, 1.0f, 1.0f, 1.0f);
Matrix4 posv = new Matrix4(pos, posa, posb, posc);
Matrix4 ProjPos = Matrix4.Mult(Matrix4.Mult(proj, model), posv);
Matrix4.Transpose(ref ProjPos, out ProjPos);
Vector2f posout = new Vector2f(
(0 + (this.glc.Width * (ProjPos.Column0.X / ProjPos.Column0.W + 1.0f)) - (this.glc.Width / 2.0f)),
(0 + (this.glc.Height * (ProjPos.Column0.Y / ProjPos.Column0.W + 1.0f)) - (this.glc.Height / 2.0f))
);
In case anyone needs it :)
精彩评论