概述
本篇是“练习项目”系列的第五篇,主要练习程序化生成各种多边形的例子。这一篇博客,主要都是一些数学知识,这里推荐一个软件:GeoGebra。这个软件可以很方便地画出各种函数的几何表示,对于问题的分析很有帮助。
实例
1、圆形
在UV坐标系中,根据给定的圆心和半径,判断当前片元的UV值到圆心的距离是否小于半径。
主要的代码如下:
float Circle(float2 center, float radius, float2 uv)
{
return 1 - step(radius, distance(uv, center));
}
这里对step方法不熟悉的话,可以查一下资料。
2、柔和的圆形
可以看到,上面白色区域与黑色区域的交界非常尖锐,下面会对边界做柔和操作。
主要的改变,就是不再使用step方法,而是使用smoothstep方法。这样,可以在边界处柔和混合两种颜色。
float SmoothCircle(float2 center, float radius, float smoothWidth, float2 uv)
{
return 1 - smoothstep(radius - smoothWidth, radius, distance(uv, center));
}
对smoothstep方法不熟悉的,可以查一下其它资料。
3、多边形
这里比较复杂,需要比较多的运算变换,下面一步步来介绍。注意,这里以三角形为例,其它多边形原理相同。
原始的UV坐标系,U和V的值域为
,如下图所示:
将值域从
变换到
。
input.uv = input.uv * 2 - 1; //[-1, 1],(0,0)在正中心
此时,UV坐标系如下图所示:
将直角坐标系转化为极坐标系。
float a = atan2(input.uv.y, input.uv.x) + PI; //[0, 2π],将整个界面变成角度分布(极坐标系)
这里要注意 ,atan2函数返回的是原点至点(x,y)的方位角,即与 x 轴的夹角。返回值的单位为弧度,取值范围为
。这里,加上PI是为了把值域转化到
。
对于UV坐标
来说,相当于逆时针旋转
弧度,向量
旋转到了向量
。如下图所示:
根据多边形的变数,把整个圆周均分,得出每条边对于的弧度。
float r = (2 * PI) / float(_Num); //一条边对应的角度(中心连接边的两个端点)
对于三角形,如下所示:
下面,需要计算向量
在最近的一条分界边的投影。
先计算经过了几条边:
。
向上取整:
。
计算经过的几条边的所有弧度:
。
计算向量
到最近的一条分界边的弧度:
。
计算夹角的余弦值:
。
得到向量
在分界边上的投影:
。
float d = cos(floor(0.5 + a / r) * r - a) * length(input.uv);
得到投影距离后,与配置的size比较,判断是否在多边形范围内。
half3 col = 1 - step(_Size, d);
此时,得到的多边形如下:
这样看起来有点不太舒服,翻转XY轴,可以得到如下效果:
float a = atan2(input.u