aboutsummaryrefslogtreecommitdiffstats
path: root/src/graphui
diff options
context:
space:
mode:
authorSven Göthel <sgothel@jausoft.com>2024-01-20 05:01:38 +0100
committerSven Göthel <sgothel@jausoft.com>2024-01-20 05:01:38 +0100
commitc1531c3d99b19032040018b9414263b0d3000147 (patch)
tree93ad05df0398d430884350166a88371f82143947 /src/graphui
parent5cca51e32999a882e2a5f00cb45ecafc824ffd86 (diff)
Graph Clipping: Use Frustum Clipping using AABBox -> Mv transformed Cube -> Frustum mapping + GraphUI Support
AABBox clipping naturally couldn't be transformed into 3D Model-View (Mv) Space, as it is axis aligned and only provided 2 points (min/max). Therefor we map the Group's AABBox to a 8-point Cube, perform the Mv-transformation and then produce the 6-plane Frustum. As before, we cull fully outside shapes within the Group's draw method and perform fragment clipping with same Frustum planes in the shader. With clipping enabled, the 3D z-axis getBounds() depth will be slightly increased for functional Frustum operation. This is also done for setFixedSize(Vec2f). The Frustum planes are copied to the Graph shader via float[4*6] -> uniform vec4 gcu_ClipFrustum[6]; // L, R, B, T, N, F each {n.x, n.y, n.z, d} +++ Concludes related work of below commits - 1040bed4ecc6f4598ea459f1073a9240583fc3c3 - 5cca51e32999a882e2a5f00cb45ecafc824ffd86
Diffstat (limited to 'src/graphui')
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Group.java111
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/Scene.java4
-rw-r--r--src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java20
3 files changed, 97 insertions, 38 deletions
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Group.java b/src/graphui/classes/com/jogamp/graph/ui/Group.java
index 1202752b1..d1156120a 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Group.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Group.java
@@ -42,6 +42,8 @@ import com.jogamp.math.Vec2f;
import com.jogamp.math.Vec3f;
import com.jogamp.math.Vec4f;
import com.jogamp.math.geom.AABBox;
+import com.jogamp.math.geom.Cube;
+import com.jogamp.math.geom.Frustum;
import com.jogamp.math.util.PMVMatrix4f;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLProfile;
@@ -77,14 +79,15 @@ public class Group extends Shape implements Container {
}
private final List<Shape> shapes = new CopyOnWriteArrayList<Shape>();
- private final Vec2f fixedSize = new Vec2f();
+ /** Enforced fixed size. In case z-axis is NaN, its 3D z-axis will be adjusted. */
+ private final Vec3f fixedSize = new Vec3f();
private Layout layouter;
private Rectangle border = null;
private boolean relayoutOnDirtyShapes = true;
private boolean widgetMode = false;
private boolean clipOnBounds = false;
- private AABBox clipBBox = null;
+ private Frustum clipFrustum = null;
/**
* Create a group of {@link Shape}s w/o {@link Group.Layout}.
@@ -118,43 +121,65 @@ public class Group extends Shape implements Container {
/** Set {@link Group.Layout}. */
public Group setLayout(final Layout l) { layouter = l; return this; }
- /** Enforce size of this group to given dimension. */
- public Group setFixedSize(final Vec2f v) { fixedSize.set(v); return this; }
- public Vec2f getFixedSize() { return fixedSize; }
+ /** Enforce size of this group for all given 3 dimensions {@link #getBounds()} without adjusting 3D z-axis like {@link #setFixedSize(Vec2f)}. */
+ public Group setFixedSize(final Vec3f v) { fixedSize.set(v); return this; }
+ /**
+ * Enforce size of this group to given 2 dimensions,
+ * adjusting the 3D z-axis {@link #getBounds()} giving room for potential clipping via {@link #setClipOnBounds(boolean)} or {@link #setClipFrustum(Frustum)}.
+ * @see #setFixedSize(Vec3f)
+ */
+ public Group setFixedSize(final Vec2f v) { fixedSize.set(v.x(), v.y(), Float.NaN); return this; }
+ /** Returns borrowed fixed size instance, see {@link #setFixedSize(Vec3f)} and {@link #setFixedSize(Vec2f)}. */
+ public Vec3f getFixedSize() { return fixedSize; }
+ /** Returns given {@link Vec2f} instance set with 2 dimensions, see {@link #setFixedSize(Vec2f)}. */
+ public Vec2f getFixedSize(final Vec2f out) { out.set(fixedSize.x(), fixedSize.y()); return out; }
/**
- * Enable {@link AABBox} clipping on {@link #getBounds()} for this group and its shapes as follows
+ * Enable {@link Frustum} clipping on {@link #getBounds()} for this group and its shapes as follows
* <ul>
* <li>Discard {@link Shape} {@link #draw(GL2ES2, RegionRenderer) rendering} if not intersecting {@code clip-box}.</li>
* <li>Otherwise perform pixel-accurate clipping inside the shader to {@code clip-box}.</li>
* </ul>
* <p>
- * {@link #setClipBBox(AABBox)} takes precedence over {@link #setClipOnBounds(boolean)}.
+ * {@link #setClipFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
+ * </p>
+ * <p>
+ * With clipping enabled, the 3D z-axis {@link #getBounds()} depth
+ * will be slightly increased for functional {@link Frustum} operation.
* </p>
* @param v boolean to toggle clipping
* @return this instance for chaining
- * @see #setClipBBox(AABBox)
+ * @see #setClipFrustum(Frustum)
+ * @see #setFixedSize(Vec2f)
+ * @see #setFixedSize(Vec3f)
*/
public Group setClipOnBounds(final boolean v) { clipOnBounds = v; return this; }
/** Returns {@link #setClipOnBounds(boolean)} value */
public boolean getClipOnBounds() { return clipOnBounds; }
/**
- * Enable {@link AABBox} clipping on explicit given pre-multiplied Mv-matrix {@code clip-box} as follows
+ * Enable {@link Frustum} clipping on explicit given pre-multiplied w/ Mv-matrix {@code clip-box}
+ * for this group and its shapes as follows
* <ul>
* <li>Discard {@link Shape} {@link #draw(GL2ES2, RegionRenderer) rendering} if not intersecting {@code clip-box}.</li>
* <li>Otherwise perform pixel-accurate clipping inside the shader to {@code clip-box}.</li>
* </ul>
* <p>
- * {@link #setClipBBox(AABBox)} takes precedence over {@link #setClipOnBounds(boolean)}.
+ * {@link #setClipFrustum(Frustum)} takes precedence over {@link #setClipOnBounds(boolean)}.
+ * </p>
+ * <p>
+ * With clipping enabled, the 3D z-axis {@link #getBounds()} depth
+ * will be slightly increased for functional {@link Frustum} operation.
* </p>
- * @param v {@link AABBox} pre-multiplied Mv-matrix
+ * @param v {@link Frustum} pre-multiplied w/ Mv-matrix
* @return this instance for chaining
* @see #setClipOnBounds(boolean)
+ * @see #setFixedSize(Vec2f)
+ * @see #setFixedSize(Vec3f)
*/
- public Group setClipBBox(final AABBox v) { clipBBox = v; return this; }
- /** Returns {@link #setClipBBox(AABBox)} value */
- public AABBox getClipBBox() { return clipBBox; }
+ public Group setClipFrustum(final Frustum v) { clipFrustum = v; return this; }
+ /** Returns {@link #setClipFrustum(Frustum)} value */
+ public Frustum getClipFrustum() { return clipFrustum; }
@Override
public int getShapeCount() { return shapes.size(); }
@@ -281,12 +306,12 @@ public class Group extends Shape implements Container {
final Object[] shapesS = shapes.toArray();
Arrays.sort(shapesS, (Comparator)Shape.ZAscendingComparator);
- final boolean useClipBBox = null != clipBBox;
- if( useClipBBox || clipOnBounds ) {
- final AABBox origClipBox = renderer.getClipBBox();
+ final boolean useClipFrustum = null != clipFrustum;
+ if( useClipFrustum || clipOnBounds ) {
+ final Frustum origClipFrustum = renderer.getClipFrustum();
- final AABBox clipBox = useClipBBox ? clipBBox : box.transform(pmv.getMv(), tempBB0);
- renderer.setClipBBox( tempBB1.set(clipBox) ); // Mv pre-multiplied AABBox
+ final Frustum frustumMv = useClipFrustum ? clipFrustum : tempC00.set( box ).transform( pmv.getMv() ).updateFrustumPlanes(tempF00);
+ renderer.setClipFrustum( frustumMv );
final int shapeCount = shapesS.length;
for(int i=0; i<shapeCount; i++) {
@@ -295,16 +320,18 @@ public class Group extends Shape implements Container {
pmv.pushMv();
shape.setTransformMv(pmv);
- final AABBox childBox = shape.getBounds();
- if( clipBox.intersects( childBox.transform(pmv.getMv(), tempBB0) ) &&
- ( !doFrustumCulling || !pmv.getFrustum().isAABBoxOutside( childBox ) ) )
+ final AABBox shapeBox = shape.getBounds();
+ final Cube shapeMv = tempC01.set( shapeBox ).transform( pmv.getMv() );
+
+ if( ( !frustumMv.isOutside( shapeMv ) ) &&
+ ( !doFrustumCulling || !pmv.getFrustum().isOutside( shapeBox ) ) )
{
shape.draw(gl, renderer);
}
pmv.popMv();
}
}
- renderer.setClipBBox(origClipBox);
+ renderer.setClipFrustum(origClipFrustum);
} else {
final int shapeCount = shapesS.length;
for(int i=0; i<shapeCount; i++) {
@@ -323,8 +350,9 @@ public class Group extends Shape implements Container {
border.draw(gl, renderer);
}
}
- private final AABBox tempBB0 = new AABBox(); // OK, synchronized
- private final AABBox tempBB1 = new AABBox(); // OK, synchronized
+ private final Frustum tempF00 = new Frustum(); // OK, synchronized
+ private final Cube tempC00 = new Cube(); // OK, synchronized
+ private final Cube tempC01 = new Cube(); // OK, synchronized
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
@@ -489,12 +517,35 @@ public class Group extends Shape implements Container {
box.resize(h.x() + p.right, h.y() + p.top, l.z());
setRotationPivot( box.getCenter() );
}
- if( !FloatUtil.isZero(fixedSize.x()) && !FloatUtil.isZero(fixedSize.y()) ) {
- final Vec3f low = box.getLow();
- final Vec3f high = new Vec3f(low);
- high.add(fixedSize.x(), fixedSize.y(), 0);
- box.setSize(low, high);
+ final boolean useFixedSize = !FloatUtil.isZero(fixedSize.x()) && !FloatUtil.isZero(fixedSize.y());
+ final boolean useClipping = null != clipFrustum || clipOnBounds;
+ if( useFixedSize || useClipping ) {
+ // final AABBox old = new AABBox(box);
+ final boolean adjustZ = useClipping || ( useFixedSize && Float.isNaN(fixedSize.z()) );
+ final Vec3f lo = box.getLow();
+ if( adjustZ ) {
+ final float oldDepth = box.getDepth();
+ final Vec3f hi;
+ final float zAdjustment = 10f*Scene.DEFAULT_ACTIVE_ZOFFSET_SCALE*Scene.DEFAULT_Z16_EPSILON;
+ lo.add( 0, 0, -(1f*zAdjustment));
+ if( useFixedSize ) {
+ hi = new Vec3f(lo);
+ hi.add(fixedSize.x(), fixedSize.y(), oldDepth+(2f*zAdjustment));
+ } else {
+ hi = box.getHigh();
+ hi.add( 0, 0, oldDepth+(1f*zAdjustment));
+ }
+ box.setSize(lo, hi);
+ } else if( useFixedSize ) {
+ final Vec3f hi = useFixedSize ? new Vec3f(lo) : box.getHigh();
+
+ hi.add(fixedSize.x(), fixedSize.y(), fixedSize.z());
+ box.setSize(lo, hi);
+ }
+ // System.err.println("- was "+old);
+ // System.err.println("- has "+box);
}
+
if( hasBorder() ) {
if( null == border ) {
final int firstRMs = null != firstGS ? firstGS.getRenderModes() : 0;
diff --git a/src/graphui/classes/com/jogamp/graph/ui/Scene.java b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
index 189c75c9d..03cc29097 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/Scene.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/Scene.java
@@ -111,6 +111,8 @@ public final class Scene implements Container, GLEventListener {
public static final float DEFAULT_ZFAR = 7000.0f;
/** Default Z precision on 16-bit depth buffer using {@link #DEFAULT_SCENE_DIST} z-position and {@link #DEFAULT_ZNEAR}. Value is {@code 6.1033297E-6}. */
public static final float DEFAULT_Z16_EPSILON = FloatUtil.getZBufferEpsilon(16 /* zBits */, DEFAULT_SCENE_DIST, DEFAULT_ZNEAR);
+ /** Default Z precision scale, i.e. multiple of {@link #DEFAULT_Z16_EPSILON} for {@link #setActiveShapeZOffsetScale(float)}. Value is {@value}. */
+ public static final float DEFAULT_ACTIVE_ZOFFSET_SCALE = 10f;
/** Default Z precision on 16-bit depth buffer using {@code -1} z-position and {@link #DEFAULT_ZNEAR}. Value is {@code 1.5256461E-4}. */
// public static final float DIST1_Z16_EPSILON = FloatUtil.getZBufferEpsilon(16 /* zBits */, -1, DEFAULT_ZNEAR);
@@ -1033,7 +1035,7 @@ public final class Scene implements Container, GLEventListener {
activeShape = shape;
}
}
- private float activeZOffsetScale = 10f;
+ private float activeZOffsetScale = DEFAULT_ACTIVE_ZOFFSET_SCALE;
/** Returns the active {@link Shape} Z-Offset scale, defaults to {@code 10.0}. */
public float getActiveShapeZOffsetScale() { return activeZOffsetScale; }
diff --git a/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java b/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java
index f84c3cf5a..838a39254 100644
--- a/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java
+++ b/src/graphui/classes/com/jogamp/graph/ui/widgets/RangedGroup.java
@@ -39,6 +39,9 @@ import com.jogamp.math.Vec2f;
import com.jogamp.math.Vec3f;
import com.jogamp.math.Vec4f;
import com.jogamp.math.geom.AABBox;
+import com.jogamp.math.geom.Cube;
+import com.jogamp.math.geom.Frustum;
+import com.jogamp.math.util.PMVMatrix4f;
import com.jogamp.opengl.GL2ES2;
import com.jogamp.opengl.GLProfile;
import com.jogamp.opengl.util.texture.TextureSequence;
@@ -134,7 +137,7 @@ public class RangedGroup extends Widget {
}
public Group getContent() { return content; }
- public Vec2f getContentSize() { return clippedContent.getFixedSize(); }
+ public Vec2f getContentSize(final Vec2f out) { return clippedContent.getFixedSize(out); }
public Group getClippedContent() { return clippedContent; }
public RangeSlider getHorizSlider() { return horizSlider; }
public RangeSlider getVertSlider() { return vertSlider; }
@@ -145,7 +148,7 @@ public class RangedGroup extends Widget {
super.validateImpl(gl, glp);
final AABBox b = content.getBounds();
- final Vec2f contentSize = getContentSize();
+ final Vec3f contentSize = clippedContent.getFixedSize();
contentPosZero.set(0, 0);
if( null != horizSlider ) {
horizSlider.setMinMax(new Vec2f(0, content.getBounds().getWidth()), 0);
@@ -164,12 +167,15 @@ public class RangedGroup extends Widget {
@Override
protected void drawImpl0(final GL2ES2 gl, final RegionRenderer renderer, final Vec4f rgba) {
if( content.isVisible() ) {
- // Mv pre-multiplied AABBox, clippedContent is on same PMV
- final AABBox clipBBox = clippedContent.getBounds().transform(renderer.getMatrix().getMv(), tempBB);
- content.setClipBBox(clipBBox);
+ final PMVMatrix4f pmv = renderer.getMatrix();
+
+ // Mv pre-multiplied Frustum, clippedContent is on same PMV
+ final Frustum clipFrustum = tempC00.set( clippedContent.getBounds() ).transform( pmv.getMv() ).updateFrustumPlanes(tempF00);
+ content.setClipFrustum(clipFrustum);
super.drawImpl0(gl, renderer, rgba);
- content.setClipBBox(null);
+ content.setClipFrustum(null);
}
}
- private final AABBox tempBB = new AABBox(); // OK, synchronized
+ private final Frustum tempF00 = new Frustum(); // OK, synchronized
+ private final Cube tempC00 = new Cube(); // OK, synchronized
}