VisPy教程:创建自定义可视化组件之物理尺寸测量
vispy Main repository for Vispy 项目地址: https://gitcode.com/gh_mirrors/vi/vispy
概述
本教程将深入讲解如何在VisPy中创建具有固定像素宽度边框的矩形可视化组件。这是VisPy可视化系统教程系列的第二部分,重点介绍如何处理不同坐标系之间的转换,确保可视化元素在不同缩放级别下保持精确的物理尺寸。
核心问题
在交互式可视化中,我们经常需要确保某些视觉元素(如边框、线条等)保持固定的像素宽度,无论用户如何缩放视图。这看似简单,但在实现上需要考虑多个坐标系的转换:
- 视觉坐标系(Visual):用户定义的逻辑坐标
- 文档坐标系(Document):与物理像素对应的坐标
- 帧缓冲区坐标系(Framebuffer):处理高DPI显示
- 渲染坐标系(Render):最终输出坐标
解决方案架构
顶点布局设计
为了实现矩形边框效果,我们采用10个顶点构成的三角形带(triangle_strip):
1--------------3
| |
| 2------4 | [注意点9和10与点1和2相同]
| | | |
| 8------6 |
| |
7--------------5
坐标系转换流程
- 首先将顶点从视觉坐标转换到文档坐标
- 在文档坐标空间调整边框宽度
- 最后转换到渲染坐标进行绘制
关键技术点
- 使用
visual_to_doc
和doc_to_render
两个变换矩阵 - 在文档坐标空间计算正确的边框偏移量
- 处理非均匀缩放和旋转情况下的边框宽度校正
实现详解
顶点着色器关键逻辑
// 1. 转换到文档坐标
vec4 doc_pos = $visual_to_doc(vec4($position, 0, 1));
// 2. 计算调整方向向量
vec4 doc_x = $visual_to_doc(vec4($adjust_dir.x, 0, 0, 0)) -
$visual_to_doc(vec4(0, 0, 0, 0));
vec4 doc_y = $visual_to_doc(vec4(0, $adjust_dir.y, 0, 0)) -
$visual_to_doc(vec4(0, 0, 0, 0));
// 3. 归一化并计算当前权重
doc_x = normalize(doc_x);
doc_y = normalize(doc_y);
vec4 proj_y_x = dot(doc_x, doc_y) * doc_x;
float cur_width = length(doc_y - proj_y_x);
// 4. 调整顶点位置
adjusted = doc_pos + ($line_width / cur_width) * (doc_x + doc_y);
// 5. 最终转换到渲染坐标
gl_Position = $doc_to_render(adjusted);
Python类实现
class MyRectVisual(visuals.Visual):
def __init__(self, x, y, w, h, weight=4.0):
# 初始化顶点和调整方向缓冲区
self.vert_buffer = gloo.VertexBuffer(...)
self.adj_buffer = gloo.VertexBuffer(...)
# 设置着色器变量
self.shared_program.vert['position'] = self.vert_buffer
self.shared_program.vert['adjust_dir'] = self.adj_buffer
self.shared_program.vert['line_width'] = weight
self.shared_program.frag['color'] = (1, 0, 0, 1)
def _prepare_transforms(self, view):
# 设置坐标变换
tr = view.transforms
view_vert = view.view_program.vert
view_vert['visual_to_doc'] = tr.get_transform('visual', 'document')
view_vert['doc_to_render'] = tr.get_transform('document', 'render')
实际应用
在场景图中测试我们的可视化组件:
canvas = scene.SceneCanvas(keys='interactive', show=True)
view = canvas.central_widget.add_view()
view.camera = 'panzoom'
# 创建两个矩形,其中一个旋转25度
rects = [MyRect(100, 100, 200, 300, parent=view.scene),
MyRect(500, 100, 200, 300, parent=view.scene)]
rects[1].transform = tr
关键知识点总结
- 坐标系理解:掌握VisPy的四层坐标系系统是开发高级可视化的基础
- 变换顺序:正确的变换顺序对保持视觉元素的物理特性至关重要
- 性能考量:在着色器中完成复杂计算比在CPU端处理更高效
- 通用性:这种技术可以推广到其他需要固定物理尺寸的可视化元素
扩展思考
读者可以尝试扩展这个示例:
- 实现圆角矩形边框
- 添加渐变填充效果
- 支持虚线边框样式
- 实现动态调整边框宽度
通过本教程,我们不仅实现了一个具体的可视化组件,更重要的是掌握了在VisPy中处理物理尺寸测量的通用方法,这为开发更复杂、更精确的可视化效果奠定了基础。
vispy Main repository for Vispy 项目地址: https://gitcode.com/gh_mirrors/vi/vispy
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考