zoukankan      html  css  js  c++  java
  • UnityShader基础光照效果

    0x00 Surface Shader 常用的三种输出数据格式


    //标准输出,若自定义输出必须带上以下所列参数
    struct SurfaceOutput{
        fixed3 Albedo;  // diffuse color
        fixed3 Normal;  // tangent space normal, if written
        fixed3 Emission;
        half Specular;  // specular power in 0..1 range
        fixed Gloss;    // specular intensity
        fixed Alpha;    // alpha for transparencies
    };
    
    //基于物理光照模型标准输出
    struct SurfaceOutputStandard{
        fixed3 Albedo;      // base (diffuse or specular) color
        fixed3 Normal;      // tangent space normal, if written
        half3 Emission;
        half Metallic;      // 0=non-metal, 1=metal
        half Smoothness;    // 0=rough, 1=smooth
        half Occlusion;     // occlusion (default 1)
        fixed Alpha;        // alpha for transparencies
    };
    struct SurfaceOutputStandardSpecular{
        fixed3 Albedo;      // diffuse color
        fixed3 Specular;    // specular color
        fixed3 Normal;      // tangent space normal, if written
        half3 Emission;
        half Smoothness;    // 0=rough, 1=smooth
        half Occlusion;     // occlusion (default 1)
        fixed Alpha;        // alpha for transparencies
    };

     

    0x01 Surface Shader compile directives


    Surface shader编码在CGPROGRAM...ENDCG块内

    • 必须在Subshader块内而不能在pass内部,Surface shader将自己编译成多个通道.
    • 必须使用#pragma surface surfaceFunction lightModel [optionalparams] 指令来表明这是surface shader.

    #pragma surface surfaceFunction lightModel [optionalparams]

    蓝色必要要参数:require params

    surfaceFunction

    格式void surf (Input IN, inout SurfaceOutput o)Input自定义结构常必须包含纹理坐标和其他自需变量

    lightModel

    Standard lighting

    使用SurfaceOutputStandard

    StandardSpecular lighting

    使用SurfaceOutputStandardSpecular

    Lambert and BlinnPhong

    不支持基于物理照明,低端设备用


    surfaceFunction Input参数

    //surfaceFunction 中Input参数纹理坐标必须带uvuv2
    struct Input
    {
        //纹理坐标用uv_或uv2_前缀指示,必须!
        float2 uv_myMainTex;//uv_XXX;
        //---以下为可选---
        float3 viewDir;    //视图方向为了计算时差、边缘光照等效果,Input需要包含视图方向
        float4 color;      //每个顶点颜色值
        float4 screenPos;  //屏幕空间位置,为了获得反射效果
        float3 worldPos;   //世界坐标空间
        float3 worldRefl;  //世界空间反射向量,surface shader不能写入o.Normal参数
        float3 worldNormal;//世界空间法向量,surface shader不能写入o.Normal参数
    
        //世界坐标反射向量,surface shader必须写入o.Normal参数
        //基于逐像素法线贴图获得反射向量,请使用WorldReflectionVector(IN,o.Normal)
        float3 worldRefl;INTERNAL_DATA;
        //世界坐标法线向量,surface shader必须写入o.Normal参数
        //基于逐像素法线贴图获得反射向量,请使用WorldReflectionVector(IN,o.Normal)
        float3 worldNormal;INTERNAL_DATA;
    }

    橙色可选参数:optional params

    Transparency and alpha testing

    使用alpha and alphatest指令

    alpha

    alpha:auto


    fade-transparencypremultiplied transparency

    alpha:blend

    混合

    alpha:fade

    淡出

    alpha:premul

    预乘(使半透明表面保留适当的镜面反射)

    alphatest:VariableName

    基于给定变量值执行cutout

    keepalpha

    始终在alpha channel写入1.0

    decal:add

    叠加在表面上,并执行叠加混合

    decal:blend

    Alpha混合


    Custom modifier functions用于计算更改输入的顶点数据,或更改最终计算的片元色

    vertex:VertexFunction

    修改计算per-vertex data

    finalcolor:ColorFunction

     

    finalgbuffer:ColorFunction

    deferred path生效

    finalprepass:ColorFunction

    forward path生效。base path


    Shadows and Tessellation 阴影和网格细分

    addshadow

     

    fullforwardshadows

    forward path下,除了支持默认的一个方向光阴影,还可支持点光和聚光阴影

    tessellate:TessFunction

    //待详细补充


    Code generation options

    调整生成着色器代码选项,使得shader更小加载更快

    exclude_path:deferred,

    exclude_path:forward,

    exclude_path:prepass


    不给指定的渲染路径生成passes

    noshadow

    关闭接受所有阴影

    noambient

    不使用环境光和探头

    novertexlights

    forward path下禁用探头和逐顶点光照

    nolightmap

    关闭所有光照贴图

    nodynlightmap

    禁用运行时动态GI

    nodirlightmap

    不支持方向光光照贴图

    nofog

    禁用所有内置fog

    nometa

    不生成meta pass(提取光照贴图和GI信息用)

    noforwardadd

    禁用forward pathadditive pass,支持一个完整的方向光和所有逐顶点/SH计算的光

    nolppv

    不再支持Light Probe Proxy Volume组件

    noshadowmask

    禁用阴影遮罩


    Miscellaneous options 各种其他选项

    softvegetation

    only be rendered Soft Vegetation

    interpolateview

    在顶点着色器中计算视图方向并进行插值;而不是在像素着色器中计算它。这可以使像素着色更快,但会消耗更多的纹理插值器。

    halfasview

    传递半角向量而不是视图向量到光照函数。半角向量将被逐顶点计算和标准化。这更快,但不完全正确。

    approxview

    被遗弃了。interpolateview

    dualforward

    基本不用(官方内置shader没搜到)

    dithercrossfade

    使表面着色器支持抖动效果。然后,您可以将这个着色器应用到GameObjects中,这些GameObjects使用为交叉淡入过渡模式配置的LOD组组件。


     

    表面着色器的工作原理

    clip_image002[8]

    0x02 Surface Shader Light Model


    直接照明和间接照明,间接照明可以理解为光照烘焙。下面是Unity自带的直接照明模型:

    Lighting.cginc

    UnityLambertLight

    基于非物理的漫反射

    LightingLambert

    //..

    LightingLambert_Deferred

    //..

    LightingLambert_PrePass

    //..

    UnityBlinnPhongLight

    基于非物理的镜面高光

    LightingBlinnPhong

    //..

    LightingBlinnPhong_Deferred

    //..

    LightingBlinnPhong_PrePass

    //..

    LightingLambert_GI

    //..

    LightingBlinnPhong_GI

    //..

     

    自定义光照函数表及说明:

    格式:Lighting+ [自定义部分] + [_path]//要去掉中括号, _path是可选的,例如

    LightingMyPhongforward path路径;LightingMyPhong_Deffereddeffered自动识别后缀,不加默认是forward path.

    //orward path,不依赖视线方向向量:
    half4 Lighting<Name> (SurfaceOutput s, UnityGI gi)
    
    //在forward path,依赖视线方向向量
    //half4 Lighting<Name> (SurfaceOutput s, half3 viewDir, UnityGI gi)
     
    //在deferred lighting paths
    half4 Lighting<Name>_Deferred (
          SurfaceOutput s,                  //标准输出结构
          UnityGI gi,                       //全局光照
          out half4 outDiffuseOcclusion,    //漫反射rgb+剔除alpha组合
          out half4 outSpecSmoothness,      //高光rgb+平滑alpha组合
          out half4 outNormal               //法线
    )//后面三个参数在UnityStandardDataToGbuffer计算编码传递给GBuffer
    
    //在Use this in light prepass (legacy deferred) lighting paths. 
    //in light prepass (legacy deferred) lighting paths
    half4 Lighting<Name>_PrePass (SurfaceOutput s, half4 light)
    
    //自定义GI解析光照贴图和探针数据
    half4 Lighting<Name>_GI (SurfaceOutput s, UnityGIInput data, inout UnityGI gi)


    自带常用Lambert and BlinnPhong lighting models

    漫反射和Lambert模型

    inline fixed4 UnityLambertLight (SurfaceOutput s, UnityLight light){
        fixed diff = max (0, dot (s.Normal, light.dir));//法线和光的入射方向的夹角得到漫反射值
        fixed4 c;
        c.rgb = s.Albedo * light.color * diff;//表面色*光色*反射(强度值)
        c.a = s.Alpha;
        return c;
    }
    

    镜面高光BlinnPhong模型

    inline fixed4 UnityBlinnPhongLight (SurfaceOutput s, half3 viewDir, UnityLight light){
        half3 h = normalize (light.dir + viewDir);//视线方向+光线方向=半角方向
        fixed diff = max (0, dot (s.Normal, light.dir));//得到与光照相关的漫反射
        float nh = max (0, dot (s.Normal, h));//得到与视线相关的漫反射
        float spec = pow (nh, s.Specular*128.0) * s.Gloss;//与光滑程度有关
        fixed4 c;
        c.rgb = s.Albedo * light.color * diff + light.color * _SpecColor.rgb * spec;
        c.a = s.Alpha;
        return c;
     }

    0x03 Example


    自带的两个光照模型对比:

    image

    把SurfaceShader中光照函数翻译为VFShader

    Lambert -逐像素

    struct v2f {
        float4 pos        :SV_POSITION;
        float2 uv        :TEXCOORD0;
        float3 lightDir    :TEXCOORD1;
        float3 normal    :TEXCOORD2;
    };
    v2f m_vert(appdata_full v) {
        v2f o;
        o.pos = UnityObjectToClipPos(v.vertex);
        //Transforms 2D UV by scale/bias property
        //#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
        o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
        // Computes object space light direction
        o.lightDir = ObjSpaceLightDir(v.vertex);
        o.normal = v.normal;
        return o;
    }
    fixed4 m_frag(v2f i) : COLOR{
         float4 c = tex2D(_MainTex,i.uv);
         i.lightDir = normalize(i.lightDir);
         i.normal = normalize(i.normal);
         float diff = max(0,dot(i.normal,i.lightDir));
    
         return c * _LightColor0 * diff;
    }

    BlinnPhong -逐像素

    struct v2f {
         float4 pos        :SV_POSITION;
         float2 uv          :TEXCOORD0;
         float3 lightDir   :TEXCOORD1;
         float3 viewDir  :TEXCOORD2;
         float3 normal    :TEXCOORD3;
    };
    v2f m_vert(appdata_full v) {
         v2f o;
         o.pos = UnityObjectToClipPos(v.vertex);
         //Transforms 2D UV by scale/bias property
         //#define TRANSFORM_TEX(tex,name) (tex.xy * name##_ST.xy + name##_ST.zw)
         o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
         // Computes object space light direction
         o.lightDir    = ObjSpaceLightDir(v.vertex);
         o.viewDir    = ObjSpaceViewDir(v.vertex);
         o.normal    = v.normal;
         return o;
    } 
    
    fixed4 m_frag(v2f i) : COLOR{
         float4 c = tex2D(_MainTex,i.uv);
         i.lightDir = normalize(i.lightDir);
         i.viewDir = normalize(i.viewDir);
         i.normal = normalize(i.normal);
         half3 h = normalize(i.lightDir + i.viewDir);
         float nh = max(0, dot(h, i.normal));
         float diff = max(0, dot(i.normal, i.lightDir));
         float spec = pow(nh, _Specular * 128) * _Gloss;
         c.rgb = c.rgb * _LightColor0.rgb * diff + _SpecColor.rgb * spec;
         return c;
    }


     

  • 相关阅读:
    因式分解
    插入排序算法
    小技巧(杂乱篇章)
    错误的模糊应用(类继承问题)
    同源策略和跨域解决方案
    Django admin源码剖析
    Python中该使用%还是format来格式化字符串?
    Django的认证系统
    Django中间件
    Django form表单
  • 原文地址:https://www.cnblogs.com/baolong-chen/p/11624840.html
Copyright © 2011-2022 走看看