Shadertoy_入门基础

官网:https://www.shadertoy.com/
在这里插入图片描述

一、基本变量

uniform vec3      iResolution;   	 // 窗口分辨率,单位像素
uniform float     iTime;        	 // 程序运行的时间,单位秒
uniform float     iTimeDelta;   	 // 渲染时间,单位秒
uniform int       iFrame;       	 // 帧率
uniform float     iChannelTime[4];       // 信道播放时间(秒)
uniform vec3      iChannelResolution[4]; // 通道分辨率(像素)
uniform vec4      iMouse;        	 // 鼠标位置
uniform samplerXX iChannel0..3;          // 输入通道  XX = 2D/Cube
uniform vec4      iDate;          // 日期(年,月,日,时)
uniform float     iSampleRate;    // 声音采样率 (i.e., 44100)
void mainImage(){}				  //main函数

示例:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // 将像素位置映射到0-1
    vec2 uv = fragCoord.xy/iResolution.xy;
    
    // 获取通道0纹理在uv出的像素颜色
    fragColor = texture(iChannel0, uv);
    
    // 让红色分量的值随时间改变。
    fragColor.r = abs(sin(iTime));
}

首先我们来具体解释下:
这是ShaderToy的主函数,参数一个入,一个出。输入的像素坐标向量,输出的是像素的颜色向量。主要作用就是根据屏幕上的像素坐标,算出像素的颜色向量,简单来说完成像素坐标到颜色的变换或者是映射。屏幕分辨率是800乘600的话,就计算800乘600区域内的所有像素。ShaderToy当前窗口的每个像素坐标都要经过这个主函数的处理以决定其颜色,所以看似这个主程序是一段代码,其实逻辑上被嵌在了一个像素坐标的大循环里面:
uv这里做了归一化处理, uv.x, uv.y的取值都在0~1;

当我们在通道0中未定义纹理的时候,我们可以你看到:
在这里插入图片描述
当我们在通道0中添加纹理素材后,我们可以看到:
在这里插入图片描述

二、圆绘制

2.1 1/4圆绘制

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    
    float d = length(uv);
    float c = d;
    
    fragColor = vec4(vec3(c), 1.0);
}

length函数是求向量的模,即是 sqrt(( u v . x ) 2 + ( u v . y ) 2) ,其实这是空间符号距离函数SDF的雏形,这个公式可以理解为向量到原点 向量 vec3(0,0,0) 的距离;还有向量里各分量的值类型一般都是float类型,所以在赋值时要加小数点。

vec3©:只给出一个值c,表示这个向量的x , y , z都是c,即是 vec3(c,c,c)

fragColor = vec4(vec3( c ), 1.0); ,这一行返回的是一个4维向量,由 r g b a四个元素组成。对基本的颜色要有一点直观感知,例如vec4(1.,1.,1.,1.)是白色;vec4(0.,0.,0.,1.)是黑色。
在这里插入图片描述
从图中可以看出:屏幕像素坐标原点 vec2(0,0) 映射出来的颜色是黑色。向右向上逐渐变淡,1/4椭圆外是白色,屏幕的颜色时白色和黑色,以及这两者之间的过渡色,这是由返回的向量rgb三个元素取值一样决定的。

2.2 基点平移

我们可以通过改变uv的取值范围,将圆点移动到屏幕中心。

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    float d = length(uv);
    float c = d;
    
    fragColor = vec4(vec3(c), 1.0);
}

在这里插入图片描述

2.3 锐化成圆

我们通过上边平移uv的原点放到了中心,现在我们可以根据uv坐标与原点的具体具体把屏幕的颜色分成黑白两色:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    float d = length(uv);
    float c = d;
    //锐化
    if(d < .3) c=1.; else c = 0.;
    
    fragColor = vec4(vec3(c), 1.0);
}

在这里插入图片描述
从图可以看到,因为图片非正方形所以我们绘制的是一个椭圆,下边我们调整x向比例,使得椭圆成圆:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
    float d = length(uv);
    float c = d;
    //锐化
    if(d < .3) c=1.; else c = 0.;
    
    fragColor = vec4(vec3(c), 1.0);
}

在这里插入图片描述

2.4 边缘模糊

从上图我们可以看圆边缘有细微锯齿,不平滑,需要引入平滑函数smoothstep: 理解float d = length(uv); ,这个可以理解为uv向量的长度,可以认为是到原点的距离,在当前的情况下,原点就是白圆的圆心,这个距离函数d就是离圆心的距离。所以,我们可以定义一个变量r,用来表示半径:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
    float d = length(uv);
    float c = d;
    //模糊
    float r = .3;
    c = smoothstep(r, r-0.02, d);
    
    fragColor = vec4(vec3(c), 1.0);
}

在这里插入图片描述

圆方法封装:

//圆绘制
float Circle(vec2 uv, vec2 p, float r, float blur) {
    float d = length(uv-p);
    float c = smoothstep(r, r-blur, d); 
    return c;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    vec2 p = vec2(0., 0.);
    float c = Circle(uv, p, .4, .05);
    
    fragColor = vec4(vec3(c), 1.0);
}

三、矩形绘制

我们可以主要用smoothstep对uv两个方向做分界处理形成矩形区域:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    
    float mask=smoothstep(-.2,.2,uv.x);
    
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

运行可以看到,我们从-0.2到0.2为过滤带,分两侧颜色;
在这里插入图片描述
接下来,我们可以将此部分封装,其中可用参数为uv变量、起点位置、终点位置、模糊大小:

float Band(float t,float start,float end,float blur)
{
    float stepL =smoothstep(start-blur,start+blur,t);
    float stepR =smoothstep(end+blur,end-blur,t);
    return stepL*stepR;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    
    float mask=Band(uv.x,-.2,.2,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

运行可见如下效果:
在这里插入图片描述
在接下来,我们对uv的v方向进行处理,将其封装为一个正方形方法:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    
    float mask=Rect(uv,-.2,.2,-.2,.2,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}


在这里插入图片描述
你也可以尝试使用不同的参数达成多边形效果:
在这里插入图片描述
在这里插入图片描述

四、波浪线绘制

4.1 基础绘制

首先,我们需要绘制一个长方形,接着上一部分的内容调整参数如下(你也可以通过对UV的比例进行调整改变):
在这里插入图片描述

在完成波浪之前,我们首先来看一下需要使用的方程式如下:
在这里插入图片描述
接着,我们在代码中体现:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=-(x-.5)*(x+.5);
    float y=uv.y+m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

运行后可见如下:
在这里插入图片描述
接下来我们可以使用更多的函数来表达:
在这里插入图片描述
在代码中体现如下:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=-(x-.5)*(x+.5);
    m=m*m*4.;
    float y=uv.y-m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}


运行可见:
在这里插入图片描述
我们也可以使用正弦函数对长方形生效:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=sin(x*8.)*.2;
    float y=uv.y-m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

在这里插入图片描述

4.2 动态绘制

接下来我们在正弦函数上使用一个时间变量达到动态效果:

float Band(float t,float start,float end,float blur)
{
    float step1 =smoothstep(start-blur,start+blur,t);
    float step2 =smoothstep(end+blur,end-blur,t);
    return step1*step2;
}

float Rect(vec2 uv,float left,float right,float bottom,float top,float blur)
{
    float band1=Band(uv.x,left,right,blur);
    float band2=Band(uv.y,bottom,top,blur);
    return band1*band2;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
	// 将像素位置映射到0-1
    vec2 uv = fragCoord/iResolution.xy;
    // 基点平移
    uv-=0.5;
    //调整x方向比例
    uv.x *= iResolution.x/iResolution.y;
 
    float t=iTime;
    
    vec3 color=vec3(0.);
    float x=uv.x;
    float m=sin(t+x*8.)*.2;
    float y=uv.y-m;

    float mask=Rect(vec2(x,y),-.5,.5,-.05,.05,.01);
    color=vec3(1.,1.,1.)*mask;
    
    fragColor = vec4(color, 1.0);
}

在这里插入图片描述

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值