Shader绘制2D圆-学习Cherno教程笔记-(OpenGL/Vulkan/DirectX/Metal)-新手向

news2024/12/27 12:05:20

文章目录

  • 相关网址
  • 前言
  • 基本实现画一个圆步骤
    • 1.初步-根据长度绘画圆
    • 2.初步-根据1-length(uv)绘画圆
    • 3.正式-绘画白色形状的圆
      • (1)if逻辑代码实现
      • (2)用shader的step函数
  • 完善圆-实现绘画手环圆
    • 1.if逻辑代码实现
    • 2.用step函数代替if
  • 用smoothstep代替step函数
    • 1.smoothstep函数
    • 2.使用smoothstep
    • 3.完善shader代码
  • 用smoothstep的小Bug
    • 1.Bug说明
    • 2.解决方法
      • 方法一
      • 方法二
  • 测试smoothstep(edg0, edg1, distance)

相关网址

Cherno原视频网址:https://www.youtube.com/watch?v=xf7Y988cPRk

shader网站:https://www.shadertoy.com/

GLSL函数解释网址:https://docs.gl/

此文是记录对第一个网址学习的笔记和思考的过程。

鄙人作为shader初学者,文中应该会有错误,欢迎指正。

前言

  • 基本思路

    用Quad顶点包围一个范围作为画布(Canvas)用glsl控制画出一个圆内alpha为1,圆外的范围的alpha为0。
    在这里插入图片描述

  • 如何控制在圆内的alpha为1,圆外的alpha为0

    用当前坐标点距离原点的长度、step函数来控制

基本实现画一个圆步骤

1.初步-根据长度绘画圆

  • shader和效果图

在这里插入图片描述

  • 说明

    1. uv相当于在xy坐标系的坐标,xy坐标系的原点在中心

    2. length(uv) = sqrt(u*u+v*v) 即长度

    3. 原点的坐标是(0, 0),distance是0,所以是黑色

      假设x点(0, 0.5), distance是0.5,所以是灰色

    所以形成

    • 靠近原点的颜色是黑色
    • 远离原点的颜色是灰色

2.初步-根据1-length(uv)绘画圆

  • shader+效果图
    在这里插入图片描述

  • 说明

    distance= 1-length(uv);

    原点的坐标是(0, 0),length(uv)是0,被1减去后,是白色1

    假设边缘点x(0, 1), length(uv)是1,被1减去后,是黑色0

    所以形成翻转颜色的效果

    • 原先靠近圆心是黑色0,远离圆心逐渐递增到白色1

    • 现在靠近圆心是白色1,远离圆心逐渐递减到黑色0

3.正式-绘画白色形状的圆

(1)if逻辑代码实现

  • shader代码+效果图

在这里插入图片描述

  • 说明

    if(distance > 0.0){
    	distance = 1.0;
    }
    

    表示原先大于0.0的颜色都白色,即灰色都是白色

(2)用shader的step函数

  • shader代码+效果图

在这里插入图片描述

  • 说明

    step(edge0, x); x<edge0 返回0,x>edge0 返回1

    step函数作用同

    if(distance > 0.0){
    	distance = 1.0;  
    }
    

    step(0, x);函数图像

    在这里插入图片描述
    从线性变成阶梯型

完善圆-实现绘画手环圆

1.if逻辑代码实现

  • shader+效果

在这里插入图片描述

  • 说明

    • 原本靠近圆心的distance为1,颜色为白色1,远离圆心的distance逐渐从1降为0,颜色从白色1到黑色0。

      但经历下面代码后成上图所示

      if(distance > 0.1){
      	col = vec3(0.0);
      }
      
    • 被白色包围的黑色范围形成说明

      以圆心为出发点,length(uv)在(0, 0.9)范围内的distance为(1, 0.1),满足if条件,使颜色为黑色0。

    • 白色范围

      以圆心为出发点,length(uv)在(0.9, 1)范围内的distance为(0.1, 0),不满足if条件,使颜色依旧是白色0。

    • 白色外面的黑色范围形成说明

      以圆心为出发点,length(uv)在(1, 1.1)范围内的distance为(0, -0.1),虽然不满足if条件不受第13行if代码块的影响,但是受第12行代码step函数的影响,早已为黑色。

    所以白色范围length为(0.9, 1)

2.用step函数代替if

  • shader+效果

在这里插入图片描述

  • 说明

    • col *= vec3(1.0 - step(0.02, distance))的作用相当于

      if(distance > 0.1){
      	col = vec3(0.0);
      }
      
    • 设第13行*以的中间值c2如下

      c2 = vec3(1 - step(0.02, distance));// step(0.02, distance)使得大于0.02的为1,小于0.02的为0
      
    • c2的值

      以圆心为出发点,length(uv)在(0, 0.98)范围内的distance为(1, 0.02),step(0.02, distance)后为1,被1减去后,为黑色0

      以圆心为出发点,length(uv)在(0.98, 1)范围内的distance为(0.02, 0),step(0.02, distance)后为0,被1减去后,为白色1

    • col的值-第11行的代码,并执行第13行的*代码

      vec3 col = vec3(step(0.0, distance));
      col *= c2;
      

      以圆心为出发点,length(uv)在(0, 0.98)范围内的distance为(1, 0.02)的col是白色1,与上述同范围的c2黑色0相乘为0黑色。

      以圆心为出发点,length(uv)在(0.98, 1)范围内的distance为(0.02, 0)的col是白色1,与上述同范围的c2白色1相乘为1白色。

    所以白色的范围length是(0.98, 1),所以很小

用smoothstep代替step函数

1.smoothstep函数

  • 说明

    https://docs.gl/sl4/smoothstep

    // 当edge0 < edge1时,当x < edg0时,返回0,当x > edg1时,返回1,当x在edg0和edg1之间时,返回x。
    // 当edge1 < edge0时,当x < edg1时,返回1,当x > edg0时,返回0,当x在edg0和edg1之间时,返回x。这个有点难理解,是我在下面情况测试出来的,没有官方说明,也许不对
    // 当edge0 = edge1 ,smoothstep退化成step(0除外)
    smoothstep(edge0, edge1, x);
    

    等同于

    genType t;
    t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
    return (3.0 - 2.0 * t) * t * t;
    

    自己测试smoothstep的结论,测试过程在后面

    // 当edge1 < edge0时,当x < edg1时,返回1,当x > edg0时,返回0,当x在edg0和edg1之间时,返回x。
    // 当edge0 = edge1 ,smoothstep退化成step
    // 但当edge0=edge1=0,smoothstep(edge0,edge1,x);无论x是什么都返回0!
    smoothstep(edge0, edge1, x);
    
  • 表示的阶梯型函数图形

    在这里插入图片描述

    如图所示,在e0 e1范围更平滑,不像step那么突兀

2.使用smoothstep

  • 代替后的shader代码+效果图

    在这里插入图片描述

    // 其中fade = 0.005,即smoothstep的第二个参数
    第16行替换成smoothstep函数是给外圈边缘平滑过渡的
    第17行替换成smoothstep函数是给内圈边缘平滑过渡的
    

    在这里插入图片描述

3.完善shader代码

  • 当前代码的不足

    由于之前第17行代码有点冗余,所以可以简短一点,写完如下,效果依旧保持良好不变

    在这里插入图片描述

    vec3(smoothstep(thickness, thickness - fade, distance));
    等价于
    vec3(1.0 - smoothstep(thickness - fade, thickness, distance));
    
  • 第17行代码说明

    • 简要说明

      原先是递增,改后是递减

    • 翻转图示

      在这里插入图片描述

      在这里插入图片描述

      原先小于0.095为0,大于0.1是1=>现变成小于0.095为1,大于0.1为0

    • 结合代码和效果图具体说明

      • 原先的效果-递增
      c2 = vec3(1 - smoothstep(0.1 - 0.005, 0.1, distance));
      // distance < 0.095 为0,distance > 0.1为1
      c2 = vec3(1 - smoothstep(0.095, 0.1, distance));
      

      length(uv)在(0, 0.9)范围内的distance为(1, 0.1),smoothstep后为1,被1减去后,为黑色0

      length(uv)在(0.9, 0.905)范围内的distance为(0.1, 0.095),smoothstep后为不变,被1减去后,为平缓的白色(0.9, 0.905)之间

      length(uv)在(0.905, 1)范围内的distance为(0.095, 0),smoothstep后为0,被1减去后,为白色1

      • 改后的效果-递减

      说明当edge0 > edge1时函数的意义发生变化,这个变化上面介绍smoothstep时也说了,只不过并没有官方说明,也没问过人,不知是否正确,如有错,欢迎指正。

      c2 = vec3(smoothstep(0.1, 0.1 - 0.005, distance))
      // distance < 0.095 为1,distance > 0.1为0,
      c2 = vec3(smoothstep(0.1, 0.095, distance))
      

      length(uv)在(0, 0.9)范围内的distance为(1, 0.1),>0.1,smoothstep后为黑色0

      length(uv)在(0.9, 0.905)范围内的distance为(0.1, 0.095),smoothstep后为不变,被1减去后,为平缓的白色(0.9, 0.905)之间

      length(uv)在(0.905, 1)范围内的distance为(0.095, 0),<0.095,smoothstep后为白色1

      所以结果不变。

  • 验证:

    这段有点不好说明,可以跳过,是用OpenGL的glsl测试smoothstep函数

    • glsl关键代码

      ....
      // fragment阶段
      void main()
      {
      	float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离
      	float circle = smoothstep(0.5, Input.Fade, distance);
      	o_Color = vec4(circle, circle, circle, 1);
      }
      

      可见,Input.Fade是变量,可以调节它是否小于0.5还是大于0.5,来验证上述是否正确

    • 当Fade=0.51大于0.5时

      在这里插入图片描述

      float circle = smoothstep(0.5, 0.51, distance);

      • 圆内白色:

        distance在(1, 0.51)范围,>(大于)0.51,smoothstep后circle是白色1。

      • 圆外黑色:

        distance在(0.5, 0)范围,<(小于)0.5,smoothstep后circle是黑色0。

    • 当Fade=0.483小于0.5时

      在这里插入图片描述

      float circle = smoothstep(0.5, 0.483, distance);

      • 圆内黑色:

        distance在(1, 0.5)范围,>(大于)0.5,smoothstep后circle是黑色0。

      • 圆外白色:

        distance在(0.483, 0)范围,<(小于)0.483,smoothstep后circle是白色1。

用smoothstep的小Bug

1.Bug说明

  • 当thickness=1时,会导致中间有一个很小很小的黑色洞

    在这里插入图片描述

  • 解释——待实际验证

    由smoothstep的减法导致的

    // distance < 0.995 为1,distance > 1为0
    c2 = vec3(smoothstep(1, 0.995, distance))
    

    注意:由图像所示,不止>1,接近1的位置也是0

    在这里插入图片描述

    length(uv)在(0, 0.002)范围内的distance为(1, 0.998),在(0.995,1)之间,但是0.998靠近1,smoothstep后为接近黑色0,所以原点呈现黑色。

    tips:这是我自己猜的,有待验证和询问别人,还是那句话,欢迎指正。

2.解决方法

方法一

初始化thickness += fade,可以解决洞的问题

在这里插入图片描述

  • 解释——待实际验证

    // distance < 1 为1,distance > 1.005为0
    c2 = vec3(smoothstep(1.005, 1, distance))
    

    length(uv)在(0, 0.002)范围内的distance为(1, 0.998),不在(1.005,1)之间,而是<1,smoothstep后为白色1。

    tips:欢迎指正

方法二

推荐,代码更好看吧

  • 解决方式

    将thickness+fade代码写入smoothstep中

    在这里插入图片描述

  • 解释——同上

    // distance < 1 为1,distance > 1.005为0
    c2 = vec3(smoothstep(1.005, 1, distance))
    

    length(uv)在(0, 0.002)范围内的distance为(1, 0.998),不在(1.005,1)之间,而是<1,smoothstep后为白色1。

    tips:如有错,欢迎指正

  • 新问题

    会有新问题,即thickness=0时,fade=0.005时,有个0.005的厚度薄圆轮廓(如上两个箭头所指)

  • 解决方法

    这问题迫不得已,cherno没说解决方案。

    我自己测试,当thickness=0时,只需调整fade为0就不会有薄圆了

  • 说明为何有效

    1.先说薄圆轮廓产生原因

    设fade= 0.1, thickness = 0

    float distance = 1.0 - length(uv); 
    vec3 col = vec3(smoothstep(0, 0.1, distance)); 
    // distance < 0 为1,distance > 0.1为0
    col *= vec3(smoothstep(0.1, 0, distance));
    
    • uv为圆内黑色范围的点

      length(uv)在(0, 0.9)范围

      1.distance > 0.1
      2.col = 1
      3.col = 1 * 0 = 0;// * 0因为distance > 0.1为0
      

      所以呈现黑色

    • uv为圆上薄圆轮廓范围的点

      length(uv)在(0.9, 1)范围

      1.0 < distance < 0.1
      2.0 < col < 0.1
      3.col = (0,0.1) * (0, 0.1) = (0, 1);
      

      所以呈现薄圆

    2.将fade=0时,薄圆消失

    设fade= 0, thickness = 0

    float distance = 1.0 - length(uv); 
    vec3 col = vec3(smoothstep(0, 0, distance));
    
    col *= vec3(smoothstep(0, 0, distance));
    

    不管distance是多少,smoothstep(0, 0, distance)返回0,所以col是黑色,与背景融合在一起,所以轮廓消失。

测试smoothstep(edg0, edg1, distance)

  • edge0=edge1=0

    void main()// 部分glsl的fragment代码
    {
    	float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离
    	float circle = smoothstep(0, 0, distance);
    	o_Color = vec4(circle, circle, circle, 1);
    }
    

    结果

    在这里插入图片描述

    说明smoothstep(0, 0, distance);返回0

  • edge0=edge1=0.2

    void main()// 部分glsl的fragment代码
    {
    	float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离
    	float circle = smoothstep(0.2, 0.2, distance);
    	o_Color = vec4(circle, circle, circle, 1);
    }
    

    在这里插入图片描述

    白色范围因distance>0.2所以smoothstep(0.2, 0.2, distance)返回1

    黑色范围因distance<0.2所以smoothstep(0.2, 0.2, distance)返回0

  • edge0=edge1=0.8

    void main()// 部分glsl的fragment代码
    {
    	float distance = 1.0 - length(Input.LocalPosition);// distance = 1-圆心的距离
    	float circle = smoothstep(0.8, 0.8, distance);
    	o_Color = vec4(circle, circle, circle, 1);
    }
    

    在这里插入图片描述

    白色范围因distance>0.8所以smoothstep(0.8, 0.8, distance)返回1

    黑色范围因distance<0.8所以smoothstep(0.8, 0.8, distance)返回0

结论

smoothstep(0, 0, distance);返回0
smoothstep(0.2, 0.2, distance);退化成step(0.2, distance);distance大于0.2返回1,小于0.2返回0
smoothstep(0.8, 0.8, distance);退化成step(0.8, distance);distance大于0.8返回1,小于0.8返回0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/197079.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ESP-IDF:使用STL stack栈做检查括号是否匹配测试

ESP-IDF:使用STL stack栈做检查括号是否匹配测试 /使用栈检查括号是否匹配测试/ #include typedef struct LINKNODE20 { struct LINKNODE20 * next; }linknode20; typedef struct MYCHAR20 { linknode20 node; char * address; int index; }MyChar20; MyChar20 * createMyC…

【MFC】文档操作——范例(12)

使用MFC框架文档操作范例&#xff1a; 创建工程 创建工程&#xff0c;其中&#xff1a; 1、MFC单文档 2、自定义改应用程序数据文件扩展名&#xff1a; 3、 最后一步选择CListView&#xff08;用报表显示数据&#xff09; 重点问题&#xff1a;数据文件的读写功能 添加数据类…

电脑多个不同分辨率屏幕鼠标移动时出现偏移、错位情况的解决方法

本文介绍在使用不同尺寸、不同分辨率的两个或多个电脑屏幕时&#xff0c;鼠标在不同屏幕之间切换时&#xff0c;出现偏移、飘动、不规则运动等情况的解决方法。 对于使用两个或多个电脑屏幕的用户而言&#xff0c;鼠标在不同屏幕之间的切换有时候会出现偏移的问题。在同时使用多…

【My Electronic Notes系列——逻辑函数的化简】

目录 序言&#xff1a; &#x1f3c6;&#x1f3c6;人生在世&#xff0c;成功并非易事&#xff0c;他需要破茧而出的决心&#xff0c;他需要永不放弃的信念&#xff0c;他需要水滴石穿的坚持&#xff0c;他需要自强不息的勇气&#xff0c;他需要无畏无惧的凛然。要想成功&…

MySQL入门篇-MySQL字符集小结

备注:测试数据库版本为MySQL 8.0 这个blog我们来聊聊MySQL的字符集 前言: 字符集和排序规则 说实话我对这两个概念比较模糊&#xff0c;其实可以简单的理解: 字符集(character set)&#xff1a;定义了字符以及字符的编码。 排序规则(collation)&#xff1a;定义了字符的比…

【Django】ORM增删改查、F对象和Q对象、聚合操作和原生数据库操作

1、ORM的增删改查均需要通过管理器对象进行。 2、可使用python3 manage.py shell 进入脚本页方便操作。 3、可修改输出格式 一、ORM查询操作 1、查询方法 &#xff08;1&#xff09;all()方法 用法&#xff1a;MyModel.objects.all()作用&#xff1a;查询所有数据&#xff0c…

微信小程序——自定义组件(纯数据字段),组件的生命周期,组件所在页面的生命周期,插槽,父子组件之间的通信,事件绑定,属性绑定,behavior

一.纯数据字段1.什么是纯数据字段概念&#xff1a;纯数据字段指的是那些不用于界面渲染的data字段。应用场景&#xff1a;例如有些情况下&#xff0c;某些 data 中的字段既不会展示在界面上&#xff0c;也不会传递给其他组件&#xff0c;仅仅在当前组件内部使用。带有这种特性的…

《Keras深度学习:入门、实战与进阶》之回归问题实例:波士顿房价预测

本文摘自《Keras深度学习&#xff1a;入门、实战与进阶》。 本节将要预测20世纪70年代中期波士顿郊区房屋价格的中位数。这个数据是1978年统计收集的&#xff0c;数据集中的每一行数据都是对波士顿周边或城镇房价的描述&#xff0c;包含以下14个特征和506条数据。  CRIM&am…

verilog图像算法实现和仿真(代码与实践)

【声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】 这里的代码指的是verilog代码,而不是之前的python代码。因为verilog处理的是数据,所以之前我们也谈到过,如果需要用verilog处理图像数据,需要先用python把图像变成文本文件,等到…

菜鸟的进阶--手写一个微型Spring

前言想干嘛深入了解spring原理&#xff0c;特别是IOC容器是如何实现的&#xff1f;AOP是如何实现的&#xff1f;手写一个spring迷你版框架&#xff0c;实现容器和AOP机制。我为什么想这么做spring是整个java体系中最重要的框架&#xff0c;它整合第三方技术&#xff0c;将所有的…

交联剂134272-64-3,Maleimide-NH2 HCl,2-马来酰亚胺乙胺盐酸盐

【中文名称】N-(2-氨乙基)马来酰亚胺盐酸盐&#xff0c;2-马来酰亚胺乙胺盐酸盐【英文名称】 MAL-NH2 HCl&#xff0c;Maleimide-NH2 HCl&#xff0c;MAL NH2 HCl&#xff0c;Maleimide-amine HCl&#xff0c;MAL-amine HCl&#xff0c;N-(2-AMinoethyl)MaleiMide Hydrochlorid…

5年老测试员,面试被刷,别人说他不懂自动化测试.....

圈内认识的朋友最近跳槽了&#xff0c;之前在一家小公司干了5年测试&#xff0c;本来以为很容易跳一个高待遇的工作&#xff0c;结果却比想象的难&#xff0c;因为他不会自动化测试… 最近也看了很多人的简历&#xff0c;写的都是3年工作经验&#xff0c;但面试中&#xff0c…

对数据库几个范式的理解

数据库关系理论 这部分主要是几个概念很抽象&#xff0c;大家开始学可能学不明白。最近在准备复试&#xff0c;复习了一下相关的内容&#xff0c;顺便做一下总结。 先说几个名词&#xff1a; 候选码&#xff1a;能够唯一确定一个元组的属性集合称为候选码。注意是集合&#…

每日学术速递2.3

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.Cv、cs.LG 1.Compositional Prompt Tuning with Motion Cues for Open-vocabulary Video Relation Detection(ICLR 2023) 标题&#xff1a;通过基于错误的隐性神经表征的上下文修剪实现高…

Java基础学习笔记(十五)—— 集合(3)

集合1 HashMap 类1.1 HashMap 类概述1.2 HashMap 案例2 TreeMap 类2.1 TreeMap 类概述2.2 TreeMap 案例3 Properties集合3.1 Properties集合概述3.2 Properties基本使用3.3 Properties特有方法3.4 Properties和IO流相结合的方法4 可变参数与不可变集合4.1 可变参数4.2 不可变集…

2023.1.26

0、任务 今明两天任务&#xff0c;回答以下问题&#xff1a; 1、网络传输延迟有哪些&#xff1f;如何区分传输延迟和排队延迟&#xff1f; 2、如何理解路由器存储转发的过程&#xff1f; 3、拥塞是什么&#xff0c;为什么会发生拥塞&#xff0c;发生拥塞的表现是什么&#xff…

网络资源下载方式:http/https、ftp/sftp、BT种子、磁力下载、ed2k下载等的区别

文章目录参考资料序言中心化下载http/https下载ftp/sftp下载http与ftp下载方式的不同中心化下载的缺点中心化下载BT种子下载磁力下载ed2k下载推荐的下载器IDM下载器安装步骤IDM如何下载种子文件参考资料 一文读懂Bt种子、磁力链接、直链、p2p这些下载的区别 常说的BT下载、磁力…

【数据结构基础】图 - 基础和Overview

图(Graph)是由顶点和连接顶点的边构成的离散结构。在计算机科学中&#xff0c;图是最灵活的数据结构之一&#xff0c;很多问题都可以使用图模型进行建模求解。例如: 生态环境中不同物种的相互竞争、人与人之间的社交与关系网络、化学上用图区分结构不同但分子式相同的同分异构体…

情人节该送女友什么?分享四款适合送女生的数码好物

情人节快到了&#xff0c;对于有伴侣的人来说&#xff0c;这是一个浪漫的日子。在这个浪漫的日子&#xff0c;一些生活仪式感是必不可少的。最近看到不少人问&#xff0c;适合女生的数码好物有哪些&#xff1f;下面&#xff0c;我来给大家推荐几款适合送女生的数码好物&#xf…

动态规划DP与记忆化搜索DFS 题单刷题(c++实现+AC代码)

文章目录数字三角形滑雪挖地雷最大食物链计数采药疯狂的采药5倍经验值过河卒洛谷动态规划入门题单&#xff1a; 提单传送门 数字三角形 观察下面的数字金字塔。写一个程序来查找从最高点到底部任意处结束的路径&#xff0c;使路径经过数字的和最大。每一步可以走到左下方的点也…