Shadertoy_入门基础
作者:互联网
一、基本变量
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);
}
标签:Shadertoy,float,入门,uv,基础,iResolution,vec2,vec3,blur 来源: https://blog.csdn.net/qq_35312463/article/details/118378747