觉得shadertoy上的一些网友的作品写得很好,加上自己对glsl一些内置函数,内置变量不是很熟悉,于是决定开始学习一下上面一些大佬的代码。

今天的案例是这个:

附上shaderToy的地址:https://www.shadertoy.com/view/ll2GD3

用three.js的ShaderMaterial实现的着色器代码如下:

<script id="vertex-shader-1" type="x-shader/x-vertex">
void main(){
gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
}
</script> <script id="fragment-shader-9" type="x-shader/x-fragment">
uniform vec2 resolution; vec3 pal( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ){
return a + b*cos( 6.28318*(c*t+d) );
}
void main( void ) {
vec2 p = gl_FragCoord.xy / resolution.xy;
vec3 col = pal( p.x, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.0,0.33,0.67) );
if( p.y>(1.0/7.0) ) col = pal( p.x, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.0,0.10,0.20) );
if( p.y>(2.0/7.0) ) col = pal( p.x, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,1.0),vec3(0.3,0.20,0.20) );
if( p.y>(3.0/7.0) ) col = pal( p.x, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,1.0,0.5),vec3(0.8,0.90,0.30) );
if( p.y>(4.0/7.0) ) col = pal( p.x, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(1.0,0.7,0.4),vec3(0.0,0.15,0.20) );
if( p.y>(5.0/7.0) ) col = pal( p.x, vec3(0.5,0.5,0.5),vec3(0.5,0.5,0.5),vec3(2.0,1.0,0.0),vec3(0.5,0.20,0.25) );
if( p.y>(6.0/7.0) ) col = pal( p.x, vec3(0.8,0.5,0.4),vec3(0.2,0.4,0.2),vec3(2.0,1.0,1.0),vec3(0.0,0.25,0.25) );
// band
float f = fract(p.y*7.0);
// borders
col *= smoothstep( 0.49, 0.47, abs(f-0.5) );
// shadowing
col *= 0.5 + 0.5*sqrt(4.0*f*(1.0-f)); gl_FragColor = vec4(col,1.0);
}
</script>

参数说明:

resolution:传入的一个vec2,其实就是画布的大小(width,height).

代码解析:

1⃣️画布归一化

vec2 p = gl_FragCoord.xy / resolution.xy;

上述代码的作用是,使得画布上的任意一点p的横轴值范围和纵轴值范围都是[0,1],极大地方便了后续色值的计算,因为色值每个通道的值范围也是[0,1]

2⃣️y轴分块,x轴颜色渐变

不难看出,分成了7等份

针对每单独的一份呢,y轴颜色不做区分,x轴颜色渐变,并且是与x轴值相关,相关代码如下:

    vec3 pal( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ){
return a + b*cos( 6.28318*(c*t+d) );
}

该函数有4个形参,分别是t(x轴坐标值,注意x的范围此时是0到1)和自定义的4种颜色。

后面的三角函数可以看作 y = b * cos(k(c*x + d)),所以y的值范围是[-b,b],那么颜色3个通道的值肯定不能小于0啊,最好也是不能大于1的,所以在前面补上a,

并且a-b>0;a+b<1;

解该二元一次不等式得:

b<0.5,

然后我们再来看一下代码中计算颜色时给的实参:

对于每个维度来说,也确实是a > b的。

补充:对于a、b,每个维度之和小于等于1,

3⃣️加边框

        // band
float f = fract(p.y*7.0);
// borders
col *= smoothstep( 0.49, 0.47, abs(f-0.5) );

我刚开始想的时候,是想着用透明度做的,看到了作者的代码,又见到这个smoothstep函数,于是去详细了解了一下:

图示法如下:

所以,针对上述代码,first:

float f = fract(p.y*7.0);

p.y * 7.0 的值为0.1、0.2、...1.0、1.1、1.2、...2.0、2.1、2.2、...3.0、3.1、3.2、........6.0、6.1、6.2、...7.0;

fract是取小数函数,所以对于每一段的f值范围都是0.0、0.1、0.2、0.3、0.4、0.5....0.9、0.0;

smoothstep( 0.49, 0.47, abs(f-0.5) )

abs(f-0.5) 走势是这样的(绝对值):0.5、0.4、0.3、0.2、0.1、0.0、0.1、0.2、0.3、0.4、0.5;

0.49 > 0.47,就是a > b;符合上述第二种计算规则,

所以该函数式算得的值走势是:0->平滑插值(升)->1->平滑插值(降)->0

col *= smoothstep( 0.48, 0.47, abs(f-0.5) );

所以在y轴上,之前的满屏,现在有了缝隙,效果如下:

因为末端smoothstep函数值为0,算得颜色为rgb(0.,0.,0.)

4⃣️smoothstep函数处理获得其他效果

float f = fract(p.y*7.0);
abs(f-0.5)

abs最大值为0.5,所以只要smoothstep(a,b,x)中

a>b,并且

a>0.5,就不会出现缝隙;

b<0.5,才会有平滑效果.

    col *= smoothstep( 0.98, 0.07, abs(f-0.5) );

smoothstep:

效果如下:

col *= smoothstep( 0.98, 0.37, abs(f-0.5) );

smoothstep:

效果如下:

 5⃣️sqrt(x * (1-x))实现y轴弧形渐变

首先看一下y = 0.5 + sqrt(x * (1-x))的表示的图形

所以对于着色器代码:

col *= 0.5 + 0.5*sqrt(4.0*f*(1.0-f));

转化为:

col *= 0.5 + sqrt(f*(1.0-f));

因为f变化顺序为0.5->0.0->0.5;所以对照上面的图形,y轴颜色的被乘数变化为1.0->0.5->1.0,注意这些变化为非线性的,所以y轴变化如下:

再乘一次:

col *= 0.5 + sqrt(f*(1.0-f));

继续:

继续:

shaderToy学习篇的更多相关文章

  1. js学习篇1--数组

    javascript的数组可以包含各种类型的数据. 1. 数组的长度 ,直接用 length 属性; var arr=[1,2,3]; arr.length; js中,直接给数组的length赋值是会 ...

  2. Tomcat集群配置学习篇-----分布式应用

    Tomcat集群配置学习篇-----分布式应用 现目前基于javaWeb开发的应用系统已经比比皆是,尤其是电子商务网站,要想网站发展壮大,那么必然就得能够承受住庞大的网站访问量:大家知道如果服务器访问 ...

  3. (转载)OC学习篇之---概述

    前言 终于开启了OC的学习篇了,之前由于工作上的事,学习就一直搁浅了,不过最近由于各种原因,感觉必须要开启iOS的开发旅程了,不然就老了.因为之前一直是做Android的,所以学习iOS来就没那么费劲 ...

  4. 《Mysql 公司职员学习篇》 第二章 小A的惊喜

          第二章 小A的惊喜  ---- 认识数据库 吃完饭后,小Y和小A回到了家里,并打开电脑开始学习Mysql. 小Y:"小A,你平时的Excell文件很多的情况下,怎么样存放Exce ...

  5. Java多线程(学习篇)

    Java多线程:(学习篇) 1.什么是线程 2.线程状态 3.线程中断 4.线程交互 5.同步机制 6.锁机制 7.堵塞队列与堵塞栈 8.条件变量.原子量.线程池等 9.线性安全类和Callable与 ...

  6. 鸟哥Linux私房菜基础学习篇学习笔记3

    鸟哥Linux私房菜基础学习篇学习笔记3 第十二章 正则表达式与文件格式化处理: 正则表达式(Regular Expression) 是通过一些特殊字符的排列,用以查找.删除.替换一行或多行文字字符: ...

  7. 鸟哥Linux私房菜基础学习篇学习笔记2

    鸟哥Linux私房菜基础学习篇学习笔记2 第九章 文件与文件系统的压缩打包: Linux下的扩展名没有什么特殊的意义,仅为了方便记忆. 压缩文件的扩展名一般为: *.tar, *.tar.gz, *. ...

  8. 鸟哥Linux私房菜基础学习篇学习笔记1

    鸟哥Linux私房菜基础学习篇学习笔记1 第三章 主导分区(MBR),当系统在开机的时候会主动去读取这个区块的内容,必须对硬盘进行分区,这样硬盘才能被有效地使用. 所谓的分区只是针对64Bytes的分 ...

  9. Scrapy学习篇(十)之下载器中间件(Downloader Middleware)

    下载器中间件是介于Scrapy的request/response处理的钩子框架,是用于全局修改Scrapy request和response的一个轻量.底层的系统. 激活Downloader Midd ...

随机推荐

  1. Android异常与性能优化相关面试问题-冷启动优化面试问题详解

    什么是冷启动: 冷启动的定义:冷启动就是在启动应用前,系统中没有该应用的任何进程信息.实际也就是要执行Application.onCreate()方法的那次启动. 冷启动 / 热启动的区别:热启动:用 ...

  2. 【ARC072 E】Alice in linear land

    被智商题劝退,告辞 题意 有一个人在一条数轴的距离原点为 \(D\) 的位置,他可以执行 \(n\) 次操作,每次操作为给定一个整数 \(d_i\),这个人向原点的方向走 \(d_i\) 个单位,但如 ...

  3. Linux之RPM 软件管理程序

    RPM RPM是软件管理程序,提供软件的安装.升级.查询.反安装的功能.优点:a.安装方便,软件中所有数据都经过编译和打包b.查询.升级.反安装方便缺点:a.缺乏灵活性b.存在相依属性 用法: rpm ...

  4. 《Python基础教程》第六章:抽象(一)

    用def定义函数 __doc__是函数属性.属性名中的双下划线表示它是个特殊属性

  5. nginx日志、变量

    日志格式类型等 包含两类:access_log  error.log log_format log只能在http模块下配置 下图是一个典型error_log配置 warn表示默认日志级别为‘’警告‘’ ...

  6. HDU-2072-单词数(字典树)

    链接: https://vjudge.net/problem/HDU-2072 题意: lily的好朋友xiaoou333最近很空,他想了一件没有什么意义的事情,就是统计一篇文章里不同单词的总数.下面 ...

  7. hdu 6052 To my boyfriend

    题目 OvO click here http://acm.hdu.edu.cn/showproblem.php?pid=6052 (2017 Multi-University Training Con ...

  8. gulp的作用,安装,使用

    1.gulp是什么?    Gulp是基于node的一个自动化构建工具,开发者可以使用它构建自动化工作流程(前端集成开发环境).例如:网页自动刷新,CSS预处理,代码检测,图片压缩等功能,只需要简单的 ...

  9. Vue 新手学习笔记:vue-element-admin 之安装,配置及入门开发

    所属专栏: Vue 开发学习进步 说实话都是逼出来的,对于前端没干过ES6都不会的人,vue视频也就看了基础的一些但没办法,接下来做微服务架构,前端就用 vue,这块你负责....说多了都是泪,脚手架 ...

  10. JavaWeb-SpringSecurity记住我功能

    系列博文 项目已上传至guthub 传送门 JavaWeb-SpringSecurity初认识 传送门 JavaWeb-SpringSecurity在数据库中查询登陆用户 传送门 JavaWeb-Sp ...