这篇文章最好与前一篇连着看,自己可做比较。

1.BlinnPhong 模型

Blinn是计算和估计镜面反射的另一种更有效的方法。这是通过从 视图方向和光方向获得半矢量来完成饿。JimBlinn将它带入来Cg的世界。他发现只获得半矢量而不是计算我们自己的反射 矢量效率更高。它减少了代码和处理时间。如果你实际查看UnityCG.cginc文件中包含的内置BlinnPhong光照模型,你会注意到它也使用来半矢量,因此它被命名为BlinnPhong,它只是完整的Phong的简单版本。

a..创建一个shader命名为BlinnPhong。

b.创建一个material命名为BlinnPhongMat。

c.移走所以才当前属性,并在属性块中添加如下属性,这样我们就可以控制镜面高光的外观:

_MainTint("Diffuse Tint",Color) = (1,1,1,1)
         _MainTex("Base (RGB)",2D) = "white" {}
         _SpecularColor("Specular Color",Color) = (1,1,1,1)
         _SpecPower("Specular Power",Range(0.1,60)) = 3

d.并在CGPROGRAM中添加相关变量‘

sampler2D _MainTex;
        float4 _MainTint;
        float4 _SpecularColor;
        float _SpecPower;

e. 现在是时候创建我们自定义光照模型来处理我们的漫反射和高光计算。

fixed4 LightingCustomBlinnPhong(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten)
        {
            float NdotL = max(0, dot(s.Normal, lightDir));
            float3 halfVector = normalize(lightDir + viewDir);
            float NdotH = max(0, dot(s.Normal, halfVector));
            float spec = pow(NdotH, _SpecPower)  * _SpecularColor;
            float4 color;
            color.rgb = (s.Albedo * _LightColor0.rgb * NdotL) + (_LightColor0.rgb * _SpecularColor.rgb * spec) * atten;
            color.a = s.Alpha;
            return color;
        }

h.更新surf函数如下表

void surf(Input IN, inout SurfaceOutput o)
        {
            half4 c = tex2D(_MainTex, IN.uv_MainTex) * _MainTint;
            o.Albedo = c.rgb;
            o.Alpha = c.a;
        }

i.为了完成我们的shader,我们需要通过使用以下代码修改 #pragma语句来告诉我们的CGPROGRAM块使用我们的自定义光照模型而不是内置模型:

CPROGRAM

#pragma surface surf CustomBlinnPhong

源码如下:

Shader "Custom/BlinnPhong" {Properties {_MainTint("Diffuse Tint",Color) = (1,1,1,1)_MainTex("Base (RGB)",2D) = "white" {}_SpecularColor("Specular Color",Color) = (1,1,1,1)_SpecPower("Specular Power",Range(0.1,60)) = 3}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf CustomBlinnPhong// Use shader model 3.0 target, to get nicer looking lighting#pragma target 3.0sampler2D _MainTex;float4 _MainTint;float4 _SpecularColor;float _SpecPower;struct Input {float2 uv_MainTex;};void surf(Input IN, inout SurfaceOutput o){half4 c = tex2D(_MainTex, IN.uv_MainTex) * _MainTint;o.Albedo = c.rgb;o.Alpha = c.a;}fixed4 LightingCustomBlinnPhong(SurfaceOutput s, fixed3 lightDir, half3 viewDir, fixed atten){float NdotL = max(0, dot(s.Normal, lightDir));float3 halfVector = normalize(lightDir + viewDir);float NdotH = max(0, dot(s.Normal, halfVector));float spec = pow(NdotH, _SpecPower)  * _SpecularColor;float4 color;color.rgb = (s.Albedo * _LightColor0.rgb * NdotL) + (_LightColor0.rgb * _SpecularColor.rgb * spec) * atten;color.a = s.Alpha;return color;}ENDCG}FallBack "Diffuse"
}

它是怎么运行的

BlinnPhong Specular几乎与Phong Specular完全相同。只是它更有效,因为它使用更少的代码来视线几乎相同的效果。在引入基于物理的渲染之前,此方法是Unity 4中Specular反射的默认选择。

计算R矢量的反射通常是昂贵的,BlinnPhong Specular 模型用视图方向V和灯光方向L之间的半矢量来代替它

我们只是在视图方向和光线方向之间获取矢量,而不是计算我们自己的反射矢量,基本上模拟反射矢量。实际上已经发现这种方法比上一种方法在物理上更准确。

根据向量代数,半矢量可以如下计算:

这里|V + L|是矢量V+L的长度。在Cg中,我们只需要将视图方向和光照方向一起添加,然后将结果标准化为单位矢量:

 float3 halfVector = normalize(lightDir + viewDir)

然后,我们只需要用这个新的半矢量dot顶点法线来获得我们主要的Speculat值。在此之后,我们只需将其赋予_SpecPower的幂并将其乘以Specular颜色变量 。它在代码和数学上很轻量,但仍然为我们提供了一个很好的Specular高亮,它可以用于许多实时情况。

相关

B这些灯光模型很简单;没有真正的材料是完美的额哑光或完美的镜面。此外,对于诸如衣服,木材和皮肤的复杂材料而言,需要知道光如何在表面下方的层中散射,这并不罕见。使用下表来回顾一些光照模型,其它光照模型,可翻看之前的博客。

2.Anisotropic镜面模型

Anisotropic是一种高光或反射,它模拟表面中凹槽的方向性,并在垂直方向上修改拉伸Specular。当你想要模拟拉丝金属时,它非常有用,而不是具有清晰,光滑和抛光表面的金属。想象以下当你查看CD或DVD的数据侧,或者高光是如何在锅或平底锅的底部形成的。你会注意到,如果你仔细检查表面,凹槽的方向,通常是金属刷的方式。将镜面反射应用于此曲面时,会获得在垂直方向上拉伸的镜面反射。

a.创建一个Shader命名为Anisotropic。

b.创建一个Material命名为AnisotropicMat。

c.双击打开shader脚本在属性块里移走之前的属性而且添加如下属性,这些将允许对表面的最终外观进行大量的艺术控制,并在CGPROGRAM添加相应变量:

Properties {
        _MainTint("Diffuse Tint",Color) = (1,1,1,1)
        _MainTex("Base(RGB)" ,2D) = "white" {}
        _SpecularColor("Specular Color",Color) = (1,1,1,1)
        _Specular("Specular Amount",Range(0,1)) = 0.5
        _SpecPower("Specular Power",Range(0,1)) = 0.5
        _AnisoDir("Anisotropic Diretion",2D) = "" {}
        _AnisoOffset("Anisotropic Offset",Range(-1,1)) = -0.3

}

sampler2D _MainTex;
        float4 _MainTex;
        float4 _SpecularColor;
        float _Specular;
        float _SpecPower;
        sampler2D _AnisoDir;
        float _AnisoOffset;

d.现在我们可以创建我们的Lighting函数u,它将在我们的表面上产生正确的各向异性效果。我们将使用以下代码;

fixed4 LightingAnisotropic(SurfaceAnisoOoutput s, fixed3 lightDir, half3 viewDir, fixed atten)
        {
            fixed3 halfVector = normalize(normalize(lightDir) + normalize(viewDir));
            float NdotL = saturate(dot(s.Normal, lightDir));
            fixed HdotA = dot(normalize(s.Normal + s.AnisoDirection), halfVector);
            float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180)));
            float spec = saturate(pow(aniso, s.Gloss * 128) * s.Specular);

fixed4 c;
            c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL) + (_LightColor0.rgb * _SpecularColor.rgb * spec)) * atten;
            c.a = a.Alpha;
            return c;
        }

e.同时我们把内置的Lighting函数替换称我们新创建的Lighting函数

CGPROGRAM
        #pragma surface surf Anisotropic

h.我们还通过在 struct Input中声明以下代码,为各向异性(Anisotropic)法线贴图提供了自己的UV.这并不是完全必要的,因为我们可以只使用主纹理中的UV,但这使我们能够独立控制拉丝金属效果的平铺,以使我们可以将其缩放到我们想要的任何尺寸寸:

struct Input {
            float2 uv_MainTex;
            float2 uv_AnisoDir;
        };

i.我们也需要在struct SurfaceAnisoOutput添加

struct SurfaceAnisoOutout
        {
            fixed3 Albedo;
            fixed3 Normal;
            fixed3 Emission;
            fixed3 AnisoDirection;
            half Specular;
            fixed Gloss;
            fixed Alpha;
        };

j.最后我们需要使用surf()函数将正确的数据传递给Lighting函数。因此,我们将从各向异性法线贴图中获取每像素信息,并设置我们的Specular参数,如下所示:
        void surf (Input IN, inout SurfaceAnisoOutput o) {
            half4 c = tex2D(_MainTex, IN.uv_MainTex) * _MainTint;
            float3 anisoTex = UnpackNormal(tex2D(_AnisoDir, IN.uv_AnisoDir));

o.AnisoDiretion = anisoTex;
            o.Specular = _Specular;
            o.Gloss = _SpecPower;
            o.Albedo = c.rgb;
            o.Alpha = c.a;

}

k.保存脚本回到Unity编辑器,我们可以调节Anisotopic Offset属性值观察变化。效果图如图所示。

源码如下:

Shader "Custom/Anisotropic" {Properties {_MainTint("Diffuse Tint",Color) = (1,1,1,1)_MainTex("Base(RGB)" ,2D) = "white" {}_SpecularColor("Specular Color",Color) = (1,1,1,1)_Specular("Specular Amount",Range(0,1)) = 0.5_SpecPower("Specular Power",Range(0,1)) = 0.5_AnisoDir("Anisotropic Diretion",2D) = "" {}_AnisoOffset("Anisotropic Offset",Range(-1,1)) = -0.3}SubShader {Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM#pragma surface surf Anisotropic// Use shader model 3.0 target, to get nicer looking lighting#pragma target 3.0sampler2D _MainTex;float4 _MainTint;float4 _SpecularColor;float _Specular;float _SpecPower;sampler2D _AnisoDir;float _AnisoOffset;struct Input {float2 uv_MainTex;float2 uv_AnisoDir;};struct SurfaceAnisoOutput{fixed3 Albedo;fixed3 Normal;fixed3 Emission;fixed3 AnisoDirection;half Specular;fixed Gloss;fixed Alpha;};fixed4 LightingAnisotropic(SurfaceAnisoOutput s, fixed3 lightDir, half3 viewDir, fixed atten){fixed3 halfVector = normalize(normalize(lightDir) + normalize(viewDir));float NdotL = saturate(dot(s.Normal, lightDir));fixed HdotA = dot(normalize(s.Normal + s.AnisoDirection), halfVector);float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180)));float spec = saturate(pow(aniso, s.Gloss * 128) * s.Specular);fixed4 c;c.rgb = ((s.Albedo * _LightColor0.rgb * NdotL) + (_LightColor0.rgb * _SpecularColor.rgb * spec)) * atten;c.a = s.Alpha;return c;}void surf (Input IN, inout SurfaceAnisoOutput o) {half4 c = tex2D(_MainTex, IN.uv_MainTex) * _MainTint;float3 anisoTex = UnpackNormal(tex2D(_AnisoDir, IN.uv_AnisoDir));o.AnisoDirection = anisoTex;o.Specular = _Specular;o.Gloss = _SpecPower;o.Albedo = c.rgb;o.Alpha = c.a;}ENDCG}FallBack "Diffuse"
}

它是如何运行的

我们将这个shader分解为其核心组件,并解释我们为什么会产生这种效果。我们将在这里主要介绍自定义光照函数。我们首先声明我们自己的SurfaceAnisoOutput结构。我们需要这样做才能从各向异性法线贴图中获取没像素信息,而我们在Surface Shader中执行此操作的唯一方法是在Surface Shader中执行此操作的唯一方法是在surf()函数中使用tex2D()函数。以下代码显示了shader中使用的自定义surface output结构:

struct SurfaceAnisoOutput
        {
            fixed3 Albedo;
            fixed3 Normal;
            fixed3 Emission;
            fixed3 AnisoDirection;
            half Specular;
            fixed Gloss;
            fixed Alpha;
        };

我们可以使用SurfaceAnisotropicOutput结构作为Lighting函数和surface 函数之间的交互方式。在我们的例子中,我们将每像素纹理信息存储在我们的surf()函数中名为anisoTex的变量中,然后通过将其存储在AnisoDirection变量中将其传递给SurfaceAnisoOutput结构。一旦我们有了这个,我们就可使用s.AnisoDirection在Lighting函数中使用每像素信息。

设置此数据连接后,我们可以继续进行实际的光照计算,这首先得到通常的半矢量,这样我们就不必进行全反射计算和漫反射光照。这是用光矢量或方向点和顶点法线的点积。这是在Cg中完成的,包括如下几行:

fixed3 halfVector = normalize(normalize(lightDir) + normalize(viewDir));

float NdotL = saturate(dot(s.Normal, lightDir));

然后,我们开始对Specular进行实际修改以获得正确的外观,首先,我们用从上一步得到的halfVector点积归一化后的各向异性法线贴图的顶点法线和每像素矢量的和。这给了我们一个浮点值,它的表面法线是1 ,当它与半矢量平行时,它回被各向异性法线贴图修正,当它与半矢量垂直时,它会变成0.最后,我们用sin()函数修改这个值,这样我们基本上可以得到一个更亮的中间高亮,最终得到一个基于halfVector的环效果。前面提到的所有操作都在以下两行Cg代码中进行了总结:

fixed HdotA = dot(normalize(s.Normal + s.AnisoDirection), halfVector);

float aniso = max(0, sin(radians((HdotA + _AnisoOffset) * 180)));

最后,我们通过将它变为s.Gloss的幂来缩放aniso值的效果,然后通过将其乘以s.Specular来全局减小其强度。

这种效果非常适合创建更高级的金属类型表面,尤其时那些经过刷涂并看起啦具有方向性的表面。它也适用于头发或任何具有方向性的柔软表面。

以上均基于Unity2018.1.0f。源码可见我的GitHub

https://github.com/xiaoshuivv/ShadersUnity2018.1.0f

【《Unity 2018 Shaders and Effects Cookbook》翻译提炼】(八)BlinnPhong模型和 Anisotropic 高光(可用于金属性,头发)相关推荐

  1. 【《Unity 2018 Shaders and Effects Cookbook》翻译提炼】(九)Physically - Based Rendering

    制作过程中最重要的方面时效率,实时着色很昂贵,而Lambertian或BlinnPhong等技术是计算成本和现实之间的折中. 拥有更   强大的GPU允许我们逐步写更强大的光照模型和渲染引擎,目的是模 ...

  2. 【《Unity 2018 Shaders and Effects Cookbook》翻译提炼】(三)法线贴图和透明材质

    1.法线贴图 3D模型的每个三角形都有一个面向方向,这是它指向的方向.它通常用放置在三角形中心的箭头表示,并且与表面正交.面对方向在光线反射到表面上的方式中起着重要作用.如果两个相邻的三角形朝着不同的 ...

  3. 22.01.23 《Unity 2018 Shaders and Effects Cookbook》笔记Chapter7

    7.Fragment Shaders and Grab Passes vertex and fragment shader 对光照如何影响物体表面不感兴趣,不受物理限制,对非真实感的效果很好 使用#p ...

  4. Unity Shaders and Effects Cookbook (3-6) 创建各向异性高光类型(Anisotropic) 模拟金属拉丝效果

    这一次学习各向异性高光类型,名字真拗口,Anisotropic 这个英文单词也很拗口. 各向异性是模拟物体表面 沟槽方向性的高光反射类型,他会修改或延伸垂直方向上的高光. 比如模拟金属拉丝的效果,就可 ...

  5. Unity Shaders and Effects Cookbook (3-4) 使用高光贴图

    在学习完上一节之后.已经了解了在Unity 中怎样实现一个高光 Shader ,可是会有一个问题.就是效果看起来不切实际,如以下的问题 我用一张图片贴到了Cube上面.然后用了一个高光材质,得到了下图 ...

  6. Unity Shaders and Effects Cookbook (7-2) Surface Shader 中实现 顶点动画

    上一节中说了,在 Surface Shader 中,添加顶点函数,我们可以在 顶点函数中获取到 顶点数据,比如顶点颜色.顶点坐标等. 这一节学习获取顶点坐标,并且修改顶点坐标,来实现顶点动画. 简单介 ...

  7. Unity Shaders and Effects Cookbook (2-7)实现 Photoshop 色阶效果

    看完了这一书上的代码,然后在网上查找 Photoshop 色阶的一些解释,大致理解为:调整色阶就是调整亮度,也就是调整纹理 R.G.B 通道的数值大小. 下面是 Photoshop 中的直方图转自ht ...

  8. Unity Shaders and Effects Cookbook (4-5)Cubemap与菲涅尔反射

    菲涅尔是人名,他发现,当我们站在水中,直直的往下看水面,是看不到反射的太阳光的.而当我们往远处看时,就能看到很强的反光,也就是成语波光粼粼所体现的.这一现象就被命名为 菲涅尔反射. 刚看这一节的时候觉 ...

  9. Hands-On Unity 2018 x 移动游戏开发教程

    Hands-On Unity 2018 x Game Development for Mobile 使用Unity 2018.2创建具有出色游戏功能的精彩游戏 想学习在Unity制作游戏,但不知道从哪 ...

最新文章

  1. Linux中的sed详解
  2. 用python解“用天平找小球”题
  3. MapReduce进阶:多MapReduce的链式模式
  4. Java IO流学习总结七:Commons IO 2.5-FileUtils
  5. 【cocos2d-js官方文档】二十五、Cocos2d-JS v3.0中的单例对象
  6. 圆心角 圆弧上点坐标_数控加工中心CNC的G02/G03圆弧指令的I、J、与R的区别
  7. 《智慧书》格言91-100
  8. ubuntu 18.04 ROS melodic 尝试 ROS CANOPEN 控制 AGV
  9. 【NodeJS 学习笔记02】入门资源很重要
  10. 廖雪峰的python学习网址
  11. SharePoint 2010学习资源
  12. mysql读写分离代码层实现_Mysql主从配置,实现读写分离
  13. java的百度编辑器插件下载安装_ueditor-extend
  14. 【附资料】PMP证书有用吗?
  15. 华为Mate S发布:余承东说要在圣诞季和三星、苹果正面开战---ESM
  16. php如何根据条件删除二维数组中的元素
  17. iTunes Connect 人员如何使用testflight安装测试版ios应用
  18. TCP协议(Transmission Control Protocol)
  19. 【Cancer Research】由Y染色体LINC00278编码的新型微肽与AR信号通路介导的男性食管鳞状细胞癌相关
  20. 小米红米3(全网通/免解锁)解BL锁教程申请BootLoader解锁教程

热门文章

  1. 远古历史研究的魅力与挑战
  2. Fedora 17 安装完全指南 for y450[zz]
  3. centos7关掉烦人的时间屏幕保护
  4. 烟雨凤凰 美食与美景
  5. ***面试中所常见的SQL题***
  6. Multi-Paxos协议日志同步应用
  7. 项目中如何进行客户引导
  8. 如何在windows下vs2005下安装Bost库
  9. 养了猫之后,我的猫也秃了
  10. 高压放大器在改良电形成装置参数优化中的应用