前面几个案例都是在 3D 空间中对顶点位置进行的变换,但本次将给出一个在 2D 空间中基于顶点位置变换进行二维扭曲的案例。
一、基本原理
介绍本节案例的具体开发之前,首先需要了解二维扭曲的基本情况,如图所示。
从图中可以看出,左侧的原始三角形经过扭曲处理后产生了右侧奇异的形状,犹如一个风车。同时从图中可以看出,要想对原始三角形实现扭曲处理,必须将大三角形切分为很多小三角形。下面简单介绍扭曲的计算思路,具体步骤如下。
- (1) 设扭动的中心点为点 O,其坐标为(X0,Y0);绕中心点被扭动的点为 D,其坐标为(X1,Y1)。
- (2)设 D 点在 X 方向上的偏移为 XSpan, Y 方向上的偏移为 YSpan,则有以下结论。
-
(3)接着就可以求出 OD 与 X 轴正方向的夹角θ,具体情况如下。
-
如果 XSpan=0,并且 YSpan 大于 0,那么θ = π /2。
-
如果 XSpan=0,并且 YSpan 小于 0,那么θ =3 π /2。
-
如果 XSpan 不等于 0,那么θ =atan(YSpan/ XSpan)。
-
(4)然后计算旋转后的 D 点与 X 轴正方向的夹角θ '。
其中 ratio 表示与当前总体旋转角度线性相关的一个系数,用于将距离转化为当前考察点的旋转角度(本案例中为-3.0~5.0,需自行根据项目设置)。
- (5)计算出旋转后的夹角后,就可以求出旋转后点的 X、 Y 坐标了。
二、开发步骤
项目基础为之前的布料模拟项目,故着色器中的代码可能有些冗余,但主要部分已经标出:
顶点着色器如下:
#version 450
layout (location = 0) in vec3 inPos;
layout (location = 1) in vec2 inUV;
layout (location = 2) in vec3 inNormal;
layout (location = 0) out vec2 outUV;
layout (location = 1) out vec3 outNormal;
layout (location = 2) out vec3 outViewVec;
layout (location = 3) out vec3 outLightVec;
layout (binding = 0) uniform UBO
{
mat4 projection;
mat4 modelview;
vec4 lightPos;
float ratio;//扭曲系数
float centerX;//顶圆心x位置
float centerY;//顶圆心y位置
} ubo;
out gl_PerVertex
{
vec4 gl_Position;
};
void main ()
{
float ratio = ubo.ratio;
float pi = 3.1415926; //圆周率
float centerX = ubo.centerX;//中心点的X坐标
float centerY = ubo.centerY;//中心点的Y坐标
float currX = inPos.x;//当前点的x坐标
float currY = inPos.y;//当前点的y坐标
float spanX = currX - centerX;//当前x偏移量
float spanY = currY - centerY;//当前y偏移量
float currRadius = sqrt(spanX * spanX + spanY * spanY);//计算距离
float currRadians;//当前点与x轴正方向的夹角
if(spanX != 0.0)
{//一般情况
currRadians = atan(spanY , spanX);
}
else
{
currRadians = spanY > 0.0 ? pi/2.0 : 3.0*pi/2.0;
}
float resultRadians = currRadians + ratio*currRadius;//计算出扭曲后的角度
float resultX = centerX + currRadius * cos(resultRadians);//计算结果点的x坐标
float resultY = centerY + currRadius * sin(resultRadians);//计算结果点的y坐标
//构造结果点,并根据总变换矩阵计算此次绘制此顶点的位置
vec4 eyePos = ubo.modelview * vec4(resultX, resultY, inPos.z, 1.0);
outUV = inUV;
outNormal = inNormal.xyz;
gl_Position = ubo.projection * eyePos;
vec4 pos = vec4(inPos, 1.0);
vec3 lPos = ubo.lightPos.xyz;
outLightVec = lPos - pos.xyz;
outViewVec = -pos.xyz;
}
我们也可以动态把圆心移动到布料一角,旋转可见如下效果: