Commit 1ef9f132 authored by Matthias Betz's avatar Matthias Betz
Browse files

Refine selection: no polygon tint, bigger markers, accurate picking



- Drop the selected-polygon colour tint; selection is shown only by the
  highlight points and edges (scene shader outputs vertex colour directly).
- Larger highlight points (glPointSize) and thicker edges (glLineWidth);
  markers use a constant on-screen pixel size independent of zoom.
- Fix click picking on HiDPI: scale logical click coords to physical
  framebuffer pixels so the sampled pixel is the one under the cursor.

Co-Authored-By: default avatarClaude Opus 4.8 <noreply@anthropic.com>
parent ac4cb04c
...@@ -61,11 +61,8 @@ public class HighlightController { ...@@ -61,11 +61,8 @@ public class HighlightController {
} }
public void changeScaling(double translateZ) { public void changeScaling(double translateZ) {
double scale = Math.abs(translateZ); // GL points/lines are sized in screen pixels, so highlight markers keep a constant on-screen
scale = Math.min(150, scale); // size regardless of zoom distance; nothing to recompute here.
scale = Math.max(10, scale);
scale = scale * 0.01;
viewport.setPointScale((float) (scale * 8));
} }
// ---- point/line accumulation ---- // ---- point/line accumulation ----
......
...@@ -33,10 +33,10 @@ public class GLViewport { ...@@ -33,10 +33,10 @@ public class GLViewport {
// last index set seen; retained so it can be (re)applied after the scene is uploaded or the GL // last index set seen; retained so it can be (re)applied after the scene is uploaded or the GL
// context is recreated (the index buffer only exists once the scene's buffers have been generated) // context is recreated (the index buffer only exists once the scene's buffers have been generated)
private volatile int[] lastIndices; private volatile int[] lastIndices;
private volatile int selectedId = 0;
private volatile boolean wireframe = false; private volatile boolean wireframe = false;
private volatile boolean cull = false; private volatile boolean cull = false;
private volatile float pointScale = 5f; private volatile float pointScale = 14f;
private volatile float lineScale = 4f;
// highlight marker data, uploaded on the GL thread when dirty // highlight marker data, uploaded on the GL thread when dirty
private volatile float[] hlPoints = new float[0]; private volatile float[] hlPoints = new float[0];
...@@ -45,8 +45,8 @@ public class GLViewport { ...@@ -45,8 +45,8 @@ public class GLViewport {
private volatile float[] hlLineColors = new float[0]; private volatile float[] hlLineColors = new float[0];
private volatile boolean highlightsDirty = false; private volatile boolean highlightsDirty = false;
// pick request: screen coords + callback (invoked on FX thread with resolved Object or null) // pick request: logical (JavaFX) screen coords + callback (invoked on FX thread with resolved Object)
private volatile int[] pickRequest; private volatile double[] pickRequest;
private volatile Consumer<Object> pickCallback; private volatile Consumer<Object> pickCallback;
private SceneData currentScene; private SceneData currentScene;
...@@ -78,8 +78,6 @@ public class GLViewport { ...@@ -78,8 +78,6 @@ public class GLViewport {
public void setIndexSet(int[] indices) { pendingIndexSet.set(indices); canvas.repaint(); } public void setIndexSet(int[] indices) { pendingIndexSet.set(indices); canvas.repaint(); }
public void setSelectedId(int id) { selectedId = id; canvas.repaint(); }
public void setWireframe(boolean on) { wireframe = on; canvas.repaint(); } public void setWireframe(boolean on) { wireframe = on; canvas.repaint(); }
public void setCulling(boolean on) { cull = on; canvas.repaint(); } public void setCulling(boolean on) { cull = on; canvas.repaint(); }
...@@ -99,7 +97,7 @@ public class GLViewport { ...@@ -99,7 +97,7 @@ public class GLViewport {
public OrbitCamera camera() { return camera; } public OrbitCamera camera() { return camera; }
public void requestPick(double x, double y, Consumer<Object> callback) { public void requestPick(double x, double y, Consumer<Object> callback) {
pickRequest = new int[]{(int) Math.round(x), (int) Math.round(y)}; pickRequest = new double[]{x, y};
pickCallback = callback; pickCallback = callback;
canvas.repaint(); canvas.repaint();
} }
...@@ -159,11 +157,10 @@ public class GLViewport { ...@@ -159,11 +157,10 @@ public class GLViewport {
sceneProgram.use(gl); sceneProgram.use(gl);
gl.glUniformMatrix4fv(sceneProgram.uniform(gl, "uMVP"), 1, false, mvp, 0); gl.glUniformMatrix4fv(sceneProgram.uniform(gl, "uMVP"), 1, false, mvp, 0);
gl.glUniform1i(sceneProgram.uniform(gl, "uSelectedId"), selectedId);
scene.draw(gl); scene.draw(gl);
overlay.draw(gl, pointScale); overlay.draw(gl, pointScale, lineScale);
int[] req = pickRequest; double[] req = pickRequest;
if (req != null && currentScene != null) { if (req != null && currentScene != null) {
picking.resize(gl, w, h); picking.resize(gl, w, h);
picking.bind(gl); picking.bind(gl);
...@@ -173,9 +170,16 @@ public class GLViewport { ...@@ -173,9 +170,16 @@ public class GLViewport {
pickProgram.use(gl); pickProgram.use(gl);
gl.glUniformMatrix4fv(pickProgram.uniform(gl, "uMVP"), 1, false, mvp, 0); gl.glUniformMatrix4fv(pickProgram.uniform(gl, "uMVP"), 1, false, mvp, 0);
scene.draw(gl); scene.draw(gl);
int id = picking.readId(gl, req[0], req[1]); // click coords are logical (JavaFX) px; the picking buffer is physical px. Scale by the
// framebuffer/canvas ratio so HiDPI displays read the pixel actually under the cursor.
double cw = canvas.getWidth();
double ch = canvas.getHeight();
float sx = cw > 0 ? (float) (w / cw) : 1f;
float sy = ch > 0 ? (float) (h / ch) : 1f;
int px = Math.round((float) req[0] * sx);
int py = Math.round((float) req[1] * sy);
int id = picking.readId(gl, px, py);
Object target = currentScene.pickRegistry().resolve(id); Object target = currentScene.pickRegistry().resolve(id);
selectedId = (target != null) ? id : 0;
Consumer<Object> cb = pickCallback; Consumer<Object> cb = pickCallback;
pickRequest = null; pickRequest = null;
pickCallback = null; pickCallback = null;
......
...@@ -74,11 +74,12 @@ public class HighlightOverlay { ...@@ -74,11 +74,12 @@ public class HighlightOverlay {
gl.glVertexAttribPointer(loc, comp, GL.GL_FLOAT, false, 0, 0L); gl.glVertexAttribPointer(loc, comp, GL.GL_FLOAT, false, 0, 0L);
} }
public void draw(GL3 gl, float pointSize) { public void draw(GL3 gl, float pointSize, float lineWidth) {
if (!created) { if (!created) {
return; return;
} }
if (lineVertexCount > 0) { if (lineVertexCount > 0) {
gl.glLineWidth(lineWidth);
gl.glBindVertexArray(lineVao); gl.glBindVertexArray(lineVao);
gl.glDrawArrays(GL.GL_LINES, 0, lineVertexCount); gl.glDrawArrays(GL.GL_LINES, 0, lineVertexCount);
} }
......
#version 330 core #version 330 core
in vec3 vColor; in vec3 vColor;
flat in int vSelected;
out vec4 fragColor; out vec4 fragColor;
void main() { void main() {
vec3 c = vColor; fragColor = vec4(vColor, 1.0);
if (vSelected == 1) {
c = mix(c, vec3(1.0, 0.0, 0.0), 0.6);
}
fragColor = vec4(c, 1.0);
} }
#version 330 core #version 330 core
layout(location = 0) in vec3 aPos; layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor; layout(location = 1) in vec3 aColor;
layout(location = 2) in int aId;
uniform mat4 uMVP; uniform mat4 uMVP;
uniform int uSelectedId;
out vec3 vColor; out vec3 vColor;
flat out int vSelected;
void main() { void main() {
gl_Position = uMVP * vec4(aPos, 1.0); gl_Position = uMVP * vec4(aPos, 1.0);
vColor = aColor; vColor = aColor;
vSelected = (aId == uSelectedId) ? 1 : 0;
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment