I'm trying to figure out how to correctly calculate the frustum bounds of my openGL scene under Orthographic Projection. The code I'm using to do so is as follows:
public void setFrustum(GL gl, GLU glu){
double[] forwardAxis = properties.getForwardAxis();
double[] leftAxis = VecMath.normalVector(properties.getUpDir(), forwardAxis);
double[] upAxis = VecMath.normalVector(forwardAxis, leftAxis);
double[] v = bounds.getWidthVector();
double width = VecMath.magnitude(VecMath.project(v, leftAxis));
double height = VecMath.magnitude(VecMath.project(v, upAxis));
double modelRatio = width / height;
double canvasRatio = properties.getAspectRatio();
// -- height bigger than width --
if (modelRatio < canvasRatio){
// -- update width --
width = height * canvasRatio;
} else{
// -- update height --
height = width / canvasRatio;
}
double l = width / 2. * 1.15;
double b = height / 2. * 1.15;
double n = properties.getNear();
double f = properties.getFar();
gl.glOrtho(-l, l, -b, b, n, f);
}
So as you can see I get my axes and my width vector:
widthVector = (xWidth, yWidth, zWidth)
and then get the width and height of the gl scene by projecting this width vector along the leftAxis and upAxis. I then match the aspectRatio to that of the canvas I'm displaying this scene in and use the width and height to calculate the bounds of the orthographic frustum (adding padding using the 1.15 scaling factor).
This works quite well for all views except the Isometric view. Here are some screen shots of this at work:
As you can see, the bottom, left and front views are all fine. However, the isometric view is chopped off (and no I didn't clip it wrong when taking the screenshot!). I would have to increase the padding scale factor I use to 1.5 instead of 1.15, but I must be doing something wrong here.
Any help would be greatly appreciated. Thanks!
This is my fitAllIn
simplified
public void fitAllIn(float[] boundingMinMaxWorldSpace) {
Vec4 centerWorldSpace = new Vec4((boundingMinMaxWorldSpace[0] + boundingMinMaxWorldSpace[1]) / 2,
(boundingMinMaxWorldSpace[2] + boundingMinMaxWorldSpace[3]) / 2,
(boundingMinMaxWorldSpace[4] + boundingMinMaxWorldSpace[5]) / 2, 1f);
Vec3 min = new Vec3(boundingMinMaxWorldSpace[0], boundingMinMaxWorldSpace[2], boundingMinMaxWorldSpace[4]);
Vec3 max = new Vec3(boundingMinMaxWorldSpace[1], boundingMinMaxWorldSpace[3], boundingMinMaxWorldSpace[5]);
float diameter = (float) Math.sqrt(
(max.x - min.x) * (max.x - min.x)
+ (max.y - min.y) * (max.y - min.y)
+ (max.z - min.z) * (max.z - min.z));
if (getCurrView().orthographicProj) {
if (glViewer.getAspect() > 1) {
// projection * scale = y
getCurrView().scale = diameter / 2 / projectionSide;
} else {
// projection * aspect * scale = x
getCurrView().scale = diameter / 2 / (projectionSide * glViewer.getAspect());
}
getCurrView().scale = viewScale.clampScale(projectionSide, getCurrView().scale);
}
getCurrView().targetPos = new Vec3(centerWorldSpace);
glViewer.refresh();
Basically I pass the bounding box in world space, I calculate the center that my camera will target, I calculate the minimum point (minX, minY, minZ) and the maximum one. I get the diameter and then a simple equation to retrieve the scaling.
scale
and projectionSide
will be used later for the elaboration of my orthographic matrix
float x = projectionSide * glViewer.getAspect() * getCurrView().scale;
float y = projectionSide * getCurrView().scale;
float z = projectionSide;
return Jglm.orthographic(-x, x, -y, y, -z, z);
Thanks to the suggestion of elect, here is my updated setFrustum routine:
public void setFrustum(GL gl, GLU glu) {
double[] widthVec = bounds.getWidthVector();
double diameter = VecMath.magnitude(widthVec);
double canvasRatio = properties.getAspectRatio();
double scale = canvasRatio > 1 ? diameter / 2 : diameter / 2 / canvasRatio;
double x = canvasRatio * scale;
double y = scale;
double n = properties.getNear();
double f = properties.getFar();
gl.glOrtho(-x, x, -y, y, n, f);
}
Works perfectly. Thanks Elect!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With