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

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);
}
http://www.xdnf.cn/news/2200.html

相关文章:

  • DHCP配置文件详解
  • 解决conda虚拟环境安装包却依旧安装到base环境下
  • AEB法规升级后的市场预测与分析:技术迭代、政策驱动与产业变革
  • 链接文件及功能安全:英飞凌官方文档摘录 - 基于Tasking与AURIX TC3xx MCAL中Link文件解析以及代码变量定位方法详解
  • C++学习:六个月从基础到就业——STL:分配器与设计原理
  • 一种滑窗像素自差值的深度学习损失函数
  • MySQL主从数据库配置教程
  • 谈谈关于【枚举】类型变量的好处
  • ARM架构的微控制器总线矩阵优先级与配置
  • SpringMVC
  • OpenFeign 日志配置
  • 在应用运维过程中,业务数据修改的证据留存和数据留存
  • 62.不同路径
  • Android移动应用开发:创建计算器
  • 模型 隐含前提
  • 【后端】主从单体数据库故障自动切换,容灾与高可用
  • Jest 快照测试
  • 前端面试 HTML篇
  • vue中 vue.config.js反向代理
  • 元数据驱动的 AI 开发:从数据目录到模型训练自动化
  • 蓝桥杯 8. 移动距离
  • 【QuPath】人工标注WSI
  • 产销协同是什么?产销协同流程有哪些?
  • 2025.04.26-淘天春招笔试题-第二题
  • AutoSAR从概念到实践系列之MCAL篇(二)——Mcu模块配置及代码详解(下)
  • Pygame事件处理详解:键盘、鼠标与自定义事件
  • QT对话框及其属性
  • Tauri文件系统操作:桌面应用的核心能力(入门系列四)
  • 深度解析责任链Filter模式:构建灵活可扩展的请求处理管道
  • Spring Boot 支持政策