JOML-CI / JOML

A Java math library for OpenGL rendering calculations
MIT License
729 stars 104 forks source link

FrustumIntersection does not have testLine #292

Closed xupwup closed 3 years ago

xupwup commented 3 years ago

Could this be added? This is what I've been using until now, but it would be nice if it were included in JOML.

private float distance(Vector3f a, int index){
        switch(index){
            case 0: return nxX * a.x + nxY * a.y + nxZ * a.z + nxW;
            case 1: return pxX * a.x + pxY * a.y + pxZ * a.z + pxW;
            case 2: return nyX * a.x + nyY * a.y + nyZ * a.z + nyW;
            case 3: return pyX * a.x + pyY * a.y + pyZ * a.z + pyW;
            case 4: return nzX * a.x + nzY * a.y + nzZ * a.z + nzW;
            case 5: return pzX * a.x + pzY * a.y + pzZ * a.z + pzW;
        }
        return Float.NaN;
    }
    public boolean testLine(Vector3f p1, Vector3f p2){
        Vector3f a = new Vector3f(p1);
        Vector3f b = new Vector3f(p2);

        for(int i = 0; i < 6; i++){
            float da = distance(a, i);
            float db = distance(b, i);
            if(da < 0 && db < 0) return false;
            if(da * db < 0 && da != db){
                float p = Math.abs(da) / Math.abs(db - da); // da an db are on different sides of zero: da is always smaller or equal to db-da
                if(da < 0) a.mul(1 - p).add(new Vector3f(b).mul(p));
                else b.mul(p).add(new Vector3f(a).mul(1 - p));
            }
        }
        return true;
    }
httpdigest commented 3 years ago

Hey @xupwup , thanks for the impl! Sure. I'll add a slightly modified version (for better perf) to FrustumIntersection. I am just wondering, why in if(da * db < 0 && da != db) { you do the extra && da != db. If the product of da and db is negative, then da must have been different to db, doesn't it? Because the product can only be negative when the signs of the factors differ.

httpdigest commented 3 years ago

This is as fast as I can get it (twice as fast as your version (11.824 ns/op vs. 22.818 ns/op in JMH) with the Vector3f objects):

public boolean testLine(float aX, float aY, float aZ, float bX, float bY, float bZ) {
    float da, db;
    da = Math.fma(nxX, aX, Math.fma(nxY, aY, Math.fma(nxZ, aZ, nxW)));
    db = Math.fma(nxX, bX, Math.fma(nxY, bY, Math.fma(nxZ, bZ, nxW)));
    if (da < 0.0f && db < 0.0f)
        return false;
    if (da * db < 0.0f) {
        float p = Math.abs(da) / Math.abs(db - da);
        float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
        if (da < 0.0f) {
            aX = dx; aY = dy; aZ = dz;
        } else {
            bX = dx; bY = dy; bZ = dz;
        }
    }
    da = Math.fma(pxX, aX, Math.fma(pxY, aY, Math.fma(pxZ, aZ, pxW)));
    db = Math.fma(pxX, bX, Math.fma(pxY, bY, Math.fma(pxZ, bZ, pxW)));
    if (da < 0.0f && db < 0.0f)
        return false;
    if (da * db < 0.0f) {
        float p = Math.abs(da) / Math.abs(db - da);
        float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
        if (da < 0.0f) {
            aX = dx; aY = dy; aZ = dz;
        } else {
            bX = dx; bY = dy; bZ = dz;
        }
    }
    da = Math.fma(nyX, aX, Math.fma(nyY, aY, Math.fma(nyZ, aZ, nyW)));
    db = Math.fma(nyX, bX, Math.fma(nyY, bY, Math.fma(nyZ, bZ, nyW)));
    if (da < 0.0f && db < 0.0f)
        return false;
    if (da * db < 0.0f) {
        float p = Math.abs(da) / Math.abs(db - da);
        float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
        if (da < 0.0f) {
            aX = dx; aY = dy; aZ = dz;
        } else {
            bX = dx; bY = dy; bZ = dz;
        }
    }
    da = Math.fma(pyX, aX, Math.fma(pyY, aY, Math.fma(pyZ, aZ, pyW)));
    db = Math.fma(pyX, bX, Math.fma(pyY, bY, Math.fma(pyZ, bZ, pyW)));
    if (da < 0.0f && db < 0.0f)
        return false;
    if (da * db < 0.0f) {
        float p = Math.abs(da) / Math.abs(db - da);
        float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
        if (da < 0.0f) {
            aX = dx; aY = dy; aZ = dz;
        } else {
            bX = dx; bY = dy; bZ = dz;
        }
    }
    da = Math.fma(nzX, aX, Math.fma(nzY, aY, Math.fma(nzZ, aZ, nzW)));
    db = Math.fma(nzX, bX, Math.fma(nzY, bY, Math.fma(nzZ, bZ, nzW)));
    if (da < 0.0f && db < 0.0f)
        return false;
    if (da * db < 0.0f) {
        float p = Math.abs(da) / Math.abs(db - da);
        float dx = Math.fma(bX - aX, p, aX), dy = Math.fma(bY - aY, p, aY), dz = Math.fma(bZ - aZ, p, aZ);
        if (da < 0.0f) {
            aX = dx; aY = dy; aZ = dz;
        } else {
            bX = dx; bY = dy; bZ = dz;
        }
    }
    da = Math.fma(pzX, aX, Math.fma(pzY, aY, Math.fma(pzZ, aZ, pzW)));
    db = Math.fma(pzX, bX, Math.fma(pzY, bY, Math.fma(pzZ, bZ, pzW)));
    return da >= 0.0f || db >= 0.0f;
}
xupwup commented 3 years ago

If the product of da and db is negative, then da must have been different to db, doesn't it? Because the product can only be negative when the signs of the factors differ.

Yep, you're right. Well spotted