1

I am attempting to have a 2D HUD which has icons that track the location on the screen of 3D objects behind the HUD in a 3D environment.

Reasoning: Sometimes you cannot see a 3D object (too far away or off screen) but you still want to know where it is.

Issue: 3D scene is using a perspective matrix to transform it, giving it depth (z-axis), the HUD is strictly 2D (xy-plane). Because of the depth, the 2D HUD cannot properly track objects when they are farther/closer away.

What I want: A way to get a 2D Vector [(x,y) pos] of where to put an icon so that it is centered where the 3D object in the background would be.

Example of all objects in an xy-plane (z=0):

You can see that as the objects get farther away from the center, the Icon (circle thing in white) is more off center. Example 1

Example of objects with increasing depths (farther from center == deeper):

You can see that the HUD thinks 3D objects are in the same plane still. Example 2

Pseudo-Code:

.getPos() gets the Vector (x,y,z)

lookAtObj = Object.getPos() - camera.getPos() // lookAt vector from camera to the object
icon.pos = Orthogonal Component of lookAtObj on camera.get_lookAt()

My Perspective Matrix:

// Function call in the OpenGL draw() method
FloatMatrix proj = FloatMatrix.getPerspectiveMatrix( this.fov, this.width, this.height, 0.1f, 200.0f );

// Function
public static FloatMatrix getPerspectiveMatrix( Double fov, float w, float h, float near, float far ){
    float asp = w/h;
    float fov_cos = (float) Math.cos( fov / 2.0d );
    float fov_sin = (float) Math.sin( fov / 2.0d );
    float fov_cot = fov_cos/fov_sin;
    float a_0  = fov_cot/asp;
    float a_3  = (far + near)/(near-far);
    float a_43 = (2.0f * far * near)/(near-far);
    float[] an = {
            a_0,  0.0f,    0.0f, 0.0f,
            0.0f, fov_cot, 0.0f, 0.0f,
            0.0f, 0.0f,    a_3,  -1.0f,
            0.0f, 0.0f,    a_43, 0.0f,
    };
    return new FloatMatrix( an, 4, 4 );

}
4

1 回答 1

2

这很简单。您可以使用gluProject. 它将采用给定的模型视图、投影和视口变换以及一个 3D 点,并应用逆向并为您在窗口坐标中吐出一个 2D 点(对于轻微的拼写错误表示歉意,只需在此处输入):

double myX = ..., myY = ..., myZ = ...; // your object's 3d coordinates
double[] my2DPoint = new double[2]; // will contain 2d window coords when done

double[] modelview = new double[16];
double[] projection = new double[16];
int[] viewport = new int[4];

gl.glGetDoublev(GL2.GL_MODELVIEW_MATRIX, modelview, 0);
gl.glGetDoublev(GL2.GL_PROJECTION_MATRIX, projection, 0);
gl.glGetIntegerv(GL2.GL_VIEWPORT, viewport, 0);
glu.gluProject(myX, myY, myZ, modelview, 0, projection, 0,
               viewport, 0, my2DPoint, 0);

// now my2DPoint[0] is window x, and my2DPoint[1] is window y

完成此操作后,您将在 2D 窗口坐标中获得 3D 点。然后只需将您的投影切换到 2D 正交投影,以窗口像素为单位,并在 2D 空间中绘制您的 HUD。

出于性能考虑,如果您每帧要绘制多个 HUD 项目;只需每帧获取一次模型视图/投影/视口(或者,更好的是,如果您更改它们并仅根据需要重新查询,则使您的缓存无效)并在随后的调用中重用它们gluProject

于 2014-03-20T04:29:37.503 回答