zoukankan      html  css  js  c++  java
  • shader画圆利用smoothstep函数抗锯齿

    当前环境opengl es 2.0,  不用ebo情况下, 直接6个顶点组成两个三角形,拼接成一个正方形,

    fragment shader代码里判断所有片元距离中心点之间的距离,大于半径的片元输出透明度为0,gl_FragColor = vec4(0,0,0,0.0),

    小于等于半径内的颜色为白色,gl_FragColor = vec4(1.0,1.0,1.0,0.0),到此为止绘制出的白色圆圈锯齿非常明显

     图中叠了3层圆圈。

    如果给圆圈的边界外扩比如5个像素,在这5个像素内,白色透明度从0% 到 100%,这是在运行会发现边界锯齿感好了很多,几乎没有的感觉

     ,核心思想就是给圆圈的边缘预留一段区间,在此区间进行边缘和边缘外界颜色、透明度的渐变,可以自己写自己写划算公式,但更方便是使用smoothstep方法进行区间比列换算,

        smoothstep(x,y,a) = [0, 1] ,总是返回[0, 1]区间之类的数, 纯数学领域范围的应用,其实就是初中数学区间比例换算么 区间[a, b] 与区间[m, n]之间的换算方法。

    附上最近写的 动态水波纹fragment shader代码:

    所谓的动态就是 cpu 里好比起了一个定时器,实时的计算当前正在扩大的圆的半径,把这个半径值传递给gpu ,gpu实时去给每个片元计算当前是在圈内还是圈外

    //
    //  
    //  Created by JD on 2020/6/12
    //
    //
    
    #ifdef GL_ES
    precision highp float;
    #endif
    
    uniform vec2 center;
    
    uniform float currentRadius;  //当前逐渐扩大的半径
    uniform float alphaChangeVal; //c++端是让其随时间递增,此处时被当作被减去的值而得到最终的透明度
    uniform float solidRadius;    //中间的不变实心半径
    
    
    
    
    /*
        表现需求:
        
        1,圆圈越变越大  ok
        2,圆圈默认从中心点往外透明度渐变    ok
        3,随时间的推移,圆圈变大的同时整体越变越透明 alphaChangeVal    ok
    
    */
    void main(void)
    {
    
    
        vec2 distanceVec = gl_FragCoord.xy - center.xy;
        float fragToCenterLength = sqrt(pow(distanceVec.x, 2) + pow(distanceVec.y, 2));
    
        // float min = 0;
        // float max = currentRadius;
        
        //110 255 170
        float redColor = 0.43;
        float greenColor = 1.0;
        float blueColor = 0.67;
    
        
        //平滑过度距离插值区间
        float smoothStepLength = 1.5;
    
    
    
        /* 
        期望的边界是理论最远边界currentRadius,但圆圈的边缘部分为了抗锯齿,需要平滑过度透明度,所以额外加上被用来做为平滑过度的一个距离区间1.5
        由此联想到当圆形扩散到最大半径值时,为了保证外边缘抗锯齿,
        那么圆形最大半径就要比外界设置的理论值再增长1.5,所以需要给外界的矩形大小增加1.5,
        或者不改变外界矩形,而是改变圆圈的最大理论值,让其减去1.5
    
        为方便处理我采用了后者,不麻烦外界参与这种平滑过度计算范围加减,直接在当前shader内处理;
        采用后者的话,最终采用了平滑过渡的圆圈会比采用前者的半径小1.5,不过这种视觉上的差异可以在此项目中忽略。
    
    
    
        */
        
    
    
            if(solidRadius > 0 && fragToCenterLength <= solidRadius - smoothStepLength)
            { //内圈
                gl_FragColor= vec4(redColor,greenColor,blueColor,1);
            }
            else if(solidRadius > 0 && fragToCenterLength <= solidRadius)
            {  //内圈边缘过度区间  [alpha=1 , 中间圆环当前统一动态alpha值:alphaChangeVal]
                float ratio = smoothstep(solidRadius - smoothStepLength, solidRadius, fragToCenterLength);
    
                float alpha = 1 - alphaChangeVal;
                gl_FragColor= vec4(redColor,greenColor,blueColor, ratio * (alpha - 1) +  1);
                
            }else if(fragToCenterLength <= currentRadius - smoothStepLength)
            { 
                //外环
                float alpha = 1 - alphaChangeVal;
                //外环中心点往外透明度 不使用渐变
                gl_FragColor = vec4(redColor,greenColor,blueColor,alpha);
    
            }
            else if(fragToCenterLength <= currentRadius)
            { //外圈过度区间 [alphaChangeVal, 0]
                float ratio = smoothstep(currentRadius - smoothStepLength, currentRadius, fragToCenterLength);
                float alpha = 1 - alphaChangeVal;
                gl_FragColor = vec4(redColor,greenColor,blueColor,(ratio - 1) * ( 0 - alpha));
            }
            else
            {//外圈以外
                gl_FragColor = vec4(0,0,0,0.0);
            }
    
    
    
    
    }
  • 相关阅读:
    取2个日期间的天数
    C#代码与JAVASCRIPT函数的相互调用
    ASP.NET验证码(3种)
    VS2008自带SQL 2005如何使用
    文本框默认有一个值,然后鼠标点上去那个值就清空
    远程桌面连接会话超时或者被限制改组策略也没用的时候就这么解决
    关于CComboBox的使用,编辑项的文字
    vc 剪切板 unicode
    Linux 防火墙、SELinux 的开启和关闭
    MSSQLSERVER服务不能启动
  • 原文地址:https://www.cnblogs.com/JD85/p/13491571.html
Copyright © 2011-2022 走看看