ShaderToy(四)画更好的笑脸

4 篇文章 0 订阅

根据smiley可将其分为三个部分,脸部,眼睛和嘴巴。

画脸部

1. 首先绘制其头部,用橘黄色涂满

    vec4 col = vec4(0.9, 0.65, 0.1, 1.0);    // orange
    float d = length(uv);
    col.a = S(0.5, 0.49, d);

2. 然后绘制边缘阴影部分,从0.35至0.5部分,颜色逐渐变深。这里自制remap函数,当d靠近边缘时,降低col的a值(alpha值)透明度,并呈现透明度渐变。

为了使a变化更快,对a值进行了平方,根据y=x2函数的性质。

    float edgeShadow = remap01(0.35, 0.5, d);
    edgeShadow *= edgeShadow;
    col.rgb *=1.0 - edgeShadow * 0.5;

3. 然后为边缘铺上一圈棕色,以表示脸框

    col.rgb = mix(col.rgb, vec3(0.6, 0.3, 0.1), S(0.47, 0.48, d));  //brown

4. 紧接着是额头的高光:定义一个highlight高亮区域,并且会在y轴(-0.1, 0.41)呈现逐渐虚化效果,使用mix(a,b,c)函数(返回c(1-a)+bc),即不在highlight区域(=0)时,使用的是col原来的颜色,否则是col.rgb到b的渐变,变化程度与highlight值相关.

    float highlight = S(0.41, 0.405, d); // 高亮区域
    highlight *= remap(0.41, -0.1, 0.75, 0.0, uv.y);
    col.rgb = mix(col.rgb, vec3(1.0), highlight);

5. 最后是脸颊的红晕,将d移动到指定位置,并赋上红色值,多次乘积使cheek变化更快,最终使用mix函数添加上。

    d = length(uv - vec2(0.25, -0.2));
    float cheek = S(0.2, 0.01, d)* 0.4;
    cheek *= S(0.17, 0.16, d);
    col.rgb = mix(col.rgb, vec3(1.0, 0.1, 0.1), cheek);  // red

由于左右脸红关于y轴对称,只需添加uv.x = abs(uv.x)

 画眼睛

1. 首先画出眼眶,将uv移动到(0.5, 0.5)处绘制眼眶,并在内部周围添加一点蓝色表示巩膜(眼白)

uv -= 0.5;
vec4 col = vec4(1.0);    
vec4 irisCol = vec4(0.3, 0.5, 1.0, 1.0); // blue
float d = length(uv);
col = mix(vec4(1.0), irisCol, S(0.1, 0.7, d)*0.5);
col.a = S(0.5, 0.48, d);

2. 添加黑色眼球与眼影

col.rgb *= 1. - S(0.45, 0.5, d)* 0.5* sat(-uv.y-uv.x);  // 眼影
col.rgb = mix(col.rgb, vec3(0.0), S(0.3, 0.28, d));

3. 绘制虹膜及周围的肌纤维

irisCol.rgb *= 1.0 + S(0.3, 0.05, d); // 在该区域(瞳仁)更亮;
col.rgb = mix(col.rgb, irisCol.rgb, S(0.28, 0.25, d));

4. 最后添加稍小的瞳仁和两处高光

col.rgb = mix(col.rgb, vec3(0.0), S(0.16, 0.14, d));
    
float highlight = S(0.1, 0.09, length(uv-vec2(-0.15, 0.15)));
highlight += S(0.07, 0.05, length(uv-vec2(0.08, -0.08)));
col.rgb = mix(col.rgb, vec3(1.0), highlight);

 画嘴巴

1. 先将嘴巴是固定在一个框中,并选择合适的函数调节嘴型。

uv -= 0.5;
vec4 col = vec4(0.5, 0.18, 0.05, 1.0);

uv.y *= 1.5;           // 使嘴巴变小
uv.y -= uv.x * uv.x * 2.0;  // 调嘴型
    
float d = length(uv);
col.a = S(0.5, 0.48, d);

2. 添加牙齿

float td = length(uv-vec2(0.0, 0.6));
   
vec3 toothCol = vec3(1.0) * S(0.6, 0.35, d);  // 添加嘴巴牙齿上面的阴影
col.rgb = mix(col.rgb, toothCol, S(0.4, 0.37, td));

3. 最后添加舌头

td = length(uv+vec2(0.0, 0.5));
col.rgb = mix(col.rgb, vec3(1.0, 0.5, 0.5), S(0.5, 0.2, td));

 完整代码:

#define S(a, b, c) smoothstep(a, b, c) 
#define sat(x) clamp(x, 0.0, 1.0)
float remap01(float a, float b, float t)
{
    return sat((t-a) / (b-a));
}

float remap(float a, float b, float c, float d, float t)
{
    return sat(((t-a)/(b-a)) * (d-c) + c);
}

vec2 within(vec2 uv, vec4 rect)
{
    return (uv - rect.xy)/(rect.zw - rect.xy);
}

vec4 Eyes(vec2 uv){
    
    uv -= 0.5;
    vec4 col = vec4(1.0);
    vec4 irisCol = vec4(0.3, 0.5, 1.0, 1.0); // blue
    
    float d = length(uv);
    
    col = mix(vec4(1.0), irisCol, S(0.1, 0.7, d)*0.5);
    
    col.rgb *= 1. - S(0.45, 0.5, d)* 0.5* sat(-uv.y-uv.x);  // 眼影
    col.rgb = mix(col.rgb, vec3(0.0), S(0.3, 0.28, d));
    
    irisCol.rgb *= 1.0 + S(0.3, 0.05, d); // 在该区域更亮;
    col.rgb = mix(col.rgb, irisCol.rgb, S(0.28, 0.25, d));
    
    col.rgb = mix(col.rgb, vec3(0.0), S(0.16, 0.14, d));
    
    float highlight = S(0.1, 0.09, length(uv-vec2(-0.15, 0.15)));
    highlight += S(0.07, 0.05, length(uv-vec2(0.08, -0.08)));
    col.rgb = mix(col.rgb, vec3(1.0), highlight);
    
    col.a = S(0.5, 0.48, d);
    return col;
}

vec4 Head(vec2 uv)
{
    
    vec4 col = vec4(0.9, 0.65, 0.1, 1.0);    // orange
    float d = length(uv);
    
    col.a = S(0.5, 0.49, d);
    
    
    float edgeShadow = remap01(0.35, 0.5, d);
    edgeShadow *= edgeShadow;
    
    col.rgb *=1.0 - edgeShadow * 0.5;
    
    col.rgb = mix(col.rgb, vec3(0.6, 0.3, 0.1), S(0.47, 0.48, d));  // vec3(0.6, 0.3, 0.1) brown,边缘用棕色覆盖
    
    float highlight = S(0.41, 0.405, d); // 高亮区域
    highlight *= remap(0.41, -0.1, 0.75, 0.0, uv.y);
    col.rgb = mix(col.rgb, vec3(1.0), highlight);
    
    d = length(uv - vec2(0.25, -0.2));
    float cheek = S(0.2, 0.01, d)* 0.4;
    cheek *= S(0.17, 0.16, d);
    col.rgb = mix(col.rgb, vec3(1.0, 0.1, 0.1), cheek);  // red
    return col;
}

vec4 Mouth(vec2 uv)
{
    uv -= 0.5;
    vec4 col = vec4(0.5, 0.18, 0.05, 1.0);
    
    uv.y *= 1.5;           // 使嘴巴变小
    uv.y -= uv.x * uv.x * 2.0;  // 调嘴型
    
    float d = length(uv);
    col.a = S(0.5, 0.48, d);
    
    float td = length(uv-vec2(0.0, 0.6));
    
    vec3 toothCol = vec3(1.0) * S(0.6, 0.35, d);  // 添加嘴巴牙齿上面的阴影
    col.rgb = mix(col.rgb, toothCol, S(0.4, 0.37, td));
    
    td = length(uv+vec2(0.0, 0.5));
    col.rgb = mix(col.rgb, vec3(1.0, 0.5, 0.5), S(0.5, 0.2, td));  // 舌头
    return col;
}

vec4 Smiley(vec2 uv)
{
    vec4 col = vec4(0.0);
    
    uv.x = abs(uv.x);
    vec4 head = Head(uv);
    vec4 eyes = Eyes(within(uv, vec4(0.03, -0.1, 0.37, 0.25))); 
    vec4 mouth = Mouth(within(uv, vec4(-0.3, -0.4, 0.3, -0.1)));
    
    col = mix(col, head, head.a); 
    col = mix(col, eyes, eyes.a);
    col = mix(col, mouth, mouth.a);
    
    return col;
}

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;

    uv -= 0.5;
    uv.x *= iResolution.x / iResolution.y ;

    // Output to screen
    fragColor = Smiley(uv);
}

最终效果图:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值