使用shader绘制WebGL Scatter各种图形
2023-12-25
Coding
Javascript
WebGL
Plot
👋 ‍️‍️阅读
❤️ 喜欢
💬 评论

使用shader绘制WebGL Scatter各种图形

上次翻译的文章中中,我们成功的使用gl.POINTS渲染出了一个顺滑的圆形。

然而很快新的需求就出现了,一个散点图上显然不能只有圆形,一般散点图都会提供多种图形选择以区分不同的数据系列。 对于圆形,我们只需要简单的判断像素到圆心的距离,对于其他图形则并没有这么简单。

  • 后文图形均为webgl渲染
  • 默认#include <default_main>实现有如下行为,你可以删除后自己定义void main()
    • 为保证在视口内可见,dist函数返回值会被/0.9
    • 默认会渲染10%的边框,即返回值0.9~1.0视为边框

三角形

首先我们想到的是最简单的三角形,我们需要在正方形的剪裁空间内绘制出一个正三角形。 为了让三角形重心落在原点处,我同时绘制了正方形的内接圆,内接圆的内接正三角形即为我们想要的结果。

-4--3--2--1-123-2--1-1

一种最为简单朴素的想法是,需要判断每一个像素是否落在三角形内。 我最初也是这么想的,所以很快开始寻找算法,最后使用了半平面法

效果如上,倒确实是画出了一个三角形。

  • 但是很显然这段代码并不好懂,我们需要从半平面逐步推导到最后的代码。
  • 同时这个代码也难以拓展,如果要画五边形,又是一长串复杂的代码。
  • 边框不符合我们预期的10%

正多边形通解

我花费了一些时间,终于发现了另一种理解方式。 由于我们只考虑正三角形,所以并不需要求点是否在三角形内,而是求该点所处的正三角形的外接圆半径。

  • 让我们想象这个一个正三角形从远点开始变大,他会扫过空间中的所有的点。
  • 所以,对于每一个点,都属于某一个半径下的三角形
  • 有了对应的半径,我们除了知道哪些点在图形内(即fragRadius < pointRadius),还能自然的得到边框(即|fragRadius - pointRadius| < borderSize / 2)

通过这一思路,我们很快就可以把问题进行转化,如下。

PSOR
  • 已知
    • P=(x,y)P=(x,y)
    • PRO=30°\angle PRO = 30 \degree (正三角形内角的一半)
  • OR|OR|

我们做辅助线PSPS,通过三角函数可以很快的得到答案

OR=OS+SR=x+ytan(30°)\begin{aligned} |OR| &= |OS| + |SR| \\ &= x + \frac y {tan(30 \degree)} \end{aligned}

这个形式可以很快的推广到正N边形。 下面是一个可以编辑的例子,你可以修改n的值来绘制四边形、五边形等等。 这一代码比上面的推导略微复杂,因为我们要把所有点都转换到第一象限。

旋转

现在我们已经可以绘制正多边形了,为了使我们的symbol符号更丰富,可以再加上旋转的功能。 这样就可以拥有上下左右四个方向的三角形了。

旋转非常简单,只需要再原坐标上进行初等三角函数变换即可。

五角星

至此,我们已经掌握了绘制点的形状的主要思路。 接下来的就可以随心所欲的玩耍了。 让我们首先来绘制一个五角星吧。

你可以使用上面的可编辑面板进行尝试,注意打开console查看shader错误信息。


Copyright © 2020-2024 Dean Xu. All Rights reserved.