Shader 001 - 函数造型能力
0x00 从函数出发
Shader 中的很多效果都是由函数计算得出的,如何更好地理解二者的关系呢。不妨先看看函数是什么?函数的定义可以简单地描述为:给定一个集合 A,对于其中的元素施加法则 f,则可以得到另一个集合 B。将这样的 A 和 B 中的元素的对应关系,反映到二维直角坐标系中,就可以得到一条关于 f 的曲线。比如,正弦函数 sin 的曲线。

那么,应当如何通过函数来得到想要的 Shader 效果?
我们都知道Shader 的中文翻译为着色器,Shader 的作用就是为屏幕中的每个像素着色。一段 Shader 程序的输入是位置信息,输出则是颜色信息。是不是很像函数中的映射关系:f(位置) = 颜色。
0x01 sin 的颜色
有了上面的表达式,稍加转变,我们就可以用 shader 来描述 sin 的颜色。在 shader 中,颜色是由一个四维浮点数向量 vec4 来表示的,分别表示 (r, g, b, a),取值范围为 0.0 到 1.0。为了展示一个完整的 sin 周期,可以对 sin 函数进行一些缩放和平移的操作,使其周期 T = 1.0:
float f = sin(x * PI_2) / 2.0 + 0.5;
同时,也需要将屏幕的像素坐标规范化,使其落在 0.0 到 1.0 之间。下面 st 的计算是一个很常用的操作,其中,gl_FragCoord 是像素的坐标,u_resolution 是画布的尺寸,两者相除可以将像素坐标规范化。
vec2 st = gl_FragCoord.xy / u_resolution;
最终代码:
#ifdef GL_ES
precision mediump float;
#endif
#define PI_2 6.2831853
uniform vec2 u_resolution;
// 绘制 y 和 x 对应关系的曲线
float plot(float y, float x) {
return smoothstep(x - 0.01, x, y) - smoothstep(x, x + 0.01, y);
}
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
float f = sin(st.x * PI_2) / 2.0 + 0.5;
vec4 color = vec4(f);
float p = plot(st.y, f);
color = (1.0 - p) * color + p * vec4(0.0, 1.0, 0.0, 1.0);
gl_FragColor = color;
}
最后得到的效果如下:

仔细观察从左到右的颜色变化,以及曲线的高度变化。不难发现,函数值越大的地方,颜色就越白,即,越接近白色的 rgba (1.0, 1.0, 1.0, 1.0);而函数值越小的地方,颜色就越黑,即,越接近黑色的 rgba (0.0, 0.0, 0.0, 0.0)。
这非常好理解,颜色 gl_FragColor 的每个分量就是根据函数的值来构造的。
0x02 sin 的形状
说完颜色,不妨再观察一下 sin 的曲线变化,是不是很像一座座高低起伏的山?只需对上面的代码稍加改造,就能得到几座连绵的绿色小山。
#ifdef GL_ES
precision mediump float;
#endif
#define PI_2 6.2831853
uniform vec2 u_resolution;
uniform float u_time;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution;
// st.x += u_time / 2.0;
float f = sin(st.x * PI_2 * 2.0) / 8.0 + 0.2;
float p = 1.0 - smoothstep(f, f + 0.01, st.y);
vec4 color = p * vec4(0.0, 1.0, 0.0, 1.0);
// color = p * vec4(0.1, 0.3, 0.4, 1.0);
gl_FragColor = color;
}
几座抽象的绿色小山,虽然看上去有点粗糙:

还可以取消上面代码中的注释,利用 u_time 值赋予画面一点动效,这样几座绿色的小山又变成波动的海浪。

0x04 理解练习掌握
本文仅谈论了最基本的 sin 函数,但也不难看出,sin 是一个强有力的造型工具。再结合另外两个工具:fract 和 dot,我们还能利用 sin 来绘制一幅简单的噪声图。
#ifdef GL_ES
precision mediump float;
#endif
uniform vec2 u_resolution;
float random(vec2 st) {
return fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453123);
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
float rnd = random(st);
gl_FragColor = vec4(vec3(rnd),1.0);
}
噪声在图形学中有广泛的应用,比如,用来模拟一些不规则的动态表面:火焰、云、岩石等。

在 Shader 中需要时时刻刻与各种函数模型打交道,正是这些函数多样的造型能力以及它们之间的有机结合,实现了多种多样的 Shader 效果。
正确使用这些函数的能力,就是 Shader 的基本功。理解并不断地练习如何使用这些函数,是非常重要的。
Shader 001 - 函数造型能力的更多相关文章
- Book of Shaders 01 - 关于函数造型能力的理解
0x00 从函数出发 Shader 中的很多效果都是由函数计算得出的,如何更好地理解二者的关系呢.不妨先看看函数是什么?函数的定义可以简单地描述为:给定一个集合 A,对于其中的元素施加法则 f,则可以 ...
- unity shader 常用函数列表
此篇博客转自csdn的一位大牛. 中间排版出了一些问题 Intrinsic Functions (DirectX HLSL) The following table lists the intrins ...
- Shader的函数公式以及使用的场景
Shader 是干什么的? 它的作用可以先简单理解为对屏幕上的物体,进行颜色处理. 而大家都知道,所有计算机,处理颜色的当然是显卡,也就是 GPU . 所以我们写 Shader 的目的就是告诉 GPU ...
- Unity3D -- shader常用函数和变量
最近在学习Unity Shader,写Shader的时候总是忘记Unity为我们提供的函数.变量怎么写的,这里整理一下,方便自己查阅,也提供给网友,学习Shader不易. 1.函数 float3 Wo ...
- 渲染路径-surface shader 光照函数与渲染路径
https://docs.unity3d.com/Manual/SL-SurfaceShaderLighting.html Lighting Model declaration Lighting mo ...
- CG Shader常用函数
为了方便自己记忆,将常用的CG函数写于此 转载于 http://www.cppblog.com/lai3d/archive/2008/10/23/64889.html Name Syntax Desc ...
- Unity Shader常用函数,标签,指令,宏总结(持续更新)
极端常用: UnityObjectToClipPos(v.vertex); 最基本的顶点变换,模型空间 ==>裁剪空间 mul(unity_ObjectToWorld, v.vertex); 顶 ...
- Unity3D -- shader光照常用函数和变量
上一篇记录了shader常用函数和变量,这篇记录一些光照计算时常用函数和变量 1.内置的光照变量 _LightColor0 float4 //该Pass处理的逐像素光源的颜色 _WorldSpaceL ...
- 匹夫细说C#:从园友留言到动手实现C#虚函数机制
前言 上一篇文章匹夫通过CIL代码简析了一下C#函数调用的话题.虽然点击进来的童鞋并不如匹夫预料的那么多,但也还是有一些挺有质量的来自园友的回复.这不,就有一个园友提出了这样一个代码,这段代码如果被编 ...
随机推荐
- 从0写一个Golang日志处理包
WHY 日志概述 日志几乎是每个实际的软件项目从开发到最后实际运行过程中都必不可少的东西.它对于查看代码运行流程,记录发生的事情等方面都是很重要的. 一个好的日志系统应当能准确地记录需要记录的信息,同 ...
- drop、truncate、delete功能介绍和三者间区别
一.delete 1.delete是DML,执行delete操作时,每次从表中删除一行,并且同时将该行的的删除操作记录在redo和undo表空间中以便进行回滚(rollback)和重做操作,但要注意表 ...
- java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决
0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...
- SweetAlert 弹框之后点击OK执行方法
swal( '审核通过!', '', 'success' ).then(function () { Return(); })
- Linux下mv命令高级用法
mv 也是 Linux 下一个使用频率非常高的命令,但除了一些基本用法,你还知道它的哪些高级用法呢? 1. 基本用法 移动一个/多个文件: 移动一个/多个目录: 重命名文件/目录. 这些都是很基本的用 ...
- TfidfVectorizer、CountVectorizer 和 TfidfTransformer 的简单教程
TfidfVectorizer.CountVectorizer 和 TfidfTransformer 是 sklearn 中处理自然语言常用的工具.TfidfVectorizer 相当于 CountV ...
- dotnet cli
前言 dotnet cli (Command-Line Interface) .net 源代码和二进制文件管理工具.需要安装 .NET Core SDK. 终端执行 dotnet --info 可以打 ...
- JavaScript学习系列博客_4_JavaScript中的数据类型
JavaScript中有6种数据类型 一.基本数据类型 - String 字符串 JS中的字符串需要使用引号引起来双引号或单引号都行 但是要注意的是某种引号嵌套使用的话,需要加上 \ 转义.比如说我们 ...
- Shell脚本最佳实践
Shell脚本最佳实践 0. 编码.缩进.文件命名和权限设置等 使用utf-8编码: 统一使用tab缩进或空格缩进,不要混用: 文件名以.sh结尾,并且统一风格: 添加可执行权限: chmod +x ...
- e3mall商城的归纳总结7之solr搭建和应用
敬给读者的话 本文主要应用的技术是solr技术的搭建和应用,本文小编尽量写的更详细一些,让读者在不考虑项目的情况下也能正常完成solr的搭建,说完搭建之后,再说明运行solrj在项目中如何应用solr ...