在上一篇文章中,我们学习了如何绘制圆并为其设置动画。在本教程中,我们将学习如何绘制正方形并使用旋转矩阵旋转它们。
如何画正方形
绘制正方形与绘制圆形非常相似,只是我们将使用不同的方程式。事实上,如果你有一个方程,你几乎可以画出任何你想要的 2D 形状!
方形方程由以下定义:
max(abs(x),abs(y)) = r
x = x坐标
y = y坐标
r = 正方形半径
我们可以重新排列变量以使方程等于零:
max(abs(x), abs(y)) - r = 0
要在图表上对此进行可视化,您可以使用Desmos 计算器绘制以下图表:
max(abs(x), abs(y)) - 2 = 0
如果您复制上面的代码片段并将其粘贴到 Desmos 计算器中,那么您应该会看到一个半径为 2 的正方形图形。正方形的中心位于原点 (0, 0)。
您还可以包含偏移量:
max(abs(x - offsetX), abs(y - offsetY)) - r = 0
offsetX = 正方形的中心在 x 轴上移动多少
offsetY = 正方形的中心在 y 轴上移动多少
使用像素着色器绘制正方形的步骤与之前创建圆形的教程非常相似。相反,我们将专门为正方形创建一个函数。
vec3 sdfSquare(vec2 uv, float size, vec2 offset) {
float x = uv.x - offset.x;
float y = uv.y - offset.y;
float d = max(abs(x), abs(y)) - size;
return d > 0. ? vec3(1.) : vec3(1., 0., 0.);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy; // <0, 1>
uv -= 0.5; // <-0.5,0.5>
uv.x *= iResolution.x/iResolution.y; // 固定纵横比
vec2 offset = vec2(0.0, 0.0);
vec3 col = sdfSquare(uv, 0.2, offset);
// 输出到屏幕
fragColor = vec4(col,1.0);
}
耶!现在我们有一个红色方块
旋转形状
您可以使用以下符号给出的旋转矩阵来旋转形状:
矩阵可以帮助我们处理多个线性方程和线性变换。实际上,旋转矩阵是一种变换矩阵。我们可以使用矩阵来执行其他转换,例如剪切、平移或反射。
我们可以使用我在Desmos上创建的图表来帮助可视化旋转。我创建了一组参数方程,它们以线性方程形式使用旋转矩阵。
线性方程形式是通过将旋转矩阵乘以WolframAlpha[x,y]计算的向量来获得的。结果是旋转后转换后的 x 坐标和转换后的 y 坐标的方程。
在Shadertoy中,我们只关心旋转矩阵,不关心线性方程的形式。我只讨论线性方程形式是为了在 Desmos 中显示旋转。
我们可以在着色器代码中创建一个rotate函数,该函数接受 UV 坐标和旋转正方形的角度。它将返回乘以 UV 坐标的旋转矩阵。然后,我们将通过传入我们的 XY 坐标调用rotate函数内部的sdfSquare函数,移动一个偏移量(如果存在)。我们将使用iTime作为角度,得到正方形动画。
vec2 rotate(vec2 uv, float th) {
return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;
}
vec3 sdfSquare(vec2 uv, float size, vec2 offset) {
float x = uv.x - offset.x;
float y = uv.y - offset.y;
vec2 rotated = rotate(vec2(x,y), iTime);
float d = max(abs(rotated.x), abs(rotated.y)) - size;
return d > 0. ? vec3(1.) : vec3(1., 0., 0.);
}
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 uv = fragCoord/iResolution.xy; // <0, 1>
uv -= 0.5; // <-0.5,0.5>
uv.x *= iResolution.x/iResolution.y; // 固定纵横比
vec2 offset = vec2(0.0, 0.0);
vec3 col = sdfSquare(uv, 0.2, offset);
// 输出到屏幕
fragColor = vec4(col,1.0);
}
请注意我们如何在 Shadertoy 中定义矩阵。让我们更仔细地查看一下这个rotate函数。
vec2 rotate(vec2 uv, float th) {
return mat2(cos(th), sin(th), -sin(th), cos(th)) * uv;
}
根据GLSL 上的这个 wiki,我们用逗号分隔的值定义了一个矩阵,但我们首先通过矩阵列。由于这是一个类型为 mat2 的矩阵,因此它是一个 2x2 矩阵。前两个值代表第一列,后两个值代表第二列。在WolframAlpha等工具中,您可以先插入值,然后使用方括号分隔每一行。在试验矩阵时请记住这一点。
我们的rotate函数返回一个类型的值,vec2因为 2x2 矩阵 ( mat2) 乘以vec2向量返回另一个vec2向量。
当我们运行代码时,我们应该看到正方形顺时针旋转。
结论
在本课中,我们学习了如何绘制一个正方形并使用变换矩阵对其进行旋转。使用您从本教程和上一教程中获得的知识,您可以使用该形状的方程或SDF绘制您想要的任何 2D形状!
在下一篇文章中,我将讨论如何在画布上绘制多个形状,同时还能更改背景颜色。