Shadertoy基础教学02、画笑脸

1、Shadertoy原教学视频链接
2、Shadertoy网址链接


文章目录


1 讲解

首先封装一下上节降到的画圆方法

  • 有一点不同之处,在于smoothstep()函数传入的参数为r, r - blur,注意第一个数大于第二个数,这样产生的效果是
    • if (d < r - blur) return 1;
    • else if (d > r) return 0;
    • d位于两者之间,返回0~1之间平滑过渡的数
// 形参(纹理坐标,圆心,半径,边界模糊长度)
float Circle(vec2 uv, vec2 p, float r, float blur)
{
    float d = length(uv - p);
    float c = smoothstep(r, r - blur, d); 
    return c;
}

画一个黄色头

  • mask(遮罩),很形象的名字。Circle函数使得屏幕上以(0,0)为圆心向外0.4个坐标单位的像素(此处忽略模糊部分)的mask变量都为1.0,而外面所有像素mask都为0,即mask在圆内为1,圆外为0
  • 之后用每个像素的col,乘以自身的mask变量的效果就是:只有mask为1的像素才会正常显示黄色,mask为0的最终颜色值col为(0,0,0)
	// 背景底色
    vec3 col = vec3(1.0, 1.0, 0.0);  
	
    float mask = Circle(uv, vec2(0.0), 0.4, 0.05);  
   
    col *= mask;	// 在圆内的像素col * 1为黄色,圆外为col * 0为黑色
    
    fragColor = vec4(vec3(col), 1.0);

画眼睛

  • 对mask变量用加减法
  • 思路很简单,刚刚我们已经画了一个圆作为头,头范围内的像素mask都为1。我们只需要再画两个眼睛,这两个眼睛内部像素mask也都为1,然后用头-这俩眼睛,即可
    float mask = Circle(uv, vec2(0.0)  ,  0.4, 0.05); 	// 头
    mask -= Circle(uv, vec2(-0.15, 0.1), 0.07, 0.05); 	// 左眼
    mask -= Circle(uv, vec2( 0.15, 0.1), 0.07, 0.05); 	// 右眼

在这里插入图片描述


嘴巴

  • 相同的思路,第一个圆画在原点,第二个圆稍微向上偏移0.1个单位,然后用第一个圆 减去 第二个圆,然后就能看到下图所示,嘴巴部分mouth变量为1,可视化一下就是fragColor = vec4(mouth.xyz, 1.0);
    float mouth = Circle(uv, vec2(0.0), 0.3, 0.01);	
    mouth -= Circle(uv, vec2(0.0, 0.1), 0.3, 0.01);

在这里插入图片描述


用之前的结果 减去 嘴巴部分就能得到一个黄色笑脸

	mask -= mouth; 

再次提醒,笑脸是通过每个像素的mask变量乘以颜色值col实现的。mask就是让屏幕上一部分像素为1,另一部分像素为0,然后对所有像素都用col * mask作为最终颜色。那么就只有mask为1的像素能显示col的颜色, col为0的像素只能显示黑色。

遮罩这个词就是这么来的,相当于给屏幕蒙上一个遮罩,只有这个遮罩内部的的像素可以有颜色,或者其他的操作等等,当然遮罩也不只是区分0,1也可以是其他数。


2 完整代码

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 )
{
    vec2 uv = fragCoord/iResolution.xy;
    
    uv -= 0.5;
    uv.x *= iResolution.x / iResolution.y; 
    
    vec3 col = vec3(1.0, 1.0, 0.0);
    float mask = Circle(uv, vec2(0.0), 0.4, 0.05);
    
    mask -= Circle(uv, vec2(-0.15, 0.1), 0.07, 0.01); 
    mask -= Circle(uv, vec2(0.15, 0.1), 0.07, 0.01); 
    
    float mouth = Circle(uv, vec2(0.0), 0.3, 0.01);
    mouth -= Circle(uv, vec2(0.0, 0.1), 0.3, 0.01);
    
    if (mouth < 0.0) 	// 嘴巴的两个圆相减,会让头顶往上的部分像素的mouth变量值为-1, 防止bug,把它们置零
    mouth = 0.0;

    mask -= mouth; 
    col *= mask;
    
    fragColor = vec4(col, 1.0);
}

效果
在这里插入图片描述


最后封装整个笑脸作为一个函数

float Circle(vec2 uv, vec2 p, float r, float blur)
{

    float d = length(uv - p);
    float c = smoothstep(r, r - blur, d);// 界内返回0,1 ,小于边界返回1, 大于边界返回0
    
    return c;
}

float Smiley(vec2 uv, vec2 p, float size)
{
    // 对笑脸做任何移动、缩放、旋转等操作,直接操作uv坐标是最方便快捷的
    uv -= p;
    uv /= size;
    // 头
    float mask = Circle(uv, vec2(0.), .4, .01);
    
    // 眼睛
    mask -= Circle(uv, vec2(-.15, .1), .07, .01); 
    mask -= Circle(uv, vec2(.15, .1), .07, .01); 
    
    // 嘴巴
    float mouth = Circle(uv, vec2(.0), .3, .01);
    mouth -= Circle(uv, vec2(.0, .1), .3, .01);
    
    if (mouth < 0.) 
        mouth = 0.;

    mask -= mouth; 

    return mask;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord/iResolution.xy;// [0,1]
    uv -= .5;// [-0.5,0.5]
    uv.x *= iResolution.x / iResolution.y; // 让像素变成正方形(uv坐标依然是x要多于1的)
    
    vec3 col = vec3(0.);
	
	vec2 pos = vec2(sin(iTime) / 2., sin(2. * iTime) / 4.);
    float size = sin(2. *iTime) / 10. + .2;
    float mask = Smiley(uv, pos, size);
    
    col = vec3(1., 1., 0.) * mask;
    
    fragColor = vec4(col, 1.);
}

请添加图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宗浩多捞

您的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值