diff options
author | Sven Göthel <[email protected]> | 2024-01-19 06:11:46 +0100 |
---|---|---|
committer | Sven Göthel <[email protected]> | 2024-01-19 06:11:46 +0100 |
commit | 5cca51e32999a882e2a5f00cb45ecafc824ffd86 (patch) | |
tree | 0266df911dc3e39a68def66fc355d18c01c0433e /src | |
parent | 1040bed4ecc6f4598ea459f1073a9240583fc3c3 (diff) |
Frustum: Revise code and its Plane definition to support Cube->Frustum as well as to extract planes for float[] vec4-shader uniforms.
commit 1040bed4ecc6f4598ea459f1073a9240583fc3c3 added AABBox -> Cube -> Frustum mapping (incomplete)
and requires Frustum.Plane.set(..) by normal and point-on-plane for distance.
Frustum.isOutside(Cube) has been added, testing all its 8-points similar to AABBox.
Further all 6 Frustum.Plane shall be extracted to Vec4f and float[],
the latter to pass the whole float[4*6] as a vec4[6] uniform array to the shader.
+++
Constructor, setter and getter have been adjusted accordingly.
Most of the loops have been unrolled.
+++
Method names to query Frustum, i.e. 'is*Outside(<Type>)'
have been reduced to 'isOutside(<Type>)'
where <Type> uniquely indenticates the purpose.
Hence only 'isSphereOutside()' is left over.
Diffstat (limited to 'src')
6 files changed, 203 insertions, 55 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Group.java b/src/graphui/classes/com/jogamp/graph/ui/Group.java index be34ecf3b..1202752b1 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Group.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Group.java @@ -312,7 +312,7 @@ public class Group extends Shape implements Container { if( shape.isVisible() ) { pmv.pushMv(); shape.setTransformMv(pmv); - if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { + if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) { shape.draw(gl, renderer); } pmv.popMv(); @@ -340,7 +340,7 @@ public class Group extends Shape implements Container { pmv.pushMv(); shape.setTransformMv(pmv); - if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { + if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) { shape.drawToSelect(gl, renderer); } pmv.popMv(); diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java index 698aa2d2f..189c75c9d 100644 --- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java +++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java @@ -481,7 +481,7 @@ public final class Scene implements Container, GLEventListener { pmv.pushMv(); shape.setTransformMv(pmv); - if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { + if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) { shape.draw(gl, renderer); } pmv.popMv(); @@ -522,7 +522,7 @@ public final class Scene implements Container, GLEventListener { pmv.pushMv(); shape.setTransformMv(pmv); - if( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( shape.getBounds() ) ) { + if( !doFrustumCulling || !pmv.getFrustum().isOutside( shape.getBounds() ) ) { final float color = ( i + 1f ) / ( shapeCount + 2f ); // FIXME // System.err.printf("drawGL: color %f, index %d of [0..%d[%n", color, i, shapeCount); diff --git a/src/jogl/classes/com/jogamp/graph/curve/Region.java b/src/jogl/classes/com/jogamp/graph/curve/Region.java index 2cbbd5f48..fac65c6ee 100644 --- a/src/jogl/classes/com/jogamp/graph/curve/Region.java +++ b/src/jogl/classes/com/jogamp/graph/curve/Region.java @@ -642,7 +642,7 @@ public abstract class Region { } else { shapeBoxT = shapeBox; } - if( frustum.isAABBoxOutside(shapeBoxT) ) { + if( frustum.isOutside(shapeBoxT) ) { return; } } diff --git a/src/jogl/classes/com/jogamp/math/Matrix4f.java b/src/jogl/classes/com/jogamp/math/Matrix4f.java index beb7b666c..b82f92727 100644 --- a/src/jogl/classes/com/jogamp/math/Matrix4f.java +++ b/src/jogl/classes/com/jogamp/math/Matrix4f.java @@ -1334,13 +1334,11 @@ public class Matrix4f { * using this premultiplied P*MV (column major order) matrix. * <p> * Frustum plane's normals will point to the inside of the viewing frustum, - * as required by this class. - * </p> - * <p> - * Usually called by {@link Frustum#updateFrustumPlanes(Matrix4f)}. + * as required by the {@link Frustum} class. * </p> + * @see Frustum#updateFrustumPlanes(Matrix4f) */ - public void updateFrustumPlanes(final Frustum frustum) { + public Frustum updateFrustumPlanes(final Frustum frustum) { // Left: a = m41 + m11, b = m42 + m12, c = m43 + m13, d = m44 + m14 - [1..4] column-major // Left: a = m30 + m00, b = m31 + m01, c = m32 + m02, d = m33 + m03 - [0..3] column-major { @@ -1415,6 +1413,7 @@ public class Matrix4f { p_n.scale(invLen); p.d *= invLen; } + return frustum; } /** diff --git a/src/jogl/classes/com/jogamp/math/geom/Frustum.java b/src/jogl/classes/com/jogamp/math/geom/Frustum.java index 991e70aac..6efc2529c 100644 --- a/src/jogl/classes/com/jogamp/math/geom/Frustum.java +++ b/src/jogl/classes/com/jogamp/math/geom/Frustum.java @@ -1,5 +1,5 @@ /** - * Copyright 2010-2023 JogAmp Community. All rights reserved. + * Copyright 2010-2024 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are * permitted provided that the following conditions are met: @@ -30,19 +30,21 @@ package com.jogamp.math.geom; import com.jogamp.math.FovHVHalves; import com.jogamp.math.Matrix4f; import com.jogamp.math.Vec3f; +import com.jogamp.math.Vec4f; /** * Providing frustum {@link #getPlanes() planes} derived by different inputs * ({@link #updateFrustumPlanes(float[], int) P*MV}, ..) used to classify objects * <ul> - * <li> {@link #classifyPoint(float[]) point} </li> - * <li> {@link #classifySphere(float[], float) sphere} </li> + * <li> {@link #classifyPoint(Vec3f) point} </li> + * <li> {@link #classifySphere(Vec3f, float) sphere} </li> * </ul> * and to test whether they are outside * <ul> - * <li> {@link #isPointOutside(float[]) point} </li> - * <li> {@link #isSphereOutside(float[], float) sphere} </li> - * <li> {@link #isAABBoxOutside(AABBox) bounding-box} </li> + * <li> {@link #isOutside(Vec3f) point} </li> + * <li> {@link #isSphereOutside(Vec3f, float) sphere} </li> + * <li> {@link #isOutside(AABBox) bounding-box} </li> + * <li> {@link #isOutside(Cube) cube} </li> * </ul> * * <p> @@ -119,13 +121,35 @@ public class Frustum { * @see #updateFrustumPlanes(float[], int) */ public Frustum() { - for (int i = 0; i < 6; ++i) { - planes[i] = new Plane(); - } + planes[LEFT ] = new Plane(); + planes[RIGHT ] = new Plane(); + planes[BOTTOM] = new Plane(); + planes[TOP ] = new Plane(); + planes[NEAR ] = new Plane(); + planes[FAR ] = new Plane(); + } + + public Frustum(final Frustum o) { + planes[LEFT ] = new Plane(o.planes[LEFT]); + planes[RIGHT ] = new Plane(o.planes[RIGHT]); + planes[BOTTOM] = new Plane(o.planes[BOTTOM]); + planes[TOP ] = new Plane(o.planes[TOP]); + planes[NEAR ] = new Plane(o.planes[NEAR]); + planes[FAR ] = new Plane(o.planes[FAR]); + } + + public Frustum set(final Frustum o) { + planes[LEFT ].set(o.planes[LEFT]); + planes[RIGHT ].set(o.planes[RIGHT]); + planes[BOTTOM].set(o.planes[BOTTOM]); + planes[TOP ].set(o.planes[TOP]); + planes[NEAR ].set(o.planes[NEAR]); + planes[FAR ].set(o.planes[FAR]); + return this; } /** - * Plane equation := dot(n, x - p) = 0 -> ax + bc + cx + d == 0 + * Plane equation := dot(n, x - p) = 0 -> Ax + By + Cz + d == 0 * <p> * In order to work w/ {@link Frustum#isOutside(AABBox) isOutside(..)} methods, * the normals have to point to the inside of the frustum. @@ -133,11 +157,75 @@ public class Frustum { */ public static class Plane { /** Normal of the plane */ - public final Vec3f n = new Vec3f(); + public final Vec3f n; /** Distance to origin */ public float d; + public Plane() { + n = new Vec3f(); + d = 0f; + } + + public Plane(final Plane o) { + n = new Vec3f(o.n); + d = o.d; + } + + public Plane set(final Plane o) { + n.set(o.n); + d = o.d; + return this; + } + + /** + * Setup of plane using 3 points. None of the three points are mutated. + * <p> + * Since this method may not properly define whether the normal points inside the frustum, + * consider using {@link #set(Vec3f, Vec3f)}. + * </p> + * @param p0 point on plane, used as the shared start-point for vec(p0->p1) and vec(p0->p2) + * @param p1 point on plane + * @param p2 point on plane + * @return this plane for chaining + */ + public Plane set(final Vec3f p0, final Vec3f p1, final Vec3f p2) { + final Vec3f v = p1.minus(p0); + final Vec3f u = p2.minus(p0); + n.cross(v, u).normalize(); + d = n.copy().scale(-1).dot(p0); + return this; + } + + /** + * Setup of plane using given normal and one point on plane. The given normal is mutated, the point not mutated. + * @param n normal to plane pointing to the inside of this frustum + * @param p0 point on plane, consider choosing the closest point to origin + * @return this plane for chaining + */ + public Plane set(final Vec3f n, final Vec3f p0) { + this.n.set(n); + d = n.scale(-1).dot(p0); + return this; + } + + /** Sets the given {@link Vec4f} {@code out} to {@code ( n, d )}. Returns {@code out} for chaining. */ + public Vec4f toVec4f(final Vec4f out) { + out.set(n, d); + return out; + } + + /** + * Sets the given {@code [float[off]..float[off+4])} {@code out} to {@code ( n, d )}. + * @param out the {@code float[off+4]} output array + */ + public void toFloats(final float[/* off+4] */] out, final int off) { + out[off+0] = n.x(); + out[off+1] = n.y(); + out[off+2] = n.z(); + out[off+3] = d; + } + /** * Return signed distance of plane to given point. * <ul> @@ -159,7 +247,7 @@ public class Frustum { /** Return distance of plane to given point, see {@link #distanceTo(float, float, float)}. */ public final float distanceTo(final Vec3f p) { - return n.x() * p.x() + n.y() * p.y() + n.z() * p.z() + d; + return n.dot(p) + d; } @Override @@ -201,6 +289,41 @@ public class Frustum { public final Plane[] getPlanes() { return planes; } /** + * Sets each of the given {@link Vec4f}[6] {@code out} to {@link Plane#toVec4f(Vec4f)} + * in the order {@link #LEFT}, {@link #RIGHT}, {@link #BOTTOM}, {@link #TOP}, {@link #NEAR}, {@link #FAR}. + * @param out the {@link Vec4f}[6] output array + * @return {@code out} for chaining + */ + public Vec4f[] getPlanes(final Vec4f[] out) { + planes[LEFT ].toVec4f(out[0]); + planes[RIGHT ].toVec4f(out[1]); + planes[BOTTOM].toVec4f(out[2]); + planes[TOP ].toVec4f(out[3]); + planes[NEAR ].toVec4f(out[4]); + planes[FAR ].toVec4f(out[5]); + return out; + } + + /** Sets the given {@code [float[off]..float[off+4*6])} {@code out} to {@code ( n, d )}. */ + /** + * Sets each of the given {@code [float[off]..float[off+4*6])} {@code out} to {@link Plane#toFloats(float[], int)}, + * i.e. [n.x, n.y, n.z, d, ...]. + * <p> + * Plane order is as follows: {@link #LEFT}, {@link #RIGHT}, {@link #BOTTOM}, {@link #TOP}, {@link #NEAR}, {@link #FAR}. + * </p> + * @param out the {@code float[off+4*6]} output array + * @return {@code out} for chaining + */ + public void getPlanes(final float[/* off+4*6] */] out, final int off) { + planes[LEFT ].toFloats(out, off+4*0); + planes[RIGHT ].toFloats(out, off+4*1); + planes[BOTTOM].toFloats(out, off+4*2); + planes[TOP ].toFloats(out, off+4*3); + planes[NEAR ].toFloats(out, off+4*4); + planes[FAR ].toFloats(out, off+4*5); + } + + /** * Copy the given <code>src</code> planes into this this instance's planes. * @param src the 6 source planes */ @@ -250,9 +373,10 @@ public class Frustum { * Frustum plane's normals will point to the inside of the viewing frustum, * as required by this class. * </p> + * @see Matrix4f#updateFrustumPlanes(Frustum) */ - public void updateFrustumPlanes(final Matrix4f pmv) { - pmv.updateFrustumPlanes(this); + public Frustum updateFrustumPlanes(final Matrix4f pmv) { + return pmv.updateFrustumPlanes(this); } /** @@ -277,45 +401,66 @@ public class Frustum { return c.updateFrustumPlanes(this); } - private static final boolean isOutsideImpl(final Plane p, final AABBox box) { + private static final boolean intersects(final Plane p, final AABBox box) { final Vec3f lo = box.getLow(); final Vec3f hi = box.getHigh(); - if ( p.distanceTo(lo.x(), lo.y(), lo.z()) > 0.0f || - p.distanceTo(hi.x(), lo.y(), lo.z()) > 0.0f || - p.distanceTo(lo.x(), hi.y(), lo.z()) > 0.0f || - p.distanceTo(hi.x(), hi.y(), lo.z()) > 0.0f || - p.distanceTo(lo.x(), lo.y(), hi.z()) > 0.0f || - p.distanceTo(hi.x(), lo.y(), hi.z()) > 0.0f || - p.distanceTo(lo.x(), hi.y(), hi.z()) > 0.0f || - p.distanceTo(hi.x(), hi.y(), hi.z()) > 0.0f ) { - return false; - } - return true; + return p.distanceTo(lo.x(), lo.y(), lo.z()) > 0.0f || + p.distanceTo(hi.x(), lo.y(), lo.z()) > 0.0f || + p.distanceTo(lo.x(), hi.y(), lo.z()) > 0.0f || + p.distanceTo(hi.x(), hi.y(), lo.z()) > 0.0f || + p.distanceTo(lo.x(), lo.y(), hi.z()) > 0.0f || + p.distanceTo(hi.x(), lo.y(), hi.z()) > 0.0f || + p.distanceTo(lo.x(), hi.y(), hi.z()) > 0.0f || + p.distanceTo(hi.x(), hi.y(), hi.z()) > 0.0f; } /** - * Check to see if an axis aligned bounding box is completely outside of the frustum. + * Returns whether the given {@link AABBox} is completely outside of this frustum. * <p> - * Note: If method returns false, the box may only be partially inside. + * Note: If method returns false, the box may only be partially inside, i.e. intersects with this frustum * </p> */ - public final boolean isAABBoxOutside(final AABBox box) { - for (int i = 0; i < 6; ++i) { - if ( isOutsideImpl(planes[i], box) ) { - // fully outside - return true; - } - } - // We make no attempt to determine whether it's fully inside or not. - return false; + public final boolean isOutside(final AABBox box) { + return !intersects(planes[0], box) || + !intersects(planes[1], box) || + !intersects(planes[2], box) || + !intersects(planes[3], box) || + !intersects(planes[4], box) || + !intersects(planes[5], box); + } + + private static final boolean intersects(final Plane p, final Cube c) { + return p.distanceTo(c.lbf) > 0.0f || + p.distanceTo(c.rbf) > 0.0f || + p.distanceTo(c.rtf) > 0.0f || + p.distanceTo(c.ltf) > 0.0f || + p.distanceTo(c.lbn) > 0.0f || + p.distanceTo(c.rbn) > 0.0f || + p.distanceTo(c.rtn) > 0.0f || + p.distanceTo(c.ltn) > 0.0f; + } + + /** + * Returns whether the given {@link Cube} is completely outside of this frustum. + * <p> + * Note: If method returns false, the box may only be partially inside, i.e. intersects with this frustum + * </p> + */ + public final boolean isOutside(final Cube c) { + return !intersects(planes[0], c) || + !intersects(planes[1], c) || + !intersects(planes[2], c) || + !intersects(planes[3], c) || + !intersects(planes[4], c) || + !intersects(planes[5], c); } public static enum Location { OUTSIDE, INSIDE, INTERSECT }; /** - * Check to see if a point is outside, inside or on a plane of the frustum. + * Classifies the given {@link Vec3f} point whether it is outside, inside or on a plane of this frustum. * * @param p the point * @return {@link Location} of point related to frustum planes @@ -335,17 +480,22 @@ public class Frustum { } /** - * Check to see if a point is outside of the frustum. + * Returns whether the given {@link Vec3f} point is completely outside of this frustum. * * @param p the point * @return true if outside of the frustum, otherwise inside or on a plane */ - public final boolean isPointOutside(final Vec3f p) { - return Location.OUTSIDE == classifyPoint(p); + public final boolean isOutside(final Vec3f p) { + return planes[0].distanceTo(p) < 0.0f || + planes[1].distanceTo(p) < 0.0f || + planes[2].distanceTo(p) < 0.0f || + planes[3].distanceTo(p) < 0.0f || + planes[4].distanceTo(p) < 0.0f || + planes[5].distanceTo(p) < 0.0f; } /** - * Check to see if a sphere is outside, intersecting or inside of the frustum. + * Classifies the given sphere whether it is is outside, intersecting or inside of this frustum. * * @param p center of the sphere * @param radius radius of the sphere @@ -368,7 +518,7 @@ public class Frustum { } /** - * Check to see if a sphere is outside of the frustum. + * Returns whether the given sphere is completely outside of this frustum. * * @param p center of the sphere * @param radius radius of the sphere diff --git a/src/jogl/classes/com/jogamp/math/util/PMVMatrix4f.java b/src/jogl/classes/com/jogamp/math/util/PMVMatrix4f.java index ec9876b24..7d02904be 100644 --- a/src/jogl/classes/com/jogamp/math/util/PMVMatrix4f.java +++ b/src/jogl/classes/com/jogamp/math/util/PMVMatrix4f.java @@ -1259,8 +1259,7 @@ public class PMVMatrix4f { if( null == frustum ) { frustum = new Frustum(); } - final Matrix4f mPMv = getPMv(); - frustum.updateFrustumPlanes(mPMv); + getPMv().updateFrustumPlanes(frustum); dirtyBits &= ~FRUSTUM; } return frustum; |