From 21f16c652da7ce7090bedce47fe916de7f47e3cc Mon Sep 17 00:00:00 2001 From: Licini Date: Wed, 14 Aug 2024 23:12:30 +0200 Subject: [PATCH] Use triangle_stripe for Tags --- CHANGELOG.md | 2 + scripts/tag.py | 14 +++--- src/compas_viewer/renderer/renderer.py | 2 +- src/compas_viewer/renderer/shaders/shader.py | 9 +--- src/compas_viewer/renderer/shaders/tag.frag | 12 +++-- src/compas_viewer/renderer/shaders/tag.vert | 41 ++++++++++++++--- src/compas_viewer/scene/tagobject.py | 46 ++++++++++++++++---- 7 files changed, 89 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 510bd83509..f584dac82b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,10 +15,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `SettingLayout` to manage complex layout with config input. * Added `robot.py` example. * Added `ortho` option to view. +* Added `vertical_align` and `horizontal_align` options to `Tag`. ### Changed * Fixed `GroupObject` `pointcolor` not found error with impliment `exclude_type_list`. +* Fixed `Tag` inconsistent height issue. ### Removed diff --git a/scripts/tag.py b/scripts/tag.py index 8414b0d25c..93659af4d7 100644 --- a/scripts/tag.py +++ b/scripts/tag.py @@ -1,13 +1,11 @@ - -from compas.geometry import Box from compas_viewer import Viewer from compas_viewer.scene import Tag -box1 = Box.from_width_height_depth(5, 1, 1) -box2 = Box.from_width_height_depth(1, 5, 1) -t = Tag("EN", (5, 1, 1), height=50) -viewer = Viewer() +t1 = Tag("Align to left", (0, 0, 0), height=50) # default align is left and bottom +t2 = Tag("Align to center", (0, 5, 0), height=50, horizontal_align="center", vertical_align="center") +t3 = Tag("Align to right", (0, 10, 0), height=50, horizontal_align="right", vertical_align="top") +t4 = Tag("Absolute height", (5, 0, 0), absolute_height=True, height=100) -# Simple list of objects -group1 = viewer.scene.add([box1, box2, t]) +viewer = Viewer() +viewer.scene.add([t1, t2, t3, t4]) viewer.show() diff --git a/src/compas_viewer/renderer/renderer.py b/src/compas_viewer/renderer/renderer.py index ca63dcf852..45ffc314a9 100644 --- a/src/compas_viewer/renderer/renderer.py +++ b/src/compas_viewer/renderer/renderer.py @@ -597,7 +597,7 @@ def paint(self): self.shader_tag.bind() self.shader_tag.uniform4x4("viewworld", viewworld) for obj in tag_objs: - obj.draw(self.shader_tag, self.camera.position) + obj.draw(self.shader_tag, self.camera.position, self.width(), self.height()) self.shader_tag.release() # draw 2D box for multi-selection diff --git a/src/compas_viewer/renderer/shaders/shader.py b/src/compas_viewer/renderer/shaders/shader.py index f54fbdf01e..b7116451ef 100644 --- a/src/compas_viewer/renderer/shaders/shader.py +++ b/src/compas_viewer/renderer/shaders/shader.py @@ -204,16 +204,11 @@ def draw_texts(self, elements: Any = None, n: int = 0): n : int, optional The number of elements. """ - GL.glDisable(GL.GL_POINT_SMOOTH) - GL.glEnable(GL.GL_POINT_SPRITE) - GL.glEnable(GL.GL_PROGRAM_POINT_SIZE) if elements: GL.glBindBuffer(GL.GL_ELEMENT_ARRAY_BUFFER, elements) - GL.glDrawElements(GL.GL_POINTS, n, GL.GL_UNSIGNED_INT, None) + GL.glDrawElements(GL.GL_TRIANGLE_STRIP, n, GL.GL_UNSIGNED_INT, None) else: - GL.glDrawArrays(GL.GL_POINTS, 0, GL.GL_BUFFER_SIZE) - GL.glDisable(GL.GL_POINT_SPRITE) - GL.glEnable(GL.GL_POINT_SMOOTH) + GL.glDrawArrays(GL.GL_TRIANGLE_STRIP, 0, GL.GL_BUFFER_SIZE) def draw_arrows(self, elements: Any, n: int, width: float, background: bool = False): """ diff --git a/src/compas_viewer/renderer/shaders/tag.frag b/src/compas_viewer/renderer/shaders/tag.frag index 4095d42887..0f22a12797 100644 --- a/src/compas_viewer/renderer/shaders/tag.frag +++ b/src/compas_viewer/renderer/shaders/tag.frag @@ -5,14 +5,12 @@ uniform sampler2D tex; uniform int text_num; uniform vec3 text_color; +varying vec2 texcoord; + void main() -{ - vec2 xy = gl_PointCoord; - xy.y -= 0.5; - xy.y *= text_num; - if (xy.y > 0 || xy.y < -1) { - discard; - } +{ + vec2 xy = texcoord; + xy.y = 1.0 - xy.y; float a = texture2D(tex, xy).r; gl_FragColor = vec4(text_color, a); if (a <= 0){ diff --git a/src/compas_viewer/renderer/shaders/tag.vert b/src/compas_viewer/renderer/shaders/tag.vert index 72ad56573b..6850114512 100644 --- a/src/compas_viewer/renderer/shaders/tag.vert +++ b/src/compas_viewer/renderer/shaders/tag.vert @@ -5,12 +5,43 @@ attribute vec3 position; uniform mat4 projection; uniform mat4 viewworld; uniform mat4 transform; +uniform float screen_aspect; +uniform float screen_height; +uniform float text_aspect; +uniform float text_height; +uniform vec3 text_position; +uniform int vertical_align; +uniform int horizontal_align; -uniform int text_height; -uniform int text_num; + +varying vec2 texcoord; void main() -{ - gl_PointSize = text_height * text_num; - gl_Position = projection * viewworld * transform * vec4(position, 1.0); +{ + + texcoord = vec2(position.x, position.y); + + vec2 position = vec2(position.x, position.y); + + if (horizontal_align == 0) { + position.x -= 0.5; + } + else if (horizontal_align == 1) { + position.x -= 1.0; + } + + if (vertical_align == 0) { + position.y -= 0.5; + } + else if (vertical_align == 1) { + position.y -= 1.0; + } + + + vec4 screen_position = projection * viewworld * vec4(text_position, 1.0); + vec2 adjustedPos = vec2(position.x / screen_aspect * text_aspect, position.y) * text_height / screen_height; + vec4 offset = vec4(adjustedPos * screen_position.w, 0.0, 0.0); + screen_position += offset; + gl_Position = screen_position; + } diff --git a/src/compas_viewer/scene/tagobject.py b/src/compas_viewer/scene/tagobject.py index 4ffae5cc15..351ae9ec4e 100644 --- a/src/compas_viewer/scene/tagobject.py +++ b/src/compas_viewer/scene/tagobject.py @@ -80,6 +80,8 @@ def __init__( height: float = 50, absolute_height: bool = False, font: Optional[PathLike] = None, + vertical_align: str = "bottom", + horizontal_align: str = "left", ): super().__init__() self.text = text @@ -88,6 +90,8 @@ def __init__( self.height = height self.absolute_height = absolute_height self.font = font or FONT + self.vertical_align = vertical_align + self.horizontal_align = horizontal_align def transform(self, transformation): """Transform the tag. @@ -109,12 +113,31 @@ class TagObject(ViewerSceneObject, GeometryObject): geometry: Tag + VERTICAL_ALIGN = {"top": 1, "center": 0, "bottom": -1} + HORIZONTAL_ALIGN = {"left": -1, "center": 0, "right": 1} + def make_buffers(self): + + positions = [ + 0, + 0, + 0, + 1, + 0, + 0, + 0, + 1, + 0, + 1, + 1, + 0, + ] + self._text_buffer = { - "positions": make_vertex_buffer(self.geometry.position), - "elements": make_index_buffer([0]), + "positions": make_vertex_buffer(positions), + "elements": make_index_buffer([0, 1, 2, 3]), "text_texture": self.make_text_texture(), - "n": 1, + "n": 4, } def make_text_texture(self): @@ -142,8 +165,7 @@ def make_text_texture(self): # The width and height of the texture must be a multiple of 4 total_width = (total_width + 3) // 4 * 4 - # The height is doubled because the text is rendered in the middle of the texture - max_height = (max_height * 2 + 3) // 4 * 4 + max_height = (max_height + 10 + 3) // 4 * 4 string_buffer = zeros(shape=(max_height, total_width), dtype="uint8") @@ -186,6 +208,8 @@ def make_text_texture(self): GL.GL_UNSIGNED_BYTE, string_buffer, ) + + self.text_aspect = total_width / 50 return texture def _calculate_text_height(self, camera_position): @@ -195,19 +219,23 @@ def _calculate_text_height(self, camera_position): else: return self.geometry.height - def draw(self, shader, camera_position): + def draw(self, shader, camera_position, width, height): """Draw the object from its buffers""" shader.enable_attribute("position") if self.worldtransformation is not None: shader.uniform4x4("transform", self.worldtransformation.matrix) shader.uniform1f("object_opacity", self.opacity) - shader.uniform1i("text_height", self._calculate_text_height(camera_position)) - shader.uniform1i("text_num", len(self.geometry.text)) + shader.uniform1f("screen_aspect", width / height) + shader.uniform1f("screen_height", height) + shader.uniform1f("text_aspect", self.text_aspect) + shader.uniform1f("text_height", self._calculate_text_height(camera_position)) + shader.uniform3f("text_position", self.geometry.position) shader.uniform3f("text_color", self.geometry.color) + shader.uniform1i("vertical_align", self.VERTICAL_ALIGN[self.geometry.vertical_align]) + shader.uniform1i("horizontal_align", self.HORIZONTAL_ALIGN[self.geometry.horizontal_align]) shader.uniformText("text_texture", self._text_buffer["text_texture"]) shader.bind_attribute("position", self._text_buffer["positions"]) shader.draw_texts(elements=self._text_buffer["elements"], n=self._text_buffer["n"]) - shader.uniform1i("is_text", 0) shader.uniform1f("object_opacity", 1) shader.disable_attribute("position")