Unity Shader——Writing Surface Shaders(3)——Surface Shader Lighting Examples

Surface Shader 光照例子

  这里有一些自定义光照模型Surface Shaders的例子。通常的Surface Shader例子在这里

  由于延迟光照在某些自定义的逐材质光照模型中表现得并不好,在下面大多数例子中,我们让shader只编译到正向渲染中。

漫反射(Diffuse)

  让我们以使用内建Lambert光照模型的shader作为开始吧!

Shader "Example/Diffuse Texture" {
    Properties {
      _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader {
      Tags { "RenderType" = "Opaque" }
      CGPROGRAM
      #pragma surface surf Lambert

      struct Input {
          float2 uv_MainTex;
      };

      sampler2D _MainTex;

      void surf (Input IN, inout SurfaceOutput o) {
          o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
      }
      ENDCG
    }
    Fallback "Diffuse"
  }

  下面是使用一张纹理贴图和不使用一张真实的纹理贴图的样子(此场景中有一个方向光)

 

  现在,我们来做个完全一样的,但是使用我们自己的光照模型,而不是内建Lambert光照模型。Surface Shader光照模型仅是一些我们需要编写的函数。这里有一个简单的Lambert光照模型。注意到只有CGPROGRAM部分发生了改变,周边的shader代码是完全一样的:

Shader "Example/Diffuse Texture" {
        Properties {
            _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader {
        Tags { "RenderType" = "Opaque" }
        CGPROGRAM
          #pragma surface surf SimpleLambert

          half4 LightingSimpleLambert (SurfaceOutput s, half3 lightDir, half atten) {
              half NdotL = dot (s.Normal, lightDir);
              half4 c;
              c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);
              c.a = s.Alpha;
              return c;
          }

        struct Input {
            float2 uv_MainTex;
        };

        sampler2D _MainTex;

        void surf (Input IN, inout SurfaceOutput o) {
            o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
        }
        ENDCG
        }
        Fallback "Diffuse"
    }

  所以我们的简单漫反射光照模型就是LightingSimpleLambert 函数。它通过计算表面法线和光线方向的点积来计算光照,然后应用光照衰减和颜色。

环绕漫反射(Diffuse Wrap)

  这里是环绕漫反射——漫反射光照的修改版,即照明环绕在物体的边缘。它对用来仿照次表面散射效果很有用。因为只是CGPROGRAM 部分发生了改变,老生常谈一次,周边的shader代码就省略了:

 ...ShaderLab code...
    CGPROGRAM
    #pragma surface surf WrapLambert

    half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten) {
        half NdotL = dot (s.Normal, lightDir);
        half diff = NdotL * 0.5 + 0.5;
        half4 c;
        c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
        c.a = s.Alpha;
        return c;
    }

    struct Input {
        float2 uv_MainTex;
    };

    sampler2D _MainTex;
        void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    }
    ENDCG
    ...ShaderLab code...

 

卡通渐变(Toon Ramp)

  下面是一个"渐变(Ramp)"光照模型。它使用一张渐变纹理来定义表面怎样对光线和法线的夹角做出反应。这能用来实现多种效果,包括卡通光照。

...ShaderLab code...
    CGPROGRAM
    #pragma surface surf Ramp

    sampler2D _Ramp;

    half4 LightingRamp (SurfaceOutput s, half3 lightDir, half atten) {
        half NdotL = dot (s.Normal, lightDir);
        half diff = NdotL * 0.5 + 0.5;
        half3 ramp = tex2D (_Ramp, float2(diff)).rgb;
        half4 c;
        c.rgb = s.Albedo * _LightColor0.rgb * ramp * (atten * 2);
        c.a = s.Alpha;
        return c;
    }

    struct Input {
        float2 uv_MainTex;
    };

    sampler2D _MainTex;

    void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    }
    ENDCG
    ...ShaderLab code...

 

简单镜面(Simple Specular)

  下面是一个简单镜面光照模型。这对于内置的BlinnPhong实际所做的内容来说非常简单。我们把它放在这来说明它是如何工作的。

  ...ShaderLab code...
    CGPROGRAM
    #pragma surface surf SimpleSpecular

    half4 LightingSimpleSpecular (SurfaceOutput s, half3 lightDir, half3 viewDir, half atten) {
        half3 h = normalize (lightDir + viewDir);

        half diff = max (0, dot (s.Normal, lightDir));

        float nh = max (0, dot (s.Normal, h));
        float spec = pow (nh, 48.0);

        half4 c;
        c.rgb = (s.Albedo * _LightColor0.rgb * diff + _LightColor0.rgb * spec) * (atten * 2);
        c.a = s.Alpha;
        return c;
    }

    struct Input {
        float2 uv_MainTex;
    };

    sampler2D _MainTex;

    void surf (Input IN, inout SurfaceOutput o) {
        o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
    }
    ENDCG
    ...ShaderLab code...

解码光照贴图(Decoding Lightmaps)

  我们将以这样一个shader作为开始:它模仿内置的光照贴图解码工作,使用Unity自带的DecodeLightmap函数解码lightmap中储存的数据信息,以及使用自带的UNITY_DIRBASIS宏定义方向光照贴图(Directional lightmap)的基本向量:

 Shader "Example/Standard Lightmap Decoding" {
        Properties {
            _MainTex ("Texture", 2D) = "white" {}
        }
        SubShader {
            Tags { "RenderType" = "Opaque" }
            CGPROGRAM

            #pragma surface surf Standard

            half4 LightingStandard (SurfaceOutput s, half3 lightDir, half atten) {
                half NdotL = dot (s.Normal, lightDir);
                half4 c; c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2);
                c.a = s.Alpha;
                return c;
            }

            inline fixed4 LightingStandard_SingleLightmap (SurfaceOutput s, fixed4 color) {
                half3 lm = DecodeLightmap (color);
                return fixed4(lm, 0);
            }

            inline fixed4 LightingStandard_DualLightmap (SurfaceOutput s, fixed4 totalColor, fixed4 indirectOnlyColor, half indirectFade) {
                half3 lm = lerp (DecodeLightmap (indirectOnlyColor), DecodeLightmap (totalColor), indirectFade);
                return fixed4(lm, 0);
            }

            inline fixed4 LightingStandard_StandardLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal) {
                UNITY_DIRBASIS

                half3 lm = DecodeLightmap (color);
                half3 scalePerBasisVector = DecodeLightmap (scale);

                if (surfFuncWritesNormal)
                {
                    half3 normalInRnmBasis = saturate (mul (unity_DirBasis, s.Normal));
                    lm *= dot (normalInRnmBasis, scalePerBasisVector);
                }

                return fixed4(lm, 0);
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;

            void surf (Input IN, inout SurfaceOutput o) {
                o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
            }
            ENDCG
            }
        Fallback "Diffuse"
    }

  现在,让我们为光照贴图中储存的光添加些色调映射(tone mapping):

Shader "Example/Tonemapped Lightmap Decoding" {
        Properties {
            _MainTex ("Texture", 2D) = "white" {}
            _Gain ("Lightmap tone-mapping Gain", Float) = 1
            _Knee ("Lightmap tone-mapping Knee", Float) = 0.5
            _Compress ("Lightmap tone-mapping Compress", Float) = 0.33
        }
        SubShader {
            Tags { "RenderType" = "Opaque" }
            CGPROGRAM

            #pragma surface surf Tonemapped

            half4 LightingTonemapped (SurfaceOutput s, half3 lightDir, half atten) {
                half NdotL = dot (s.Normal, lightDir);
                half4 c; c.rgb = s.Albedo * _LightColor0.rgb * (NdotL * atten * 2); c.a = s.Alpha;
                return c;
            }

            half _Gain;
            half _Knee;
            half _Compress;

            inline half3 TonemapLight (half3 i) {
                i *= _Gain;
                return (i > _Knee)? (((i - _Knee)*_Compress)+_Knee): i;
            }

            inline fixed4 LightingTonemapped_SingleLightmap (SurfaceOutput s, fixed4 color) {
                half3 lm = TonemapLight(DecodeLightmap (color));
                return fixed4(lm, 0);
            }

            inline fixed4 LightingTonemapped_DualLightmap (SurfaceOutput s, fixed4 totalColor, fixed4 indirectOnlyColor, half indirectFade) {
                half3 lm = TonemapLight(lerp (DecodeLightmap (indirectOnlyColor), DecodeLightmap (totalColor), indirectFade));
                return fixed4(lm, 0);
            }

            inline fixed4 LightingTonemapped_StandardLightmap (SurfaceOutput s, fixed4 color, fixed4 scale, bool surfFuncWritesNormal) {
                UNITY_DIRBASIS

                half3 lm = TonemapLight(DecodeLightmap (color));
                half3 scalePerBasisVector = DecodeLightmap (scale);

                if (surfFuncWritesNormal)
                {
                    half3 normalInRnmBasis = saturate (mul (unity_DirBasis, s.Normal));
                    lm *= dot (normalInRnmBasis, scalePerBasisVector);
                }

                return fixed4(lm, 0);
            }

            struct Input {
                float2 uv_MainTex;
            };

            sampler2D _MainTex;

            void surf (Input IN, inout SurfaceOutput o) {
                o.Albedo = tex2D (_MainTex, IN.uv_MainTex).rgb;
            }
            ENDCG
        }
        Fallback "Diffuse"
    }
时间: 2024-10-22 20:09:39

Unity Shader——Writing Surface Shaders(3)——Surface Shader Lighting Examples的相关文章

Unity Shader——Writing Surface Shaders(1)——Surface Shader Examples

这里有Surface Shader的一些例子.下面的这些例子关注使用内建的光照模型:关于如何使用自定义光照模型的例子参见Surface Shader Lighting Examples. 简单 我们将会以一个非常简单的shader作为开始,并在此基础上逐渐完善.下面这个shader会把表面颜色置成“白色”.它使用内建的Lambert(漫反射)光照模型. Shader "Example/Diffuse Simple" { SubShader { Tags { "RenderTy

Unity Shader——Writing Surface Shaders(0)

从今天起,开始翻译Unity关于shader的官方文档.翻译水平比较一般,目的主要是通过翻译来提升对shader的见解,也让其他人更容易的了解shader.以下开始正文内容: 编写Surface Shaders 和光交互的shader写起来很复杂,有不同的光照类型.阴影选项.渲染路径(正向渲染和延迟渲染),有时shader需要考虑所有的复杂性. Unity中的Surface Shader是一个代码生成器,用它来写光照shader(lit shader)相比于使用低阶的顶点/像素shader(ve

Unity Shader——Writing Surface Shaders(2)——Custom Lighting models in Surface Shaders

Surface Shader中的自定义光照模型 当你在编写 Surface Shaders 时,是在描述一个表面的属性(反射颜色.法线……),而且光的交互过程是由一个光照模型来计算的.内建的光照模型有Lambert(漫反射光照)和BlinnPhong(镜面光照). 有时候,你可能想要使用一个自定义的光照模型,这在Surface Shader中是可能的.光照模型其实就是一些满足某些约定的Cg/HLSL函数.Unity内建的光照模型Lambert和BlinnPhong定义在Lighting.cgin

Writing Surface Shaders

[Writing Surface Shaders] Writing shaders that interact with lighting is complex. There are different light types, different shadow options, different rendering paths (forward and deferred rendering), and the shader should somehow handle all that com

【Unity Shaders】Mobile Shader Adjustment—— 什么是高效的Shader

本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源(当然你也可以从官网下载). ========================================== 分割线 ========================================== 写在前面 之前学习的各种Shader时,我们从没有考虑在所有平台下的可用性.Unity是一个强大的跨

【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader

本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源(当然你也可以从官网下载). ========================================== 分割线 ========================================== 写在前面 在上一篇里,我们学习了一些技巧来初步优化Shader.这次,我们学习更多的技术来实现一个更

Unity加载模块深度解析(Shader)

作者:张鑫链接:https://zhuanlan.zhihu.com/p/21949663来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 接上一篇 加载模块深度解析(二),我们重点讨论了网格资源的加载性能.今天,我们再来为你揭开Shader资源的加载效率. 这是侑虎科技第59篇原创文章,欢迎转发分享,未经作者授权请勿转载.同时如果您有任何独到的见解或者发现也欢迎联系我们,一起探讨.(QQ群465082844) 资源加载性能测试代码 与上篇所提出的测试代码一样,我们

Unity3D Shader官方教程翻译(十九)----Shader语法,编写表面着色器

Writing Surface Shaders Writing shaders that interact with lighting is complex. There are different light types, different shadow options, different rendering paths (forward and deferred rendering), and the shader should somehow handle all that compl

【译】Unity3D Shader 新手教程(2/6) &mdash;&mdash; 积雪Shader

如果你是一个shader编程的新手,并且你想学到下面这些酷炫的技术,我觉得你可以看看这篇教程: 实现一个积雪效果的shader 创建一个具有凹凸纹理的shader 为每个像素修改其对应纹理值 在表面着色器中修改模型的顶点数据 引论 这是我们系列教程的第二部分,我们将在此部分实现些有用的技术.在学习完第一部分的所有背景知识后,我们将利用所学的知识实现一个简单的积雪效果的shader.效果如下: 准备工作 我们想做的其实很简单,简单介绍一下: 随着Snow Level(表示积雪的程度,该值越大,积雪