• 三角函数的天下


    最近学习Shader,在网上膜拜了几位大神后,搞了一个简单例程——三角函数的天下,效果如下,希望大家喜欢。

    首先,当然是准备好我们的Shader与Material,不知道如何准备的可以在CSDN查看浅墨或者在新浪博客查看风宇冲的博客。Shader的代码如下

    Shader "followDreamLgx/Trigonometric function" 
    {
        Properties 
        {   
            _MainTex ("Base (RGB)", 2D) = "white" {}  
            _A ("振幅(最大和最小的幅度)", Range(0, 2)) = 1  
            _W ("角速度(圈数)", Range(0, 20)) = 15   
            _K ("偏距(整体大小)", Range(0, 3)) = 1  
        }   
           
        SubShader {      
            Tags {"Queue" = "Transparent"}        
            ZWrite Off  
      
            Pass 
            {       
                CGPROGRAM       
                #pragma vertex vert  
                #pragma fragment frag       
                #include "UnityCG.cginc"  
                #pragma target 3.0     
             
                sampler2D _MainTex;   
                float _A;  
                float _W;  
                float _K;  
               
                struct v2f
                {       
                    float4 pos:SV_POSITION;       
                    float4 srcPos : TEXCOORD0;    
                };     
         
                v2f vert(appdata_base v) 
                {     
                    v2f o;     
                    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);     
                    // 根据当前顶点计算在屏幕上的位置  
                    o.srcPos = ComputeScreenPos(o.pos);    
                    return o;     
                }     
         
                fixed4 frag(v2f i) : COLOR0 
                {   
                    // 当前顶点在屏幕上的位置  
                    float2 center = (i.srcPos.xy/i.srcPos.w);    //纹理在视觉坐标系中的坐标
                    float3 col = (0,0,0);                                  //最终输出牙呢RGB值
                      int index = 150;                                        //将圆进行等分的份数(我们实际上是在画圆,只不过这是一个变形的圆)
                      
                    for(int j = 0; j < index; j ++)  
                    {  
                        // 求每个点的角度【将圆形变成30边形,计算每个顶点的角度】  
                        float pi = 3.14;
                        float an = 2 * pi * float(j) / index;  
                        // 求每个点坐标,再乘以波值 
                        float2 pointPos = float2(cos(an), sin(an))  * (_A +   _K * cos(_W * an)) ; 
                        // 在UV值域范围上半径大小为【50/_ScreenParams.xy】  
                        // 所以新的UV偏移量为【center + pointPos * 单位半径】  
                        col = max(col, tex2D(_MainTex, center + pointPos * 25 / _ScreenParams.xy).xyz);  
                    }  
                    return fixed4(col, 1);   
                }    
                ENDCG    
            }//end pass  
        }// end subshader  
        FallBack Off     
    } 

    直接看我们的重点,FragmentShader的代码

    基础知识

    1. 圆的参数方程为:x = rcosA,y = rcosB(原点在圆心)。
    2. 点A到点B的距离为10,那么点B到点A的距离也为10。
      我们平时要绘制一个圆的时候,首先拿到的点是圆心,然后根据圆心去确定圆周。但是在Shader中,我们拿到的点是圆周上的点,所以没办法根据圆心去确定圆周。但是根据上面的结论,我们通过判断点是否在圆周上也是可行的。
    3. ComputeScreenPos:能够将顶点从投影坐标系变换到视觉坐标系(一般情况下这两个坐标系是重合的)
    4. _Time:为Unity内部定义的float4变量,y分量对应着时间,x分量对应着20分之一时间
    5. ScreenParams:x是摄像机渲染物体的像素宽度,y是摄像机渲染物体的像素高度,详情可以查看Unity Manual中Built-in shader variables

    代码详解

    1. float an = 2 * pi * float(j) / index;计算每一个点的圆心角
    2. float pointPos = float2(cos(an),sin(an)) * (_A + _K * cos(_W * an))
      float(cos(an),sin(an))计算出了当前要绘制点的位置(圆的参数方程,半径为1)
      (_A + _K * cos(_W * an))为圆的半径,由于cos的存在,半径一直在改变。先抛开cos(_W * an),也就是将圆的半径缩放了(_A + _K)倍。而添加了cos(_W * an),我们知道三角函数是周期函数,抛开_W,那么an在循环结束的时候,就会对应着一个周期,取值遍布[-1,1]。假如这个时候_K = 1,_A = 1那么(_A + _K * cos(_W * an))的取值为[0,2],0对应着中心部分,2代表着最大的圆的半径。如图1.观察可以发现,有一部分凹进去了,那部分就是半径为0的部分。而假如_W取其它的值,比如3,那么整个图案就会有3个周期。如图2.假如我们将_K的取值改为3,那么就会得到图3的效果。
               
                                   图1                                                                        图2                                                                          图3  
    3. col = max(col, tex2D(_MainTex, center + pointPos * 25 / _ScreenParams.xy).xyz);
      在tex2D中,我们以当前点为圆心,取得周围点的颜色值,然后再跟默认纹理的颜色进行比较,假如tex2D寻址到的颜色值比较大,说明我们找到了圆心(除了圆心,图片上其它颜色都是黑色)。那么就获取圆心的颜色。center为视觉坐标系中纹理的UV值,pointPos*25/_ScreenParams.xy为我们最终的半径的大小。
    4. 最后将捕获到的颜色值返回,实际上就是圆心的颜色值。

    总结

    1. 最重要的是能够转换思维,理解AB的长度等于BA的长度。代码上从圆心处开始思考。
    2. 下载链接http://yunpan.cn/cdvx9LPYiKUgU  访问密码 0a8f
  • 相关阅读:
    软件工程概论课后作业2
    第三周进度表
    软件工程概论课后作业1
    第二周进度表
    9.异常处理
    《构建之法》阅读笔记二
    《构建之法》阅读笔记一
    第五周进度表
    软件工程个人作业03
    第四周进度表
  • 原文地址:https://www.cnblogs.com/suimeng/p/4727981.html
Copyright © 2020-2023  润新知