Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FrustumIntersection does not have testLine #292

Closed
xupwup opened this issue May 31, 2021 · 3 comments
Closed

FrustumIntersection does not have testLine #292

xupwup opened this issue May 31, 2021 · 3 comments

Comments

@xupwup
Copy link

xupwup commented May 31, 2021

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
Copy link
Member

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 httpdigest added this to the 1.10.2 release milestone May 31, 2021
@httpdigest
Copy link
Member

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):

  • using Math.fma with -Djoml.useMathFma
  • using a better linear interpolation that does not require two multiplications (and is also folded into a single Math.fma):
  • manual loop unrolling to avoid the tableswitch
  • avoiding unnecessary && da != db
  • checked for correctness/equality with your version using fuzzying (a lot of random inputs)
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
Copy link
Author

xupwup commented May 31, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants