Hmm, odd. Transforming a point from 3d to 2d is super simple & fast… you should be able to do it a BAJILLION times per frame with less than a 80->40 fps drop.
Several features of your code make me suspicious.
You can probably eliminate at least the 2 matrix gets to projection matrix & viewport. Your viewport should be known already, from when you set it, and it doesn’t change.
Your projection matrix is very simple and can just be stored in your code.
The fact that gluProject uses a bunch of 2d arrays makes me uneasy. Those things are super expensive in Java. Also looking at the src code for gluProject(), it’s nothing to write home about. It remultiplies the matrices with each other every time you call the function, not to mention its heavy use of arrays, 1 & 2 d alike.
Given a FloatBuffer (16) projectionMatrix and 3d position pos_c already transformed into camera space, you can transform it into the viewport pos like this: (code touched up for this example, may contain small typos/errors, treat as pseudocode):
Rectangle2di viewport = new Rectangle2di();
Matrix4f projectionMatrix = new JwMatrix4f();
public boolean projectCameraSpacePointToViewport(Vector3f pos_c, Vector3f viewportPos, boolean computeZ)
{
if (pos_c.z < nearPlane || pos_c.z > farPlane)
return false;
final float projectedW = (projectionMatrix.m03 * pos_c.x) + (projectionMatrix.m13 * pos_c.y)
+ (projectionMatrix.m23 * pos_c.z) + projectionMatrix.m33;
if (Math.abs(projectedW) < 0.0001f)
return false;
final float ooProjectedW = 1.0f / projectedW;
final float projectedX = ooProjectedW
* ((projectionMatrix.m00 * pos_c.x) + (projectionMatrix.m10 * pos_c.y) + (projectionMatrix.m20 * pos_c.z));
final float projectedY = ooProjectedW
* ((projectionMatrix.m01 * pos_c.x) + (projectionMatrix.m11 * pos_c.y) + (projectionMatrix.m21 * pos_c.z));
if (!MathUtils.withinEpsilonInclusive(-1.0f, projectedX, 1.0f)
|| !MathUtils.withinEpsilonInclusive(-1.0f, projectedY, 1.0f))
return false;
final float halfViewportWidth = viewport.getWidth() * 0.5f;
final float halfViewportHeight = viewport.getHeight() * 0.5f;
viewportPos.x = (projectedX * halfViewportWidth) + viewport.getLeft() + halfViewportWidth;
viewportPos.y = (projectedY * halfViewportHeight) + viewport.getTop() + halfViewportHeight;
if (computeZ)
{
viewportPos.z = ooProjectedW
* ((projectionMatrix.m02 * pos_c.x) + (projectionMatrix.m12 * pos_c.y)
+ (projectionMatrix.m22 * pos_c.z) + projectionMatrix.m32);
}
return true;
}
//------------------- setup code for projectionMatrix:
private float farPlane = 8192.0f;
private float nearPlane = 0.1f;
private float fovHorizontal = MathUtils.PI / 2.0f;
private float fovVertical = 1.0f;
VolumeFrustum frustum = new VolumeFrustum();
private float oo_viewportHeight = 0.0f;
private float oo_viewportWidth = 0.0f;
private float aspect = 1.0f;
private void setup()
{
if (viewport.getWidth() != 0)
oo_viewportWidth = 1.0f / viewport.getWidth();
else
oo_viewportWidth = 1000000.0f;
if (viewport.getHeight() != 0)
oo_viewportHeight = 1.0f / viewport.getHeight();
else
oo_viewportHeight = 1000000.0f;
// calculate the vertical FOV based on the horizontal fov
aspect = viewport.getWidth() * oo_viewportHeight;
fovVertical = fovHorizontal / aspect;
frustum.setupFrustum(getNearPlane(), getFarPlane(), getFovHorizontal(), fovVertical, viewport.getWidth(),
viewport.getHeight());
final float viewDepth = farPlane - nearPlane;
final float w = 1.0f / (float) Math.tan(fovHorizontal * 0.5f);
final float h = 1.0f / (float) Math.tan(fovVertical * 0.5f);
final float Q = (viewDepth != 0.0f) ? (farPlane / viewDepth) : 1.0f;
projectionMatrix.m00 = w;
projectionMatrix.m10 = 0.0f;
projectionMatrix.m20 = 0.0f;
projectionMatrix.m30 = 0.0f;
projectionMatrix.m01 = 0.0f;
projectionMatrix.m11 = h;
projectionMatrix.m21 = 0.0f;
projectionMatrix.m31 = 0.0f;
projectionMatrix.m02 = 0.0f;
projectionMatrix.m12 = 0.0f;
projectionMatrix.m22 = Q;
projectionMatrix.m32 = -nearPlane * Q;
projectionMatrix.m03 = 0.0f;
projectionMatrix.m13 = 0.0f;
projectionMatrix.m23 = 1.0f;
projectionMatrix.m33 = 0.0f;
projectionMatrix.store(projectionMatrixBuffer);
projectionMatrixBuffer.rewind();
}