当前位置: 首页 > news >正文

ShaderToy学习笔记 03.多个形状和旋转

1. 正方形和旋转

1.1. 正方形

要绘制一个正方形,我们需要定义一个点到正方形边界的距离函数。对于中心在原点的正方形,其数学表达式为:
对于一个点 p(x,y) 到正方形边界的距离函数可以表示为:

d = max(|x|, |y|) - r

其中:

  • |x| 和 |y| 分别表示点到原点的x轴和y轴距离的绝对值
  • r 为正方形的半边长
  • d 为点到正方形边界的有向距离:
    • d < 0 表示点在正方形内部
    • d = 0 表示点在正方形边界上
    • d > 0 表示点在正方形外部

我们可以使用 desmos 来验证一下。

运行结果如下图所示:

#define PIXW (1./iResolution.y)vec3 sdfSquare(vec2 uv, float r,vec2 offset)
{uv=uv-offset;float d=max(abs(uv.x),abs(uv.y))-r;return d>0.?vec3(0.):vec3(abs(sin(iTime*0.3)),abs(cos(iTime*0.3)),abs(sin(iTime*0.3)));
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 c=sdfSquare(uv,0.3,vec2(0,0));// Output to screenfragColor = vec4(vec3(c),1.0);
}

1.2. 旋转

1.2.1. 2.1 旋转矩阵

1.2.2. 二维空间的旋转矩阵

从向量角度看:

点A可以理解为向量A1+A2,其中 A1 为(x,0),A2 为(0,y)。
将坐标轴旋转θ角度后,点A’的坐标为(x’,y’)。


将坐标轴以逆时针旋转θ角度后,点A’的坐标为(x’,y’)。
点A’可以理解为向量A1’+A2’,其中

A1' = (x*cos(θ),x*sin(θ))
A2' = (-y*sin(θ),y*cos(θ))

**注意:从图中也可以看出A2’的x坐标为 -y*sin(θ) **

A’=A1’+A2’ ,所以

x' = x * cos(θ) - y * sin(θ)
y' = x * sin(θ) + y * cos(θ)

在二维空间中,旋转矩阵可以表示为:

R ( θ ) = ( cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ) R(\theta) = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix} R(θ)=(cosθsinθsinθcosθ)

对于任意点 A(x, y),旋转后的坐标 A’(x’, y’) 可以通过矩阵乘法得到:

( x ′ y ′ ) = ( cos ⁡ θ − sin ⁡ θ sin ⁡ θ cos ⁡ θ ) ( x y ) \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} \cos\theta & -\sin\theta \\ \sin\theta & \cos\theta \end{pmatrix} \begin{pmatrix} x \\ y \end{pmatrix} (xy)=(cosθsinθsinθcosθ)(xy)

展开后得到旋转公式:

x' = x * cos(θ) - y * sin(θ)
y' = x * sin(θ) + y * cos(θ)

在 desmos 来验证一下

思路:

  • 定义一个旋转矩阵 R,它是一个 2x2 的矩阵,其中包含了旋转角度的余弦和正弦值。

运行结果如下图所示:


#define PIXW (1./iResolution.y)#define PI 3.1415926535897932384626433832795
vec2 rotate(vec2 uv ,float theta)
{mat2 m=mat2(cos(theta),sin(theta),-sin(theta),cos(theta));return m*uv;
}
vec3 sdfSquare(vec2 uv, float r,vec2 offset)
{uv=uv-offset;uv=rotate(uv,PI/4.);float d=max(abs(uv.x),abs(uv.y))-r;return d>0.?vec3(0.):vec3(abs(sin(iTime*0.3)),abs(cos(iTime*0.3)),abs(sin(iTime*0.3)));
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 c=sdfSquare(uv,0.3,vec2(0,0));// Output to screenfragColor = vec4(vec3(c),1.0);
}

1.2.3. 三维空间的旋转矩阵

详见 https://blog.csdn.net/weixin_44539328/article/details/147030682?spm=1011.2415.3001.5331 # 1. 多个2D形状和混合

1.1. mix函数

mix函数可以将两个颜色混合在一起,它的语法如下:

函数说明数学公式示例
mix(x,y,a)在x和y之间按a进行线性插值。a的范围在[0,1]之间,当a=0时返回x,当a=1时返回yf(x,y,a) = x * (1-a) + y * amix(0.0, 1.0, 0.5) = 0.5

1.1.1. 用mix函数混合颜色

#define PIXW (1./iResolution.y)
vec3 getBackgroundColor(vec2 uv)
{return mix(vec3(1,0,1),vec3(0,1,0),uv.y);
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 c=getBackgroundColor(uv);// Output to screenfragColor = vec4(vec3(c),1.0);
}

1.2. SDF 介绍

SDF在shader中指的是"Signed Distance Function"(有符号距离函数)。这是一个非常重要的概念,让我详细解释一下:

  1. 基本概念:

    • SDF 是一个返回点到形状表面距离的函数
    • 返回值的符号表示点是在形状内部(负值)还是外部(正值)
    • 表面上的点返回值为0
  2. SDF 的特点:

    • 可以精确描述几何形状
    • 计算效率高
    • 便于实现形状的混合和变形
    • 可以轻松实现平滑过渡和边缘效果

1.3. 用SDF实现多个2D形状

1.3.1. 用SDF实现一个圆

核心代码

    vec3 c=getBackgroundColor(uv);float circle_d=sdfCircle(uv,r,vec2(0,0));c=mix(vec3(1,0,0),c,step(0.,circle_d));

完整代码

#define PIXW (1./iResolution.y)
float sdfCircle(vec2 p, float r,vec2 offset)
{return length(p-offset)-r;
}vec3 getBackgroundColor(vec2 uv)
{
//uv.y [-1,1]
//y: [0,1] float y=(uv.y+1.)/2.; return mix(vec3(1,0,1),vec3(0,1,1),y);
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 c=getBackgroundColor(uv);float circle_d=sdfCircle(uv,r,vec2(0,0));c=mix(vec3(1,0,0),c,step(0.,circle_d));// Output to screenfragColor = vec4(vec3(c),1.0);
}

1.3.2. 用SDF实现一个矩形 和 圆形

核心代码

    vec3 c=getBackgroundColor(uv);float circle_d=sdfCircle(uv,r,vec2(0,0));float rect_d=sdfRect(uv,vec2(0.3,0.3),vec2(0,0));c=mix(vec3(1,0,0),c,step(0.,circle_d));c=mix(vec3(0,1,0),c,step(0.,rect_d));

采用mix函数,实现形状的混合,但当两个形状相交时,最后画的图形会覆盖前面的图形。上图中圆形和矩形相交部份显示的是矩形的颜色。
完整代码


#define PIXW (1./iResolution.y)
float sdfCircle(vec2 p, float r,vec2 offset)
{return length(p-offset)-r;
}
float sdfSquare(vec2 p, float r,vec2 offset)
{return max(abs(p.x-offset.x)-r,abs(p.y-offset.y)-r);
}
vec3 getBackgroundColor(vec2 uv)
{
//uv.y [-1,1]
//y: [0,1] float y=(uv.y+1.)/2.; return mix(vec3(1,0,1),vec3(0,1,1),y);
}void mainImage( out vec4 fragColor, in vec2 fragCoord )
{// Normalized pixel coordinates (from -1 to 1)vec2 uv = (2.0*fragCoord-iResolution.xy)/iResolution.xx;float r=0.3;vec3 c=getBackgroundColor(uv);float circle_d=sdfCircle(uv,r,vec2(-0.5,0));float square_d=sdfSquare(uv,r,vec2(-0.1,0));c=mix(vec3(1,0,0),c,step(0.,circle_d));c=mix(vec3(0,1,0),c,step(0.,square_d));// Output to screenfragColor = vec4(vec3(c),1.0);
}

相关文章:

  • ‌C/C++对时间的处理
  • Scratch——第19课 正话反说问题
  • 线程池(四):并发编程常见问题解析
  • QT6 源(52)篇二:存储 c 语言字符串的类 QByteArray 的使用举例,
  • 中美艺术教育深度融合,Glowstar与ACSDA在尔湾签署战略合作协议推动艺术发展
  • ShaderToy学习笔记 02.圆
  • JAVA多线程(8.0)
  • Pygame核心概念解析:Surface、Clock与事件循环
  • C++学习-入门到精通-【2】类、对象和字符串的介绍
  • 2025.04.26-饿了么春招笔试题-第二题
  • leetcode 26和80
  • DIY 3D打印机 原理及步骤概况
  • MySQL基本命令--系统+用户+表
  • 搭建动态SQL取数
  • 【Token系列】02 | Embedding是怎么“长出来”的?从查表到训练过程全解
  • JavaScript基础知识合集笔记1——数据类型
  • Qt开发:QSettings的介绍和使用
  • 如何下载VSCode插件市场为VSIX文件
  • 2025第十六届蓝桥杯省赛第二场(京津冀)JAVA B组真题回顾
  • 数据库监控功能-oracle
  • 张译、惠英红分获第二十届中国电影华表奖优秀男、女演员奖
  • 地下管道密布成难题,道路修整如何破局?
  • 利用AI捏造“天价骨灰盒”谣言,内蒙古包头一网民被行政处罚
  • A股三大股指涨跌互现,电力股走强,地产股冲高回落
  • 科克托是说真话的骗子,而毕加索是一言不发、让大家去猜的人
  • 天问三号计划2028年前后发射实施,开放20千克质量资源