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 - 函数造型能力的更多相关文章

  1. Book of Shaders 01 - 关于函数造型能力的理解

    0x00 从函数出发 Shader 中的很多效果都是由函数计算得出的,如何更好地理解二者的关系呢.不妨先看看函数是什么?函数的定义可以简单地描述为:给定一个集合 A,对于其中的元素施加法则 f,则可以 ...

  2. unity shader 常用函数列表

    此篇博客转自csdn的一位大牛. 中间排版出了一些问题 Intrinsic Functions (DirectX HLSL) The following table lists the intrins ...

  3. Shader的函数公式以及使用的场景

    Shader 是干什么的? 它的作用可以先简单理解为对屏幕上的物体,进行颜色处理. 而大家都知道,所有计算机,处理颜色的当然是显卡,也就是 GPU . 所以我们写 Shader 的目的就是告诉 GPU ...

  4. Unity3D -- shader常用函数和变量

    最近在学习Unity Shader,写Shader的时候总是忘记Unity为我们提供的函数.变量怎么写的,这里整理一下,方便自己查阅,也提供给网友,学习Shader不易. 1.函数 float3 Wo ...

  5. 渲染路径-surface shader 光照函数与渲染路径

    https://docs.unity3d.com/Manual/SL-SurfaceShaderLighting.html Lighting Model declaration Lighting mo ...

  6. CG Shader常用函数

    为了方便自己记忆,将常用的CG函数写于此 转载于 http://www.cppblog.com/lai3d/archive/2008/10/23/64889.html Name Syntax Desc ...

  7. Unity Shader常用函数,标签,指令,宏总结(持续更新)

    极端常用: UnityObjectToClipPos(v.vertex); 最基本的顶点变换,模型空间 ==>裁剪空间 mul(unity_ObjectToWorld, v.vertex); 顶 ...

  8. Unity3D -- shader光照常用函数和变量

    上一篇记录了shader常用函数和变量,这篇记录一些光照计算时常用函数和变量 1.内置的光照变量 _LightColor0 float4 //该Pass处理的逐像素光源的颜色 _WorldSpaceL ...

  9. 匹夫细说C#:从园友留言到动手实现C#虚函数机制

    前言 上一篇文章匹夫通过CIL代码简析了一下C#函数调用的话题.虽然点击进来的童鞋并不如匹夫预料的那么多,但也还是有一些挺有质量的来自园友的回复.这不,就有一个园友提出了这样一个代码,这段代码如果被编 ...

随机推荐

  1. C#LeetCode刷题之#876-链表的中间结点(Middle of the Linked List)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3836 访问. 给定一个带有头结点 head 的非空单链表,返回链 ...

  2. Vue 离开页面时的校验-mixin-beforeRouteLeave

    一定要看下函数前的注释, 需要在使用的页面定义[needCheckFlag]data属性 一定要看下函数前的注释, 需要在使用的页面定义[needCheckFlag]data属性 一定要看下函数前的注 ...

  3. MySQL查看没有主键的表

    select table_schema, table_name from information_schema.tables where table_name not in (select disti ...

  4. excel如何复制筛选内容

    https://jingyan.baidu.com/article/ca00d56c75b7e5e99eebcf3c.html

  5. vue报错vue-router.esm.js?8c4f:2007 Uncaught (in promise) NavigationDuplicated {_name: "NavigationDuplicated", name: "NavigationDuplicated"}

    今天在写vue项目配置好路由点击菜单时,突然在控制台报错. 错误信息如下: Uncaught (in promise) NavigationDuplicated {_name: "Navig ...

  6. web主题适配方案指北

    前置知识 在这里了解实现网页主题切换的相关知识. CSS 变量 要实现主题切换需要了解一点 css 自定义属性.当然,本文还提供了其他实现方式,为了不给您接下来的阅读带来阻碍,先了解它. 变量的声明 ...

  7. nohup 命令的使用

    nohup 命令的使用 1. nohup简介 nohup 命令运行由 Command参数和任何相关的 Arg参数指定的命令,忽略所有挂断(SIGHUP)信号.在注销后使用 nohup 命令运行后台中的 ...

  8. OVS 流表offload

    原文链接:https://www.dazhuanlan.com/2019/12/31/5e0af1858dada/ 最近开始调研网卡的OVS流表offload功能,所以目前查看一下OVS这块是怎么做的 ...

  9. latex:备忘代码

    1.脚注代码: \footnote{欧几里德,约公元前330--340年.} 结果为: 2.改变某个字的字体形状,表示强调 \emph{勾股定理} 结果为(勾股数这三个字与其他字不一样): 3.正文中 ...

  10. Asp.net Core启动流程讲解(四)

    Asp.net Core内 DI(DependencyInjection)贯穿了项目的始终,要学习Asp.net Core就无法越过DI. 下面讲解一下DI在Asp.Net Core内的流程 asp. ...