• Shadertoy基础教学01、画圆(smoothstep()函数讲解)


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


    在这个网站上进行像素着色器代码的编辑,有两点需要了解:

    • 像素着色器的输入如下图所示,这些属性我们可以直接使用
      在这里插入图片描述
    • 函数void mainImage(out vec4 fragColor, in vec2 fragCoord)
      • out vec4 fragColor :当前像素输出的颜色值
      • in vec2 fragCoord:当前像素的屏幕空间中的x,y坐标

    1 画圆

    1.1 基础讲解

    首先,我们把屏幕空间的坐标映射到纹理坐标空间[0,1]。可以通过除以视口分辨率来实现

        vec2 uv = fragCoord/iResolution.xy;	
    
    • 1

    为了方便,可以选择把坐标系原点(0,0)移动到屏幕正中心

    	uv -= vec2(0.5, 0.5);
    
    • 1

    我们的视口一般不会是正方形,比如800x600这种分辨率,因此x轴的像素数量是比y轴要多200个的,而我们的x,y坐标取值范围都在[0,1],这就会导致对每个像素而言,x轴上的长度要比y轴上的更小所以:在竖轴上,(0,0)到(0,3)有3个像素,而横轴上的(0,0)到(3,0)有4个像素。 在这种情况下直接画圆,得到的会是椭圆,因为最终显示器上的像素都是 正方形的 。竖轴上3个像素,横轴上4个像素,必然得到一个椭圆

    在这里插入图片描述 在这里插入图片描述
    因此,需要把纹理空间的像素们也变成正方形的,很明显我们每个像素的水平方向长度是不够的,因此要把纹理坐标的x分量扩大。只需要简单乘以视口宽高比

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

    1.2 smoothstep()内置函数的使用(可选)

    让圆的边界更平滑,原理就不讲咯,很简单,可以参考这篇文章。我没搜它的源码,但是它的伪代码长下面这样。

    它与超级常见的clamp()的唯二区别就是

    • 边界外的不直接返回边界值,而是0 、1
    • 边界内的值不直接范围t自身,而是稍微操作一下,让曲线更平滑
    float smoothstep(float t1, float t2, float t)
    {
    	// 分支中相等的情况没写,无所谓的,放哪个区间都可以
    	if (t1 < t2)
    	{
    		if (t < t1)
    			return 0;
    		else if (t > t1 && t < t2)
    			return f(t);	
    		else if (t > t2)
    			return 1;
    	}
    	if (t1 > t2)
    	{
    		if (t < t1)
    			return 1;
    		else if (t > t1 && t < t2)
    			return f(t);	
    		else if (t > t2)
    			return 0;
    	}
    	if (t1 == t2)
    	{
    		if (t < t1)
    			return 0;
    		else
    			return 1;
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    1.3 完整代码

    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
        vec2 uv = fragCoord/iResolution.xy;		
        
        uv -= 0.5;     // 左下角(-0.5,-0.5),右上角(0.5,0.5)
        uv.x *= iResolution.x / iResolution.y; // 让像素变成正方形, 区间也变了,懒得算了哈,明显的x轴的上区间上限更大了
        
        float d = length(uv);
        float r = 0.3;
        if (d > r) 
        	c = 1.0; 
        else 
        	c = 0.0;
        fragColor = vec4(vec3(c), 1.0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    结果图,有锯齿
    在这里插入图片描述


    如果采用smoothstep()平滑过度一下

    void mainImage( out vec4 fragColor, in vec2 fragCoord )
    {
        vec2 uv = fragCoord/iResolution.xy;// [0,1]
        
        uv -= 0.5;// [-0.5,0.5]
        uv.x *= iResolution.x / iResolution.y; // 让像素变成正方形
        
        float d = length(uv);
        float r = 0.3;
        float c = smoothstep(r, r + .2, d);
    
        fragColor = vec4(vec3(c), 1.);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    是不是很滑
    在这里插入图片描述

    如果更改一下参数,还可以实现更模糊的效果
    在这里插入图片描述

  • 相关阅读:
    【方向盘】启动命令和IDEA如何传递:VM参数、命令行参数、系统参数、环境变量参数、main方法参数
    【MATLAB】 02 结构化程序与自定义函数
    Django思维导图-路由
    34.Django视图
    Linux 内存管理 pt.3
    在消息队列kafka多消费者组消费同一Topic场景下的idea调试debug断点进不去的解决方案
    解决方案:用决策树算法如何生成决策树图及生成SQL规则
    Python进阶——JSON
    day04 MYSQL多表查询操作
    把Android手机变成电脑摄像头
  • 原文地址:https://blog.csdn.net/Motarookie/article/details/125409098