Unity中 一个精简的图片变灰shader的逐行学习

最近在学习shader 由于是为了2d游戏 所以不用太深
今天看了冯乐乐那本入门精要前五章就开始上手
没耐心老毛病了
半复制半改出了一个shader
来逐句分析下 加强自己的理解
由于是初学 也希望大家能指出我理解上的问题 谢谢

首先代码如下

Shader "Custom/basicGoGrey"
{
    
    
    Properties{
    
    
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {
    
    }
        _Red("Red", Float) = 0.21
        _Blue("Blue", Float) = 0.07
        _Green("Green", Float) = 0.72
    }
    SubShader
    {
    
    
        Blend SrcAlpha OneMinusSrcAlpha
        Pass{
    
    
            CGPROGRAM
                #include "UnityCG.cginc"
                #include "UnityUI.cginc"
                #pragma vertex vert
                #pragma fragment frag
                struct a2v{
    
    
                    float4 vertex   :POSITION;
                    float4 texcoord :TEXCOORD0;
                };
                struct v2f{
    
    
                    float4 pos      : SV_POSITION;
                    half2 texcoord  : TEXCOORD0;
                };

                v2f vert(a2v IN) {
    
    
                    v2f OUT;
                    OUT.pos = UnityObjectToClipPos(IN.vertex);
                    OUT.texcoord = IN.texcoord;
                    return OUT;
                }

                sampler2D _MainTex;
                float _Red;
                float _Blue;
                float _Green;

                fixed4 frag(v2f IN) : SV_Target{
    
    
                    fixed4 colorTex =  (tex2D(_MainTex, IN.texcoord));
                    colorTex.r = colorTex.g = colorTex.b = colorTex.r * _Red + colorTex.b * _Blue + colorTex.g * _Green;
                    return colorTex;
                }
            ENDCG
        }
        
    }
    FallBack "Diffuse"
}

效果
变灰效果图


我们首先全局看看
分两块Properties (属性)和 subShader(shader“本身”)
subShader中

Blend SrcAlpha OneMinusSrcAlpha

Blend SrcAlpha设置了混合效果
没有的话就会
没有设置blend

接下来

Pass{
    
    
    CGPROGRAM
        #include "UnityCG.cginc"
        #include "UnityUI.cginc"
        #pragma vertex vert
        #pragma fragment frag
        struct a2v{
    
    
            float4 vertex   :POSITION;
            float4 texcoord :TEXCOORD0;
        };
        struct v2f{
    
    
            float4 pos      : SV_POSITION;
            half2 texcoord  : TEXCOORD0;
        };

        v2f vert(a2v IN) {
    
    
            v2f OUT;
            OUT.pos = UnityObjectToClipPos(IN.vertex);
            OUT.texcoord = IN.texcoord;
            return OUT;
        }

        sampler2D _MainTex;
        float _Red;
        float _Blue;
        float _Green;

        fixed4 frag(v2f IN) : SV_Target{
    
    
            fixed4 colorTex =  (tex2D(_MainTex, IN.texcoord));
            colorTex.r = colorTex.g = colorTex.b = colorTex.r * _Red + colorTex.b * _Blue + colorTex.g * _Green;
            return colorTex;
        }
    ENDCG
}

是真正的主体部分 CGPROGRAM 和 ENDCG 是CG代码片段


1

#include "UnityCG.cginc"
#include "UnityUI.cginc"

用很C语言的方式 引用了常用的Unity内置方法和变量 但首先很多方法变量都会自动引入 另外这个例子并没有用到引用的东西


2

#pragma vertex vert
#pragma fragment frag

vertex是顶点着色器 fragment是片元着色器 我目前的理解是

“vertex着色器进行矩阵变换位置,计算光照公式生成逐顶点颜色,生成/变换纹理坐标”
“fragment色器的作用是处理由光栅化阶段生成的每个片元,最终计算出每个像素的最终颜色”

啊我的感觉就是
顶点着色器拿到图片 把图片信息转换为很多个数据块(片元) 每个数据块都带有关于“某个点”的信息 包括位置深度等
然后片元着色器得到一个数据块(叫片元)然后处理这一个个数据块来呈现在屏幕上

啊大概吧 先这样理解吧


3

struct a2v{
    
    
    float4 vertex   :POSITION;
    float4 texcoord :TEXCOORD0;
};
struct v2f{
    
    
    float4 pos      : SV_POSITION;
    half2 texcoord  : TEXCOORD0;
};

这里声明了两个方便顶点着色器和片元着色器操作的结构
我们从中看出这两个着色器所处理产出的数据

a2v :a to v 表示从应用到vertex着色器 其中包含
POSITION 表示模型的顶点坐标
TEXCOORD0 模型的第一套纹理坐标

另外说一下 这种声明格式

Type Name   :   Semantic

用Semantic语义来告诉某数据(比如模型的顶点坐标)放进这个名字(比如vertex)的变量里。

再说v2f 自然是顶点着色器到片元着色器的结构
SV_POSITION 包含顶点在裁剪空间中的位置信息
TEXCOORD0 模型的第一套纹理坐标(也叫UV坐标


4

v2f vert(a2v IN) {
    
    
    v2f OUT;
    OUT.pos = UnityObjectToClipPos(IN.vertex);
    OUT.texcoord = IN.texcoord;
    return OUT;
}

填充v2f即 片元着色器需要的片元信息

OUT.pos = UnityObjectToClipPos(IN.vertex);

这里初看有些懵逼 但其实蛮讲道理:
OUT.pos也就是SV_POSITION 包含顶点在裁剪空间中的位置信息
我们自然需要把 “模型的顶点坐标”(IN.vertex/POSITION) 转换为 “裁剪空间中模型的顶点坐标”
便是UnityObjectToClipPos(IN.vertex);(既然我们不需要特殊处理这部分)

OUT.texcoord = IN.texcoord;

模型的第一套纹理坐标不变 没什么好说的


5

sampler2D _MainTex;
float _Red;
float _Blue;
float _Green;

fixed4 frag(v2f IN) : SV_Target{
    
    
    fixed4 colorTex =  (tex2D(_MainTex, IN.texcoord));
    colorTex.r = colorTex.g = colorTex.b = colorTex.r * _Red + colorTex.b * _Blue + colorTex.g * _Green;
    return colorTex;
}

首先自然声明sampler2D _MainTex为原图
然后一会儿要用到的三原色常数 要从properties里“引导”一下

然后

fixed4 colorTex = tex2D(_MainTex, IN.texcoord);

首先确认片元着色器输出的应该是颜色值 或者说这个片元的一个或多个颜色值
那么tex2D这个函数是干什么的?简单来说取出_MainTex在IN.texcoord这个地方的颜色值 这个_MainTex将在每次render时从我们的图片上获取(大概吧)
得到这个点或者块(片元)的颜色
自然要操作成黑白

colorTex.r = colorTex.g = colorTex.b = colorTex.r * _Red + colorTex.b * _Blue + colorTex.g * _Green;

其实也很好理解 我们平时的图片 黑白的话一定是r=g=b这样
怎么确认这个值呢 自然取决于颜色的“深度”我们就可以用
colorTex.r * _Red + colorTex.b * _Blue + colorTex.g * _Green
这样来算 当然如果你的三个常数过大那就全黑了

啊暂时先这样吧 还有很多其实我也不太明白
之后应该会更新针对UI的shader需要的东西(因为UI会有需要特别的properties等)
一边学一边搞吧。

猜你喜欢

转载自blog.csdn.net/weixin_42767868/article/details/123052788
今日推荐