Java OpenGL - 计算等轴测视图的正交裁剪体

5

我正在尝试计算正交投影下OpenGL场景的视锥体范围。我使用以下代码进行计算:

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);
}

所以,正如你所看到的,我获得了我的轴和宽度向量:

widthVector = (xWidth, yWidth, zWidth)

然后通过沿着左轴和上轴投影这个宽度向量来获取gl场景的宽度和高度。然后将纵横比与我正在显示此场景的画布相匹配,并使用宽度和高度计算正交视锥体的边界(使用1.15缩放因子添加填充)。

这对于除等角视图之外的所有视图都很有效。以下是此方法运作的一些屏幕截图:

BottomView LeftView FrontView

IsometricView

正如您所看到的,底部、左侧和前视图都很好。然而,等角视图被截断了(不,我在截屏时没有剪切它!)。我必须将我使用的填充比例因子增加到1.5而不是1.15,但我一定做错了什么。
任何帮助都将不胜感激。谢谢!
2个回答

2
这是我的fitAllIn简化版。
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();

基本上我传递世界空间中的边界框,计算我的相机将要对准的中心点,计算最小点(minX,minY,minZ)和最大点。我获取直径,然后使用一个简单的方程来检索缩放比例。scaleprojectionSide稍后将用于制作正交矩阵。
        float x = projectionSide * glViewer.getAspect() * getCurrView().scale;
        float y = projectionSide * getCurrView().scale;
        float z = projectionSide;

        return Jglm.orthographic(-x, x, -y, y, -z, z);

谢谢你的回答。看起来使用直径是我缺失的关键。我将更新我的代码,使用直径而不是宽度和高度。如果这解决了我的问题,我会再次发布。谢谢! - CB_Maverick
你能解释一下你的投影方向变量在做什么吗?你为它赋予什么值?它是全局设置还是根据某些给定参数计算得出的? - CB_Maverick

1

感谢elect的建议,这是我的更新后的setFrustum例程:

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);
}

工作完美。谢谢Elect!


我太晚看到你的最后一条评论了,但是你已经解决了。我很高兴 :) - elect

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接