[Shader] 固定管线2 纹理混合及透明

2019-08-27  本文已影响0人  周末的游戏之旅

纹理混合

Shader "Sbin/ff2"
{
    Properties{
        //变量名 在监视面板显示的名字 类型 = 默认值
        _Color("Main Color",Color) = (1,1,1,1)
        _Ambient("环境光",Color) = (0.3,0.3,0.3,0.3)
        _Specular("高光(镜面反射光)",Color)=(1,1,1,1)
        _Shininess("高光强度",Range(0,8)) = 4
        _Emission("自发光",Color)=(1,1,1,1)
        _MainTexture("主纹理",2d)=""
        _SecondTexture("次纹理",2d)=""
    }

    SubShader {
        //必须使用pass编写一个渲染通道
        pass{
            //小括号为固定值 中括号为参数值
            // Color(1,0,0,1)
            // Color[_Color]

            //材质命令块
            Material{
                //下面是属性

                //描述的是材质的漫反射颜色,可以理解为这个物体本身固有的颜色
                DIFFUSE[_Color]
                //设置环境光
                AMBIENT[_Ambient]
                //设置高光
                SPECULAR[_Specular]
                // 浮点值 描述Specular有多强,决定在镜面高光反射过程中被高光反射的部分的区域
                SHININESS[_Shininess]
                //自发光
                emission[_Emission]
            }
            //启用顶点光照 如果不开启光照,物体的颜色不会被反射,这时不论怎么修改颜色都不会变化
            Lighting on
            //独立的高光
            SeparateSpecular on
            
            SetTexture[_MainTexture]
            {   
                // Combine texture
                // Combine 表示合并,texture 表示参数_MainTexture
                // 这里只应用了贴图而没有应用之前的顶点光照,因此会失去光照效果
                
                // Combine texture * primary
                // primary 是fixed function shader的关键词
                // primary 代表前面所有计算了材质和光照以后的颜色
                // 这两个颜色相乘就会得到一个混合的颜色
                // 这里要注意的是 颜色rgba的每一个分量都是一个浮点数,范围是[0,1]
                // 也就是两个浮点数相乘,这时会得到一个更小的浮点数,因此颜色会看起来更深

                Combine texture * primary double
                // double 表示对这个结果乘2,也就是对 texture * primary 乘2 ,也就是提高两倍的亮度

                // Combine texture * primary quad
                // qua 乘4
            }
            // 多个纹理混合
            // SetTexture 只能有一个参数
            SetTexture[_SecondTexture]
            {
                Combine texture * previous double
                // previous 表示在这个SetTexture之前的所有计算过的材质和光照的颜色
                // 按照这个想法,可以继续编写SetTexture,但不是无限写的
                // fixed function shader 是基本对照于显卡硬件的固定渲染部分
                // 显示卡是有一个混合纹理最大上限的,显卡硬件越好能混合的纹理越多
                // 两张纹理混合是现在几乎所有显卡都支持的
            }
        }
    }
}

透明

通过上面对 fiexd function shader 的学习,可以假设如果需要透明,那么只要将各种颜色的Alpha值降低,那么经过一轮计算下来,Alpha值肯定是小数,这样就可以透明了?
事实只有这样是不够的。

ShaderLab:Blending

上面是一张渲染流程图。
当着色器渲染过后,会进入AlphaTest阶段,然后再进入Blending(混合)阶段。
Blending可以使用SrcFactor(源的部分)和DstFactor(目标的部分)进行一种混合运算。

SrcFactor是指当前正在渲染的。
DstFactor是指当前处自己之外已经渲染完的(包括天空盒)。

Blending Factor(混合因素) 解释
SrcAlpha 此阶段的值乘以源alpha值。(当前已经渲染完的Alpha值)
OneMinusSrcAlpha 此阶段的值乘以(1 - 源alpha)。(1-当前已经渲染完的Alpha值)

常见的混合类型:

Blend SrcAlpha OneMinusSrcAlpha // Traditional transparency(传统透明度)
Blend One OneMinusSrcAlpha // Premultiplied transparency(预乘透明度)
Blend One One // Additive(附加)
Blend OneMinusDstColor One // Soft Additive(软附加)
Blend DstColor Zero // Multiplicative(乘)
Blend DstColor SrcColor // 2x Multiplicative(2倍乘)

在Pass中添加Blending指令

Shader "Sbin/ff2"
{
    Properties{
        _Color("Main Color",Color) = (1,1,1,1)
        _Ambient("环境光",Color) = (0.3,0.3,0.3,0.3)
        _Specular("高光(镜面反射光)",Color)=(1,1,1,1)
        _Shininess("高光强度",Range(0,8)) = 4
        _Emission("自发光",Color)=(1,1,1,1)
        _MainTexture("主纹理",2d)=""
        _SecondTexture("次纹理",2d)=""
    }

    SubShader {
        pass{
            Blend SrcAlpha OneMinusSrcAlpha // Traditional transparency(传统透明度)
            // 效果是,用当前颜色中的的Alpha值与(1-当前颜色的Alpha值)的比例去混合之前已经渲染好的乘积颜色值


            Material{
                DIFFUSE[_Color]
                AMBIENT[_Ambient]
                SPECULAR[_Specular]
                SHININESS[_Shininess]
                emission[_Emission]
            }

            Lighting on
            
            SeparateSpecular on
            
            SetTexture[_MainTexture]
            {   
                Combine texture * primary double
            }

            SetTexture[_SecondTexture]
            {
                Combine texture * previous double
            }
        }
    }
}

效果如下:


小球的颜色虽然发生了变化,但是并没有达到透明效果。
这是因为在Unity引擎中存在一种渲染顺序的东西。

ShaderLab SubShader Tags(标签)

子着色器使用标签来告诉他们希望如何以及何时将其渲染到渲染引擎。

基本语法:

Tags {"TagName1"="Value1" "TagName2"="Value2"}

渲染顺序-队列标记:

可以使用Queue标记确定的对象的绘制顺序,一个着色器决定其对象属于哪个渲染队列,这样任何透明着色器都会确保它们在所有不透明对象之后绘制,依此类推。
有四个预定义的渲染队列:

在SubShader中添加渲染队列

Shader "Sbin/ff2"
{
    Properties{
        _Color("Main Color",Color) = (1,1,1,1)
        _Ambient("环境光",Color) = (0.3,0.3,0.3,0.3)
        _Specular("高光(镜面反射光)",Color)=(1,1,1,1)
        _Shininess("高光强度",Range(0,8)) = 4
        _Emission("自发光",Color)=(1,1,1,1)
        _MainTexture("主纹理",2d)=""
        _SecondTexture("次纹理",2d)=""
    }

    SubShader {
        
        Tags { "Queue" = "Transparent" }
        //设置渲染队列

        pass{
            Blend SrcAlpha OneMinusSrcAlpha // Traditional transparency(传统透明度)
            // 效果是,用当前颜色中的的Alpha值与(1-当前颜色的Alpha值)的比例去混合之前已经渲染好的乘积颜色值


            Material{
                DIFFUSE[_Color]
                AMBIENT[_Ambient]
                SPECULAR[_Specular]
                SHININESS[_Shininess]
                emission[_Emission]
            }

            Lighting on
            
            SeparateSpecular on
            
            SetTexture[_MainTexture]
            {   
                Combine texture * primary double
            }

            SetTexture[_SecondTexture]
            {
                Combine texture * previous double
            }
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读