渲染画(笑脸怎么画)

@TOC目录开始学习ShaderToy,往往不知所措,看不太懂;不容易懂,背后全是数学公式;请看这篇了解一下原理和基础。实践方法:请打开网站https://www.shadertoy.com,点击新建开始实验。完成一个圆的渲染首先把下列代码贴入voidmainImage(outvec4fragColor,invec2fragCoord){vec2uv=…

大家好,又见面了,我是你们的朋友全栈君。

开始学习ShaderToy, 往往不知所措,看不太懂;不容易懂,背后全是数学公式;请看这篇了解一下原理和基础。

实践方法:请打开网站
https://www.shadertoy.com,点击新建开始实验。

完成一个圆的渲染

首先把下列代码贴入

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{ 
   
    vec2 uv = fragCoord/iResolution.xy;
    
    float d = length(uv);
    float c = d;
    
    fragColor = vec4(vec3(c), 1.0);
}

解释:这是ShaderToy的主函数,参数一个入,一个出。输入的像素坐标向量,输出的是像素的颜色向量。主要作用就是根据屏幕上的像素坐标,算出像素的颜色向量,简单来说完成像素坐标到颜色的变换或者是映射。屏幕分辨率是800乘600的话,就计算800乘600区域内的所有像素。ShaderToy当前窗口的每个像素坐标都要经过这个主函数的处理以决定其颜色,所以看似这个主程序是一段代码,其实逻辑上被嵌在了一个像素坐标的大循环里面

uv这里做了归一化处理, uv.x, uv.y的取值都在0~1;

length函数是求向量的模,即是 ( u v . x ) 2 + ( u v . y ) 2 \sqrt {(uv.x)^2+(uv.y)^2} (uv.x)2+(uv.y)2
,其实这是空间符号距离函数SDF的雏形,这个公式可以理解为向量到原点 向量 v e c 3 ( 0 , 0 , 0 ) vec3(0,0,0) vec3(0,0,0)的距离;还有向量里各分量的值类型一般都是float类型,所以在赋值时要加小数点。

vec3©:只给出一个值c,表示这个向量的 x , y , z x,y,z x,y,z都是c,即是 v e c 3 ( c , c , c ) vec3(c,c,c) vec3(c,c,c),类似Python的Numpy里多维数组的广播性质。

fragColor = vec4(vec3(c), 1.0);,这一行返回的是一个4维向量,由 r g b a rgba rgba 四个元素组成.对基本的颜色要有一点直观感知,例如vec4(1.,1.,1.,1.)是白色;vec4(0.,0.,0.,1.)是黑色。
在这里插入图片描述

认识图:屏幕像素坐标原点 v e c 2 ( 0 , 0 ) vec2(0,0) vec2(0,0) 映射出来的颜色是黑色。向右向上逐渐变淡,1/4椭圆外是白色,屏幕的颜色时白色和黑色,以及这两者之间的过渡色,这是由返回的向量rgb三个元素取值一样决定的。

把原点移到屏幕中心
通过改变uv的取值范围,将黑点移动到屏幕中心

uv -=.5; // uv取值范围:-.5 <> .5

在这里插入图片描述
认识图:屏幕被黑灰色覆盖,相当于把第一张图作了一个平移。

人工干预颜色
把屏幕的颜色分成黑白两色,通过:

if(d < .3) c=1.; else c = 0.;

在这里插入图片描述
椭圆变圆
把椭圆变成圆,通过调整x方向的比例:

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

在这里插入图片描述边缘平滑
可以看打边缘有细微锯齿,不平滑,需要引入平滑函数smoothstep:
理解float d = length(uv);,这个可以理解为uv向量的长度,可以认为是到原点的距离,在当前的情况下,原点就是白圆的圆心,这个距离函数d就是离圆心的距离。所以,我们可以定义一个变量r,用来表示半径

float r = .3;
if(d < r) c=1.; else c = 0.;

引入平滑函数smoothstep, 让c的取值落在r-0.02和r之间:

//if(d < r) c=1.; else c = 0.;
c = smoothstep(r, r-0.02, d);

在这里插入图片描述

可以试着调整r以及其他值观察效果
完整代码:

void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord/iResolution.xy;
    uv -=0.5;
    
    uv.x *= iResolution.x/iResolution.y;
    
    float d = length(uv);
	float c = d;
    float r = .3;
    
    c = smoothstep(r, r-0.02, d);
    
    fragColor = vec4(vec3(c), 1.0);
}

制作笑脸

最终效果图如下:
在这里插入图片描述代码优化
首先优化一下画圆函数,写成一个功能函数,同时加入一个参数,让圆心随向量p的指定发生改变:

float Circle(vec2 uv, vec2 p, float r, float blur) {
    float d = length(uv-p);
    float c = smoothstep(r, r-blur, d);
    
    return c;
}

主程序代码:

vec2 uv = fragCoord/iResolution.xy;
uv -=0.5;
uv.x *= iResolution.x/iResolution.y;

vec2 p = vec2(.2, -.1);
float c = Circle(uv, p, .4, .05);
c = Circle(uv, vec2(-.5, .2), .1, .01);

fragColor = vec4(vec3(c), 1.0);

第二个圆覆盖了第一个。

在这里插入图片描述

c = Circle(uv, vec2(-.5, .2), .1, .01);代码改一下,改为相加,再看效果
注意:这优点类型光线追踪里CSG的做法,构建复杂几何实体的几个基本操作

c += Circle(uv, vec2(-.5, .2), .1, .01);

在这里插入图片描述试一下相减操作。

c -= Circle(uv, vec2(.1, .1), .07, .01);

在这里插入图片描述再加一个圆

float c = Circle(uv, vec2(0.), .4, .05);
c -= Circle(uv, vec2(-.13, .2), .07, .01);
c -= Circle(uv, vec2(.13, .2), .07, .01);

效果:
在这里插入图片描述
颜色变换

float mask = Circle(uv, vec2(0.), .4, .05);
mask -= Circle(uv, vec2(-.13, .2), .07, .01);
mask -= Circle(uv, vec2(.13, .2), .07, .01);

vec3 col = vec3(1., 1., 0.) * mask;
fragColor = vec4(col, 1.0);

效果如下:
在这里插入图片描述
制作月牙
同样适用两个圆相减的方式。

float mask = Circle(uv, vec2(0.), .4, .05);
mask -= Circle(uv, vec2(-.13, .2), .07, .01);
mask -= Circle(uv, vec2(.13, .2), .07, .01);

float mouth = Circle(uv, vec2(0.), .3, .02);

mouth -= Circle(uv, vec2(0.,0.1), .3, .02);

vec3 col = vec3(mouth);

fragColor = vec4(col, 1.0);

效果
在这里插入图片描述
调整代码,生成笑脸:

float mask = Circle(uv, vec2(0.), .4, .05);
mask -= Circle(uv, vec2(-.13, .2), .07, .01);
mask -= Circle(uv, vec2(.13, .2), .07, .01);

float mouth = Circle(uv, vec2(0.), .3, .02);

mouth -= Circle(uv, vec2(0.,0.1), .3, .02);

mask -= mouth;

vec3 col = vec3(1., 1., 0.) * mask;

fragColor = vec4(col, 1.0);

效果
在这里插入图片描述

优化代码,增加缩放和移动功能

通过uv来实现

float Circle(vec2 uv, vec2 p, float r, float blur) {
	float d = length(uv-p);
    float c = smoothstep(r, r-blur, d);
    
    return c;
}

float Smiley(vec2 uv, vec2 p, float size) {
    uv -= p;
    uv /= size;
    
    float mask = Circle(uv, vec2(0.), .4, .05); 
    mask -= Circle(uv, vec2(-.13, .2), .07, .01);
    mask -= Circle(uv, vec2(.13, .2), .07, .01);
    
    float mouth = Circle(uv, vec2(0., 0.), .3, .02);
    mouth -= Circle(uv, vec2(0., .1), .3, .02);
    
    mask -= mouth;

    return mask;
}

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;
    
    vec3 col = vec3(0.);
    float mask = Smiley(uv, vec2(0.02), .5);
    col = vec3(1., 1., 0.)*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);
    
    return c;
}

float Smiley(vec2 uv, vec2 p, float size) { 
   
    uv -= p;
    uv /= size;
    
    float mask = Circle(uv, vec2(0.), .4, .05);
    
    mask -= Circle(uv, vec2(-.13, .2), .07, .01);
    mask -= Circle(uv, vec2(.13, .2), .07, .01);
    
    float mouth = Circle(uv, vec2(0., 0.), .3, .02);
    mouth -= Circle(uv, vec2(0., .1), .3, .02);
    
    mask -= mouth;

    return mask;
}

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;
    
    vec3 col = vec3(0.);
    
    float t = iTime;
    vec2 p = vec2(sin(t)*.7, cos(t)*0.3);
    
    float mask = Smiley(uv, p, .3);
    
    
    col = vec3(1., 1., 0.)*mask;
    
    fragColor = vec4(col,1.0);
}

小结

1、大致了解了ShaderToy程序的工作原理
2、了解图形之间的加减操作,了解CSG是构造复杂集合图形的方法
3、初步实现动画效果

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/128141.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • pycharm虚拟环境与本地环境区别_pycharm自带python吗

    pycharm虚拟环境与本地环境区别_pycharm自带python吗    Python的版本众多,在加上适用不同版本的PythonPackage。这导致在同时进行几个项目时,对库的依赖存在很大的问题。这个时候就牵涉到对Python以及依赖库的版本管理,方便进行开发,virtualenv就是用来解决这个问题的。下面介绍使用PyCharm创建VirtualEnvironment的方法。    PyCharm可以使用virtualenv中的功能来创建虚拟环境。Py…

    2022年8月27日
    4
  • sublime 激活码(注册激活)

    (sublime 激活码)JetBrains旗下有多款编译器工具(如:IntelliJ、WebStorm、PyCharm等)在各编程领域几乎都占据了垄断地位。建立在开源IntelliJ平台之上,过去15年以来,JetBrains一直在不断发展和完善这个平台。这个平台可以针对您的开发工作流进行微调并且能够提供…

    2022年3月29日
    213
  • keras多层感知器识别手写数字执行预测代码_感知机模型多层神经网络

    keras多层感知器识别手写数字执行预测代码_感知机模型多层神经网络2.Keras建立多层感知器模型2.1简单介绍多层感知器模型注:以下模型及其说明来自于《TensorFlow+Keras深度学习人工智能实践应用》林大贵著以矩阵方式仿真多层感知器模型的工作方式(如下图所示)建立输入与隐藏层的公式:h1=ReLu(x*w1+b1)变量名说明输入层x仿真输入神经元接收外界传送消息,如上图所示,共有784个神经元。隐藏层h1…

    2022年10月9日
    4
  • mysql econnreset_node使用knex连接mysql,每个小时大概率出现:read ECONNRESET?

    mysql econnreset_node使用knex连接mysql,每个小时大概率出现:read ECONNRESET?我有一个node程序每小时查询一次本地数据库马上再查询一次内网数据库,仅在查询内网数据库时出现readECONNRESET。使用npm库knex+mysql2连接数据库,knex配置如下(有使用连接池)require(‘knex’)({client:’mysql2′,connection:{host:’127.0.0.1′,user:’your_database_user’,pass…

    2022年6月17日
    42
  • linux ioctl函数详解,ioctl函数详解「建议收藏」

    linux ioctl函数详解,ioctl函数详解「建议收藏」1.介绍Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的信息,所以,我们有必要了解一下ioctl函数的具体实现.2.相关结构体与相关函数#includeintioctl(intd,intrequest,….);参数:d-文件描述符,这里是对网络套…

    2022年10月18日
    1
  • idea 插件库永久激活破解方法[通俗易懂]

    idea 插件库永久激活破解方法,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    831

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号