Shader与ShaderToy开篇

写在前面

        Unity从学习到工作至今已经有三个年头了,开发中每次遇到难点第一件事就是百度搜索,从来没有自己的想法,甚是惭愧。想着不能再这样浑浑噩噩下去了,也决定开个博客,记录一下开发中自己觉得有用的东西,希望日后某一天回顾起来不会觉得日子白过,如果还能帮助到有需要有同学那就再好不过了。

关于Shader

        说起来跟Shader也很有渊源,因为以前自学过C#,第一份工作也是网站后台的开发,学习起Unity也是一路轻车熟路没啥难度,浏览一些文章过后也意识到自己只是懂了个皮毛,但觉得面试起来应该问题不大,就在面试的前一个晚上,看了一些面试题目才意识到Shader的存在,结果第二天的面试也是刚好死在Shader相关的题目上。开博客的第一篇文章是与Shader相关,大概也是为了回归个初心吧,毕竟当年的第一次就是栽在了它身上。

        关于这个shader,又不得不说起candycat这个博主。工作后陆续遇到了shader方面的问题,基本都是无法个人解决的,带我的人就向我推荐了这个博主。当时连个CSDN账号都懒得登录,就这样一篇一篇的看着她的文章学习起了shader,期间还买了她出过的shader书籍,不过现在都还没看完,十分惭愧。学习到现在,虽然说无法吃透shader,但起码阅读起shader的代码,写一些简单的shader效果是没多大问题的。说起来candycat还是女生,年纪比我还小,无意识间敬佩又增加了一分。

        想要写个shadertoy,也是因为最近终于有时间认真看了这位博主shadertoy相关的文章。不过说实话,自认为对shader已经有一定理解了但学习起来还是很吃力, 摸索了两个星期大概也理解了个皮毛,所以想以这个shadertoy为介入点,开始自己的学习笔记之路。不知不觉又写了一堆废话,还是直接开始写正文吧。

正文

        shadertoy的一些效果跟原理就不必多说了,有兴趣可以点击这里看看。因为我是学Unity的,所以还是偏向于Shadertoy转Unity的Shaderlab之后的运用。首先要说的是candycat的那个shadertoy转shaderlab的模板。下面是这位博主的原代码。

//Design By candycat(https://blog.csdn.net/candycat1992)
Shader "Shadertoy/Template" { 
    Properties{
        iMouse ("Mouse Pos", Vector) = (100, 100, 0, 0)
        iChannel0("iChannel0", 2D) = "white" {}  
        iChannelResolution0 ("iChannelResolution0", Vector) = (100, 100, 0, 0)
    }

    CGINCLUDE    
    #include "UnityCG.cginc"   
    #pragma target 3.0      

    #define vec2 float2
    #define vec3 float3
    #define vec4 float4
    #define mat2 float2x2
    #define mat3 float3x3
    #define mat4 float4x4
    #define iGlobalTime _Time.y
    #define mod fmod
    #define mix lerp
    #define fract frac
    #define texture2D tex2D
    #define iResolution _ScreenParams
    #define gl_FragCoord ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy)

    #define PI2 6.28318530718
    #define pi 3.14159265358979
    #define halfpi (pi * 0.5)
    #define oneoverpi (1.0 / pi)

    fixed4 iMouse;
    sampler2D iChannel0;
    fixed4 iChannelResolution0;

    struct v2f {    
        float4 pos : SV_POSITION;    
        float4 scrPos : TEXCOORD0;   
    };              

    v2f vert(appdata_base v) {  
        v2f o;
        o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
        o.scrPos = ComputeScreenPos(o.pos);
        return o;
    }  

    vec4 main(vec2 fragCoord);

    fixed4 frag(v2f _iParam) : COLOR0 { 
        vec2 fragCoord = gl_FragCoord;
        return main(gl_FragCoord);
    }  

    vec4 main(vec2 fragCoord) {
        return vec4(1, 1, 1, 1);
    }

    ENDCG    

    SubShader {    
        Pass {    
            CGPROGRAM    

            #pragma vertex vert    
            #pragma fragment frag    
            #pragma fragmentoption ARB_precision_hint_fastest     

            ENDCG    
        }    
    }     
    FallBack Off    
}

        说实话代码还没看几行就懵了,为什么在子着色器外搞了一大段shaderlab的代码?为什么子着色器的通道下就加了三行pragma指令?顶点着色器跟片段着色器呢?虽然疑问一个一个涌出来,但还是硬着头皮将代码写了一遍(写代码真的十分重要!)。硬逼自己查了下资料,总算是看出了个端倪,再一次感叹自己学艺不精啊。

         其实就是看代码的时候看漏了一个关键词

CGINCLUDE

        第一次看的时候我直接就将CGINCLUDE理解成了shaderlab的CGPROGRAM,在敲代码的时候还十分自信地在前面加了个#号,简直是惨不忍赌。上面的代码中CGINCLUDE到ENDCG之间是一个自定义的代码段,而且还是在当前shaderlab里被调用的,所以没有include的信息。而子着色器SubShader的通道下的vert跟frag引用的,就刚好是上面自定义代码段里定义的两个函数。豁然开朗啊豁然开朗,既然理解了这个模板,所以也根据上面的模板,还原成了自己能够理解的版本,代码如下。

Shader "Shadertoy/Template" { 
    Properties{
        iMouse ("Mouse Pos", Vector) = (100, 100, 0, 0)
        iChannel0("iChannel0", 2D) = "white" {}  
        iChannelResolution0 ("iChannelResolution0", Vector) = (100, 100, 0, 0)
    }
    SubShader {    
        Pass {    
            CGPROGRAM    
            #pragma vertex vert    
            #pragma fragment frag 
			//使用低精度来提升片段着色器的运行速度 一般指fp16 半精度
            #pragma fragmentoption ARB_precision_hint_fastest     
			#include "UnityCG.cginc"   
			#pragma target 3.0      
			//定义各种常用宏
			#define vec2 float2
			#define vec3 float3
			#define vec4 float4
			#define mat2 float2x2
			#define mat3 float3x3
			#define mat4 float4x4
			#define iGlobalTime _Time.y
			#define mod fmod
			#define mix lerp
			#define fract frac
			#define texture2D tex2D
			//_ScreenParams为屏幕的分辨率
			#define iResolution _ScreenParams
  			

			#define PI2 6.28318530718
			#define pi 3.14159265358979
			#define halfpi (pi * 0.5)
			#define oneoverpi (1.0 / pi)

			fixed4 iMouse;
			sampler2D iChannel0;
			fixed4 iChannelResolution0;

			struct v2f {    
				float4 pos : SV_POSITION;    
				float4 scrPos : TEXCOORD0;   
			};              

			v2f vert(appdata_base v) {  
				v2f o;
				o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
				//将顶点转成屏幕坐标
				o.scrPos = ComputeScreenPos(o.pos);
				return o;
			}  
			/*代码是从上到下读取的,要想在方法前面调用还没定义好的main函数,需要先声main方法
			  或者将main方法写在调用之前,这里将main方法写在后面是为了代码的可观性 因这之后逻辑大都在main方法上编写
			*/
			vec4 main(vec2 fragCoord);

			fixed4 frag(v2f _iParam) : COLOR0 { 
			  /*
			  1.在四维中有xyzw四个分量 其中xyz三个点与w相除得到归一化的点
			  2.(_iParam.srcPos.xy/_iParam.srcPos.w)将得到在屏幕中归一化后的屏幕位置
			  3.最后与屏幕的分辨率相乘获得具体的位置
			  */
			   vec2 fragCoord = ((_iParam.scrPos.xy/_iParam.scrPos.w) * _ScreenParams.xy);
				return main(fragCoord);
			}  

			vec4 main(vec2 fragCoord) {
				return vec4(1, 1, 1, 1);
			}

            ENDCG    
        }    
    }     
    FallBack Off    
}

        个人觉得这样写的话逻辑就很明朗了,毕竟还是习惯在Unity中直接看到效果, 浏览器看shadertoy简直是奇卡无比。之后学习到的一些效果都希望在unity里能正常运行,当然也会转成shadertoy在网页上看看效果如何。

        说的废话有点多,这次就先写到这里了。感觉不能一下子写太多,就像以前学习shader一样,老是想一次性吃完整个大饼结果还没消化吸收就排放出去了。这比喻有点恶心但却实是如此。已经好久没提起劲学习了,希望这次能成为一个好的开端,记录下学习shadertoy的整个过程。

        水滴石穿,持之以恒~

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值