Skip to content

Commit d5d00cc

Browse files
authored
Merge pull request #215 from compas-dev/feature/linewidth
Line width is back!
2 parents e3a403f + 3943bf9 commit d5d00cc

File tree

8 files changed

+421
-72
lines changed

8 files changed

+421
-72
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
### Changed
1313

14+
* Made `linewidth` working again through `GeometryShader`.
15+
1416
### Removed
1517

1618

scripts/example.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from compas.datastructures import Mesh
44
from compas.geometry import Box
55
from compas.geometry import Frame
6+
from random import random
67
from compas_viewer.viewer import Viewer
78

89
viewer = Viewer(show_grid=True)
@@ -17,9 +18,13 @@
1718
for j in range(M):
1819
viewer.scene.add(
1920
Box(0.5, 0.5, 0.5, Frame([i, j, 0], [1, 0, 0], [0, 1, 0])),
20-
linecolor=Color.white(),
21+
linecolor=Color.from_i(random()),
2122
facecolor=Color(i / N, j / M, 0.0),
2223
name=f"Box_{i}_{j}",
24+
linewidth=3 * random(),
25+
show_points=True,
26+
pointcolor=Color.from_i(random()),
27+
pointsize=10
2328
)
2429

2530
viewer.show()

src/compas_viewer/renderer/renderer.py

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ def __init__(self, viewer: "Viewer"):
6262
self.grid = None
6363

6464
self.shader_model: Shader = None
65+
self.shader_lines: Shader = None
6566
self._shader_tag: Shader = None
6667
self.shader_arrow: Shader = None
6768
self.shader_instance: Shader = None
@@ -108,6 +109,9 @@ def rendermode(self, rendermode):
108109
self.shader_model.bind()
109110
self.shader_model.uniform1f("opacity", self._opacity)
110111
self.shader_model.release()
112+
self.shader_lines.bind()
113+
self.shader_lines.uniform1f("opacity", self._opacity)
114+
self.shader_lines.release()
111115
self.update()
112116

113117
@property
@@ -197,7 +201,6 @@ def initializeGL(self):
197201
"""
198202
GL.glClearColor(*self.viewer.config.renderer.backgroundcolor.rgba)
199203
GL.glPolygonOffset(1.0, 1.0)
200-
GL.glEnable(GL.GL_POLYGON_OFFSET_FILL)
201204
GL.glEnable(GL.GL_CULL_FACE)
202205
GL.glCullFace(GL.GL_BACK)
203206
GL.glEnable(GL.GL_DEPTH_TEST)
@@ -432,6 +435,16 @@ def init(self):
432435
self.shader_model.uniformBuffer("settingsBuffer", self.buffer_manager.settings_texture, unit=1)
433436
self.shader_model.release()
434437

438+
self.shader_lines = Shader(name="modellines")
439+
self.shader_lines.bind()
440+
self.shader_lines.uniform4x4("projection", projection)
441+
self.shader_lines.uniform4x4("viewworld", viewworld)
442+
self.shader_lines.uniform1f("opacity", self.opacity)
443+
self.shader_lines.uniform3f("selection_color", self.viewer.config.renderer.selectioncolor.rgb)
444+
self.shader_lines.uniformBuffer("transformBuffer", self.buffer_manager.transform_texture, unit=0)
445+
self.shader_lines.uniformBuffer("settingsBuffer", self.buffer_manager.settings_texture, unit=1)
446+
self.shader_lines.release()
447+
435448
def update_projection(self, w=None, h=None):
436449
"""
437450
Update the projection matrix.
@@ -451,6 +464,10 @@ def update_projection(self, w=None, h=None):
451464
self.shader_model.uniform4x4("projection", projection)
452465
self.shader_model.release()
453466

467+
self.shader_lines.bind()
468+
self.shader_lines.uniform4x4("projection", projection)
469+
self.shader_lines.release()
470+
454471
self.shader_tag.bind()
455472
self.shader_tag.uniform4x4("projection", projection)
456473
self.shader_tag.release()
@@ -508,21 +525,34 @@ def paint(self, is_instance: bool = False):
508525
viewworld = self.camera.viewworld()
509526
self.update_projection()
510527

511-
# rebind the model shader
512-
self.shader_model.bind()
513-
self.shader_model.uniform1f("opacity", self.opacity)
514-
self.shader_model.uniformBuffer("transformBuffer", self.buffer_manager.transform_texture, unit=0)
515-
self.shader_model.uniformBuffer("settingsBuffer", self.buffer_manager.settings_texture, unit=1)
516-
517-
self.shader_model.uniform4x4("viewworld", viewworld)
518-
self.shader_model.uniform1i("is_instance", is_instance)
519-
528+
# Update object settings (visibility, selection, etc.)
529+
self.buffer_manager.update_settings()
530+
531+
# Update uniforms for both shaders
532+
for shader in [self.shader_model, self.shader_lines]:
533+
shader.bind()
534+
shader.uniform1f("opacity", self.opacity)
535+
shader.uniformBuffer("transformBuffer", self.buffer_manager.transform_texture, unit=0)
536+
shader.uniformBuffer("settingsBuffer", self.buffer_manager.settings_texture, unit=1)
537+
shader.uniform4x4("viewworld", viewworld)
538+
shader.uniform1i("is_instance", is_instance)
539+
shader.release()
540+
541+
# Update viewport uniform for line shader
542+
self.shader_lines.bind()
543+
self.shader_lines.uniform2f("viewport", (self.width(), self.height()))
544+
self.shader_lines.release()
545+
546+
# Draw the grid
520547
if self.viewer.config.renderer.show_grid:
548+
self.shader_model.bind()
521549
self.grid.draw(self.shader_model)
550+
self.shader_model.release()
522551

523552
# Draw all the objects in the buffer manager
524553
self.buffer_manager.draw(
525554
self.shader_model,
555+
self.shader_lines,
526556
self.rendermode,
527557
is_instance=is_instance,
528558
)
@@ -531,7 +561,6 @@ def paint(self, is_instance: bool = False):
531561
tag_objs = [obj for obj in self.viewer.scene.objects if isinstance(obj, TagObject)]
532562
if tag_objs:
533563
# release the model shader and bind the tag shader
534-
self.shader_model.release()
535564
self.shader_tag.bind()
536565
self.shader_tag.uniform4x4("viewworld", viewworld)
537566
for obj in tag_objs:
@@ -540,7 +569,7 @@ def paint(self, is_instance: bool = False):
540569

541570
# draw 2D box for multi-selection
542571
if self.viewer.mouse.is_tracing_a_window:
543-
# Ensure the shader is bound before drawing
572+
# Ensure the model shader is bound before drawing
544573
self.shader_model.bind()
545574

546575
# Draw the selection box
@@ -554,6 +583,7 @@ def paint(self, is_instance: bool = False):
554583
self.width(),
555584
self.height(),
556585
)
586+
self.shader_model.release()
557587

558588
# Unbind once we're done
559589
GL.glBindVertexArray(0)
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#version 330 core
2+
3+
// Inputs
4+
in vec4 g_vertex_color;
5+
in vec3 g_ec_pos;
6+
in float g_is_selected;
7+
in float g_show;
8+
in float g_show_points;
9+
in float g_show_lines;
10+
in float g_show_faces;
11+
in vec4 g_instance_color;
12+
in float g_object_opacity;
13+
14+
// Uniforms
15+
uniform float opacity;
16+
uniform bool is_lighted;
17+
uniform vec3 selection_color;
18+
uniform int element_type;
19+
uniform bool is_instance;
20+
uniform bool is_grid;
21+
22+
out vec4 fragColor;
23+
24+
void main() {
25+
// Early visibility checks
26+
if (g_show == 0.0 ||
27+
(element_type == 0 && g_show_points == 0.0) ||
28+
(element_type == 1 && g_show_lines == 0.0) ||
29+
(element_type == 2 && g_show_faces == 0.0) ||
30+
(is_instance && is_grid)) {
31+
discard;
32+
}
33+
34+
// Handle instanced objects
35+
if (is_instance) {
36+
fragColor = g_instance_color;
37+
return;
38+
}
39+
40+
// Calculate color and alpha
41+
float alpha = opacity * g_object_opacity * g_vertex_color.a;
42+
vec3 color = g_vertex_color.rgb;
43+
44+
// Handle selection highlighting
45+
if (g_is_selected > 0.5) {
46+
color = selection_color * (element_type == 0 ? 0.9 :
47+
element_type == 1 ? 0.8 :
48+
1.0);
49+
alpha = max(alpha, 0.5);
50+
}
51+
52+
// Draw circular points
53+
if (element_type == 0) {
54+
vec2 center = gl_PointCoord - vec2(0.5);
55+
if (length(center) > 0.5) {
56+
discard;
57+
}
58+
}
59+
60+
// Apply lighting if needed
61+
if (is_lighted && !is_grid) {
62+
vec3 ec_normal = normalize(cross(dFdx(g_ec_pos), dFdy(g_ec_pos)));
63+
vec3 L = normalize(-g_ec_pos);
64+
fragColor = vec4(color * dot(ec_normal, L), alpha);
65+
} else {
66+
fragColor = vec4(color, alpha);
67+
}
68+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
#version 330 core
2+
3+
layout (lines) in;
4+
layout (triangle_strip, max_vertices = 4) out;
5+
6+
// from vertex shader
7+
in vec4 vertex_color[];
8+
in vec3 ec_pos[];
9+
in float is_selected[];
10+
in float show[];
11+
in float show_points[];
12+
in float show_lines[];
13+
in float show_faces[];
14+
in vec4 instance_color[];
15+
in float object_opacity[];
16+
in float linewidth[];
17+
18+
// to fragment shader
19+
out vec4 g_vertex_color;
20+
out vec3 g_ec_pos;
21+
out float g_is_selected;
22+
out float g_show;
23+
out float g_show_points;
24+
out float g_show_lines;
25+
out float g_show_faces;
26+
out vec4 g_instance_color;
27+
out float g_object_opacity;
28+
29+
uniform vec2 viewport; // The (width, height) of the viewport in pixels
30+
31+
void main() {
32+
vec2 p1 = gl_in[0].gl_Position.xy / gl_in[0].gl_Position.w;
33+
vec2 p2 = gl_in[1].gl_Position.xy / gl_in[1].gl_Position.w;
34+
35+
vec2 dir = normalize(p2 - p1);
36+
vec2 normal = vec2(-dir.y, dir.x);
37+
38+
float width = linewidth[0];
39+
vec2 offset = normal * width / viewport;
40+
41+
// Vertex 1
42+
gl_Position = vec4((p1 - offset) * gl_in[0].gl_Position.w, gl_in[0].gl_Position.zw);
43+
g_vertex_color = vertex_color[0];
44+
g_ec_pos = ec_pos[0];
45+
g_is_selected = is_selected[0];
46+
g_show = show[0];
47+
g_show_points = show_points[0];
48+
g_show_lines = show_lines[0];
49+
g_show_faces = show_faces[0];
50+
g_instance_color = instance_color[0];
51+
g_object_opacity = object_opacity[0];
52+
EmitVertex();
53+
54+
// Vertex 2
55+
gl_Position = vec4((p1 + offset) * gl_in[0].gl_Position.w, gl_in[0].gl_Position.zw);
56+
EmitVertex();
57+
58+
// Vertex 3
59+
gl_Position = vec4((p2 - offset) * gl_in[1].gl_Position.w, gl_in[1].gl_Position.zw);
60+
g_vertex_color = vertex_color[1];
61+
g_ec_pos = ec_pos[1];
62+
g_is_selected = is_selected[1];
63+
g_show = show[1];
64+
g_show_points = show_points[1];
65+
g_show_lines = show_lines[1];
66+
g_show_faces = show_faces[1];
67+
g_instance_color = instance_color[1];
68+
g_object_opacity = object_opacity[1];
69+
EmitVertex();
70+
71+
// Vertex 4
72+
gl_Position = vec4((p2 + offset) * gl_in[1].gl_Position.w, gl_in[1].gl_Position.zw);
73+
EmitVertex();
74+
75+
EndPrimitive();
76+
}

0 commit comments

Comments
 (0)