您的位置:首页 > 移动开发 > Unity3D

Unity Shader——Writing Surface Shaders

2016-11-22 15:27 309 查看
Unity Shader——Writing Surface Shaders(0)

原文:http://www.cnblogs.com/dreamlofter/p/4496579.html?utm_source=tuicool&utm_medium=referral

一、
表面着色器surface shader

标准输出结构(Surface Output)

Unity中的Surface Shader是一个代码生成器,用它来写光照shader(lit shader)相比于使用低阶的顶点/像素shader(vertex/pixel
shader)程序,会更加容易。

注意Surface Shader中并没有固定的语言和奇幻的东西(magic or ninjas involved)。它仅仅是生成原本必须由手工重复编写的代码。你也可以用Cg/HLSL来写shader代码。

 

它如何工作

你定义一个“surface
函数”,其输入是你所需要的任意UVs或数据,输出是SurfaceOutput数据结构。SurfaceOutput简单地描述了surface的属性(properties
of the surface),如反射率颜色(albedo color)、法线(normal)、散射(emission)、镜面反射(specularity )等。

 

rface Shader编译器会确定需要什么输入,有什么输出等,也会产生实际的顶点&像素shader(vertex&pixel
shaders),以及渲染路径来处理正向和延迟渲染。

 

surface标准的输出结构如下:

struct SurfaceOutput

{
        half3 Albedo;            //反射率,也就是纹理颜色值(r,g,b)
        half3 Normal;            //法线,法向量(x, y, z)
        half3 Emission;          //自发光颜色值(r, g,b)
        half Specular;           //镜面反射度
        half Gloss;              //光泽度
        half Alpha;              //透明度
};
 
在Unity 5中,surface shader也能使用物理光照模型。内建的标准和标准镜面光照模型(见下文)分别使用以下输出结构:

 struct
SurfaceOutputStandard
 {
         fixed3 Albedo;                  // 漫反射颜色
         fixed3 Normal;                  // 切线空间法线
         half3 Emission;                 //自发光
         half Metallic;            // 金属度;取0为非金属, 取1为金属
         half Smoothness;  // 光泽度;取0为非常粗糙, 取1为非常光滑
         half Occlusion;                 // 遮挡(默认值为1)
         fixed Alpha;                      // 透明度
};
 
structSurfaceOutputStandardSpecular
{
   fixed3 Albedo;      //漫反射颜色
   fixed3 Specular;    //镜面反射颜色
   fixed3 Normal;      //切线空间法线,如果赋值的话
   half3 Emission;            //自发光
   half Smoothness;    // 0=粗糙, 1=光滑
   half Occlusion;     //遮挡(默认1)
   fixed Alpha;        //透明度
};

Surface Shader编译指令

  Surface shader放在CGPROGRAM..ENDCG块中,就像其他任何的shader一样。不同处在于:

它必须放在SubShader块中,而不是Pass中。Surface
shader将会自动编译进多个pass中。

它使用#pragma surface ...指令来指示它是Surface shader。

  #pragma surface指令如下:

#pragma surface surfaceFunction lightModel [optionalparams]

必须参数

surfaceFunction —拥有surface shader代码的Cg函数。此函数应有这样的格式:void
surf (Input IN, inout SurfaceOutput o),其中Input是你定义好的结构,它应该包含任何纹理坐标以及surface函数所需的额外的自动变量。

lightModel —要使用的光照模型。内建的光照模型是基于物理的标准和标准镜面光照模型,以及简单的非物理Lambert(漫反射)和BlinnPhong(镜面)光照模型。

来学习如何编写。

光照模型是一个以Lighting开头与名字组合在一起的合乎规范的函数。你可以在你的着色器文件(shader file)或导入文件(included files)中的任何一个地方声明它。这个函数是:

half4 LightingName (SurfaceOutput s, half3 lightDir, halfatten);这是在正向渲染路径(forwardrendering path)中使用的光照模式。它不是取决于视图方向的(viewdirection)。例如:漫反射(diffuse)。

half4 LightingName (SurfaceOutput s, half3 lightDir,half3 viewDir, half atten);这是在正向渲染路径(forwardrendering
path)中使用的光照模式。它取决于视图的方向(view direction)。

half4 LightingName_PrePass (SurfaceOutput s, half4light); 这是在延时光照路径(deferredlighting path)中使用的。

标准光照模型使用SurfaceOutputStandard输出结构,并匹配Unity中的标准(金属工作流)shader。

标准镜面光照模型使用SurfaceOutputStandardSpecular输出结构,并匹配Unity中的标准(高光设置)shader。

Lambert和BinnPhong光照模型是不基于物理的(来自Unity 4.x),但是使用它们的shader在低配电脑上能够渲染地更快。

可选参数:

  透明度和alpha测试(Transparency and alpha
testing)
由alpha和alphatest指令控制。通常透明度有两种类型:传统alpha混合(用于对象淡出)或更逼近物理的“混合预乘”(允许半透明的表面保持合适的镜面反射)。开启半透明度使得产生的surface
shader代码包含blending指令:基于给定的变量,开启alpha裁剪将会在生成的像素shader中进行碎片丢弃。

alpha 或 alpha:auto
—  将会选择fade-transparency (同alpha:fade)作为简单的光照函数,选择premultiplied transparency (同alpha:premul)作为物理光照函数。

alpha:fade —允许传统的透明度渐隐。

alpha:premul —允许预乘alpha透明度。

alphatest:VariableName —允许alpha裁剪透明度。截断值是一个名为VariableName的float类型变量。你还可以使用addshadow指令来生成合适的投影通道。

keepalpha —默认alpha通道中的不透明度为1.0(白色),无论输出结构中的Alpha是多少或者光照函数的返回值是多少。

decal:add —附加的贴花shader(如terrain AddPass)。这对位于其他表面正上方和使用附加混合的对象来说是有意义的。

decal:blend —半透明贴花shader。这对位于其他表面正上方和使用alpha混合的对象来说是有意义的。

  

定制修改器函数(Custom modifier functions)能够用来改变或者计算输入的顶点数据,或者改变最终计算出的片段颜色。

vertex:VertexFunction —定制顶点修改器函数.此函数在生成的顶点shader的开始处被调用,可以修改或计算预顶点数据,参见 Surface
Shader Examples。

finalcolor:ColorFunction —定制的最终颜色修改器函数。参见Surface
Shader Examples。

 
阴影和镶嵌(Shadows and Tessellation)—附加指令,用于控制阴影和镶嵌的处理。

addshadow —生成一个投影通道。一般还要使用定制顶点修改器,这样投影也能获取任何程序上的顶点动画。当shader通过fallback来使用投影时,通常不需要任何特别的阴影处理。

fullforwardshadows —支持 Forward 渲染路径中所有的光照阴影模型。默认shader只支持正向渲染中来自单方向光产生的阴影。如果你需要用点光源或聚光光源来产生阴影,使用该指令。

tessellate:TessFunction —使用DX11 GPU镶嵌;该函数计算镶嵌因子。详情参见 Surface
Shader Tessellation。

 
代码生成选项 —默认生成的surface shader代码会尝试去处理所有可能的光照/阴影/光照贴图场景。尽管如此,在某些情况下你并不需要其中一些,你可以调整生成的代码来跳过它们。这样就能产生更小、加载速度更快的shader。

exclude_path:deferred exclude_path:forward exclude_path:prepass -对于给定的渲染路径(分别是Deferred
Shading, Forward 和 Legacy
Deferred),不生成相应的通道。

noshadow —在此shader中关闭所有支持阴影功能。

noambient —不应用任何环境光或光照探测(light probes)。

novertexlights —不在正向渲染中应用任何光照探测或预顶点光照。

nolightmap —在此shader中关闭所有支持光照贴图功能。

nodynlightmap —在此shader中关闭支持运行时动态全局光照(runtime dynamic global
illumination)功能。

nodirlightmap -在此shader中关闭支持方向光照贴图功能。

nofog —关闭内建的支持所有雾效果功能。

nometa —不产生“meta”通道(该meta用来由光照贴图和动态全局光照提取表面信息)。

noforwardadd —关闭Forward 渲染附加通道。这使得shader支持单方向完全光照,以及所有其他由每个顶点/SH计算的光照。同时使得shader更小。

 
混合选项

softvegetation —当柔性植被开启时,surface shader才会被渲染。

interpolateview —在顶点shader中计算视线方向并进行插值,而不是在像素shader中进行计算。这使得像素shader更快,但会多消耗一个纹理插值器。

halfasview —将half-direction向量,而不是视线方向向量,传递给光照函数。Half-direction将被逐顶点计算和单位化。这会更快,但不会完全正确。

approxview —在Unity 5.0中被移除,请用interpolateview 替代。

dualforward -在forward渲染路径中使用dual
lightmaps 。

  要了解使用上述不同选项所带来确切的变化,使用Shader Inspector中的“Show
Generated Code” 按钮将会有所帮助。

Surface Shader 输入结构

  输入结构 Input 通常有shader所需的任意纹理坐标。纹理坐标必须命名为“uv”+“纹理名称”(或者以“uv2”开头,来使用第二个纹理坐标集)。 

输入结构中还能放入一下额外的变量:

float3viewDir —将会包含视线方向,用来计算视差影响,边缘光照等。

float4 with COLOR semantic —将会包含每个顶点插值后的颜色。

float4 screenPos —将会包含反射或屏幕空间影响下的屏幕空间坐标。

float3 worldPos —将会包含世界空间坐标。

float3 worldRefl —如果surface shader没有赋值o.Normal,将会包含世界反射向量。参见例子:Reflect-Diffuse
shader。

float3 worldNormal —如果surface shader没有赋值o.Normal,将会包含世界法向量。

float3 worldRefl; INTERNAL_DATA — 如果surface shader没有赋值o.Normal,将会包含世界法向量。为了获得逐像素法线贴图的反射向量,请使用WorldReflectionVector
(IN, o.Normal)。参见例子: Reflect-Bumped shader。

float3 worldNormal; INTERNAL_DATA — 如果surface shader没有赋值o.Normal,将会包含世界法向量。为了获得逐像素法线贴图的法向量,请使用WorldNormalVector
(IN, o.Normal)。

Surface shaders 和 DirectX 11

  目前,surface shader编译管道的部分内容并不能理解 DirectX
11-特定的HLSL语法,所以如果你在使用HLSL特性,诸如StructuredBuffers, RWTextures和其他非DX9语法,你必须将之包含在只针对DX11的预处理器宏中。详情参见Platform
Specific Differences 。

Platform difference helpers 平台差异帮助

 

UNITY_UV_STARTS_AT_TOP总是用1或0定义;当纹理的V坐标系原点在纹理顶部的平台上值是1。Direct3D类似平台使用1;OpenGL类似平台使用0。

简单的surface:

Shader "LT/HalfLambert" {  

    Properties {  

        _EmissiveColor ("Emissive Color", Color) = (1,1,1,1)  

        _AmbientColor  ("Ambient Color", Color) = (1,1,1,1)  

        _MySliderValue ("This is a Slider", Range(0,10)) = 2.5  

        _RampTex ("Ramp Texture", 2D) = "white"{}  

    }  

    SubShader {  

        Tags { "RenderType"="Opaque" "RenderType"="Opaque" }  

        LOD 200  

        CGPROGRAM  

        #pragma surface surf BasicDiffuse finalcolor:final noforwardadd   

        #pragma debug  

        fixed4 _EmissiveColor;  

        fixed4 _AmbientColor;  

        half _MySliderValue;  

        sampler2D _RampTex; 

        //vert内给Input赋值,surf里使用到
        struct Input  

        {  

            half2 uv_RampTex;  

        };  

        //根据input内容计算出SurfaceOutput需要的变量,

        void surf (Input IN, inout SurfaceOutput o)  

        {  

            fixed4 c;  

            c =  pow((_EmissiveColor + _AmbientColor), _MySliderValue);  

            o.Albedo = c.rgb + tex2D(_RampTex, IN.uv_RampTex).rgb;  

            o.Alpha = c.a;  

        }  

        //半兰伯特光照模型  返回fixed4 col。无inout

        inline fixed4 LightingBasicDiffuse (SurfaceOutput s, fixed3 lightDir, fixed atten)  

        {         

            fixed difLight = max(0, dot (s.Normal, lightDir));  

            fixed hLambert = difLight * 0.5 + 0.5;  

            fixed3 ramp = tex2D(_RampTex, fixed2(hLambert,hLambert)).rgb;  

            fixed4 col;  

            col.rgb = s.Albedo * _LightColor0.rgb * (ramp) * atten;  

            col.a = s.Alpha;  

            return col;  

        }  

        void final(Input IN, SurfaceOutput o, inout fixed4 color) {    

            color = color * 0.5 + 0.5;   

        }   

        ENDCG  

    }   

    FallBack "Diffuse"  

}  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  unity unity shader