在本章中,我们将比上一章更详细地探讨表面着色器的主题。我们将开始建立一个非常简单的哑光材料和全息投影结束。

在本章中,我们将介绍以下食谱:

  • 实现漫反射shading
  • 访问和修改打包数组
  • 创建一个法线映射的着色器
  • 创建全息着色器

  表面着色器在第二章“创建你的第一个着色器”中介绍过,它是可以在Unity中使用的着色器类型之一。本章将向您展示这些是什么以及它们是如何工作的。一般来说,在创建任何Surface Shader时,需要完成两个基本步骤:

  1. 首先,您必须指定您想要描述的材料的某些物理属性,例如它的扩散颜色、平滑度和透明度。这些属性在一个名为surface函数的函数中初始化,并存储在一个名为SurfaceOutput的结构中
  2. 其次,SurfaceOutput被传递给一个照明模型。这是一个特殊的功能,它也将获取场景中附近灯光的信息。然后使用这些参数来计算模型中每个像素的最终颜色。照明函数是一段代码,它决定了光在接触材料时应该如何表现。

  下图大致总结了表面着色器的工作原理。自定义照明模型将在第五章“理解照明模型”中探讨,而第七章“顶点函数”将关注顶点修饰器

实现漫反射 shading

  在我们开始纹理映射之前,了解漫反射材料是如何工作的是很重要的。某些物体可能有均匀的颜色和光滑的表面,但在反射光中不够光滑。这些哑光材料最好用一个弥散着色器来表示。虽然在现实世界中不存在纯粹的漫反射材质,但漫反射着色器的实现成本相对较低,并且主要应用于低多边形美学的游戏中,所以它们值得学习。

 有几种方法可以创建一个漫反射着色器。一个快速的方法是从Unity的标准表面着色器开始,编辑它以删除任何额外的纹理信息。

准备

  在开始这个食谱之前,你应该已经创建了一个名为SimpleDiffuse的标准表面着色器。关于创建标准表面着色器的说明,请参阅第二章“创建你的第一个着色器”中的“创建一个基本的标准着色器配方”,如果你还没有这样做的话。

怎么做……

按照以下步骤应用漫反射 shading 到一个模型:

  1. 为了创建一个原始着色器的副本,我从第02章/Shaders文件夹中复制了SimpleDiffuse,在项目窗口中选择它并按Ctrl + D在我的计算机上。从那里,我移动副本到Chapter 03/Shaders文件夹,然后将复制的文件从SimpleDiffuse 1重命名为SimpleDiffuse。

  2. 通过打开你创建的SimpleDiffuse着色器,我们可以通过重命名第一行来区分第02章的版本:

    Shader "CookbookShaders/Chapter 03/StandardDiffuse"
    

    在那之后,我们可以做一些改变。

  3. 在Properties部分中,删除除_Color之外的所有变量

    Properties
    {_Color ("Color", Color) = (1, 1, 1, 1)
    }
    
  4. 从SubShader{}部分,删除_MainTex, _Glossiness,和 _metal 变量。你不应该删除对uv_MainTex的引用,因为Cg不允许Input结构为空。值将被忽略。

  5. 另外,删除UNITY_INSTANCING_BUFFER_START/END宏和与它们一起使用的注释。

  6. 删除surf()函数的内容,并将其替换为以下内容:

    void surf (Input IN, inout SurfaceOutputStandard o)
    {o. Albedo = _Color. rgb;
    }
    
  7. 你的着色器应该如下所示:

    Shader "CookbookShaders/Chapter 03/StandardDiffuse"
    {Properties{_Color ("Color", Color) = (1, 1, 1, 1)}SubShader{Tags { "RenderType"="Opaque" }LOD 200CGPROGRAM// 基于物理的标准照明模型,并在所有光类型上启用阴影#pragma surface surf Standardfullforwardshadows// 使用着色器模型3.0目标,以获得更好的外观照明#pragma target 3. 0struct Input{float2 uv_MainTex;};fixed4 _Color;void surf (Input IN, inout SurfaceOutputStandard o){o. Albedo = _Color. rgb;}ENDCG}FallBack "Diffuse"
    }
    

  由于这个着色器已经与标准着色器改装,它将使用基于物理的渲染来模拟光在模型上的行为。

NOTE
如果你想要达到非逼真的效果,你可以改变第一个#pragma指令,让它使用Lambert而不是Standard。如果这样做,还应该用SurfaceOutput替换surf函数的SurfaceOutputStandard参数。关于这个和Unity支持的其他照明模型的更多信息,Jordan Stevens整理了一篇很好的文章,你可以在这里看到:http: //www.jordanstevenstechart. com/lighting-models

  1. 保存着色器并潜入Unity。使用第二章创建你的第一个着色器中创建一个基本的标准着色器配方中提供的相同的说明,创建一个名为SimpleDiffuseMat的新材质,并将我们新创建的着色器应用到它上面。当Inspector窗口中的color属性被选中时,单击它旁边的窗口,将颜色更改为不同的颜色,比如红色。

  2. 然后,通过 File | New Scene 创建一个新场景。从弹出的模板菜单中,继续创建一个基本(内置)场景,并按下创建。

  3. 进入本书示例代码的Models文件夹,将兔子对象从Project窗口拖放到Hierarchy窗口中。

NOTE
你可以在Hierarchy选项卡中双击一个对象,将摄像机放在被选中的对象上。

  1. 从那里,分配SimpleDiffuseMat材质给对象:

它是如何工作的……

  着色器允许你通过它们的表面输出将材质的渲染属性传达给它们的照明模型。它是当前照明模型需要的所有参数的包装。不同的照明模型有不同的SurfaceOutput结构,这并不奇怪。下表显示了在Unity中使用的三种主要输出结构以及如何使用它们。


SurfaceOutput结构体有以下属性:

  • fixed3 Albedo:这是Material的扩散色
  • fixed3 Normal:这是切空间,法线,如果写入的话。
  • fixed3 Emission:颜色是物质发出的光的颜色 (这个属性在标准着色器中被声明为half3)。
  • fixed Alpha:这是材料的透明度。
  • half Specular:从0到1的镜面功率。
  • fixed Gloss:这是反射强度。

Te SurfaceOutputStandard结构体有以下属性:

  • fixed3 Albedo:这是材质的底色(无论是漫射色还是镜面色)。
  • fixed3 Normal
  • half3 Emission:它的属性被声明为half3,而在SurfaceOutput中被定义为fixed3
  • fixed Alpha:
  • half Occlusion:环境吸收(默认1)
  • half Smoothness:是平滑度(0 =粗糙,1 =光滑)
  • half Metallic: 0 = 非金属,1 = 金属。

SurfaceOutputStandardSpecular结构体有以下属性:

  • fixed3 Albedo.
  • fixed3 Normal.
  • half3 Emission.
  • fixed Alpha.
  • half Occlusion.
  • half Smoothness.
  • fixed3 Specular:这是镜面的颜色。它与SurfaceOutput中的Specular属性非常不同,因为它允许您指定一种颜色,而不是单个值

  正确使用表面着色器就是用正确的值初始化表面输出。

NOTE
有关创建Surface Shaders的更多信息,请查看以下链接:https: //docs. unity3d. com/Manual/SL-SurfaceShaders. html

访问和修改打包数组

  粗略地说,着色器内部的代码必须至少对屏幕上的每个像素执行。这就是为什么gpu是高度优化的并行计算;它们可以同时执行多个流程。在Cg中可用的标准类型的变量和运算符中,这种哲学也很明显。理解它们是必要的,不仅可以正确使用着色器,而且可以编写高度优化的着色器。

怎么做……

  Cg中有两种类型的变量:单值和包装数组。后者可以被识别,因为它们的类型以一个数字结尾,例如float3或int4。顾名思义,这些类型的变量类似于结构,这意味着它们每个都包含几个单个值。Cg称它们为打包数组,尽管它们并不完全是传统意义上的数组。

  包装数组的元素可以作为普通结构来访问。它们通常被称为x, y, z和w。然而,Cg还为它们提供了其他别名,即r、g、b和a。尽管使用x和r没有区别,但它会对你的读者产生巨大的影响。着色器编码通常涉及到位置和颜色的计算。你可能在标准着色器中见过:

o. Alpha = _Color. a;

  在这里,o是一个结构体,_Color是一个填充数组。这也是Cg禁止混合使用这两种语法的原因:你不能使用_Color.xgz

  打包数组还有一个在c#中没有对应的重要特性:swizzling。Cg允许您在一行中对打包数组中的元素进行寻址和重新排序。这再次出现在标准着色器中

o. Albedo = _Color. rgb;

  反照率是固定的3,这意味着它包含三个固定类型的值。然而,_Color被定义为固定类型。直接赋值会导致编译器错误,因为_Color大于Albedo。在c#中这样做的方法如下:

o. Albedo. r = _Color. r;
o. Albedo. g = _Color. g;
o. Albedo. b = _Color. b;

但是,它可以在Cg中压缩为:

o. Albedo = _Color. rgb;

Cg还允许你重新排序元素;例如,使用_Color。BGR交换红色和蓝色通道。

最后,当一个值被赋给一个打包数组时,它会被复制到它的所有字段中:

o. Albedo = 0; // Black =(0, 0, 0)
o. Albedo = 1; // White =(1, 1, 1)

这就是所谓的smearing。

Swizzling也可以用在表达式的左边,只允许覆盖包装数组的某些组件:

o. Albedo. rg = _Color. rg;

这叫做Masking。

有更多的…

  当它被应用到填充矩阵时,混合显示了它的全部潜力。Cg允许float4x4等类型,它表示一个四行四列的foats矩阵。你可以使用_mRC表示法访问矩阵中的单个元素,其中R是行,C是列:

float4x4 matrix;
// . . .
float first = matrix. _m00;
float last = matrix. _m33;

Te _mRC符号也可以被链接:

float4 diagonal = matrix. _m00_m11_m22_m33;

可以使用方括号选择整个行:

float4 firstRow = matrix[0] ;
// 相当于
float4 firstRow = matrix. _m00_m01_m02_m03;

另请参阅

  除了更容易编写之外,swizzling, smearing, 和 masking属性也有性能方面的好处。

  然而,不恰当地使用swizzling会使你的代码乍一看难以理解,也可能使编译器更难自动优化你的代码。

  打包数组是Cg最好的特性之一。你可以在这里找到更多关于它们的信息: http: //http. developer. nvidia. com/CgTutorial/cg_tutorial_chapter02. html


[Shader] Shader Cookbook 使用表面着色器[2]相关推荐

  1. shader入门1 了解表面着色器

    shader类型 ①Fixed function shader :属于固定渲染管线 Shader, 基本用于高级Shader在老显卡无法显示时的回滚.使用的是ShaderLab语言,语法与微软的FX ...

  2. 【Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...

  3. 【Unity3D Shader编程】之六 暗黑城堡篇 表面着色器 Surface Shader 的写法 一

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow 本系列文章由@浅墨 ...

  4. 表面着色器(Surface Shader)的写法(一)

    一.表面着色器的标准输出结构(Surface Output) 要书写Surface Shader,了解表面着色器的标准输出结构必不可少.此为表面着色器书写的第一个要素. 而定义一个"表面函数 ...

  5. Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接: http://blog.csdn.net/poem_qianmo/article/details/42215079 作者:毛星云(浅墨) ...

  6. 【浅墨Unity3D Shader编程】之六 暗黑城堡篇: 表面着色器(Surface Shader)的写法(一)

    本文主要讲解了Unity中SurfaceShader的具体写法,以及几个常用的CG函数的用法. 在这里先说明一下,表面着色器将分为两次讲解,本文介绍表面着色器的基本概念和一些写法,用内置的兰伯特光照模 ...

  7. Unity Shader 表面着色器边缘光(Rim Lighting)二

    这一节我们要实现下面的效果 (图一) (图二) 首先针对图一我们创建一个材质,并把颜色改成红色的,然后我们就得到了一个很普通的红色小球. 我们只需要在鼠标进入的时候把材质的Shader换成带边缘光的S ...

  8. [Shader] Shader Cookbook 创建你的第一个着色器[1]

      本章将涵盖一些在今天的游戏开发阴影管道中发现的更常见的扩散技术.让我们想象一个立方体,它被均匀地涂成白色,在一个有定向光的3D环境中.即使在每张脸上使用的颜色是相同的,它们也会有不同的白色深浅,这 ...

  9. Unity Shader 燃烧消融效果(surface表面着色器)

    有些时候需要让角色死亡时逐渐燃烧消失,用表面着色器很容易实现. 可以用一张黑白图片控制各部位的消融顺序,比如让该图片的某通道和一个变量相比,小于该变量则舍弃片元.变量从0不断变大,则消融面积逐渐扩大. ...

最新文章

  1. 研究生要这样度过!(转)
  2. [YTU]_2443( C++习题 复数类--重载运算符3+)
  3. IDEA+Maven运行调试MapReduce程序
  4. 【转载】COM 连接点
  5. Win11提示无法安装程序怎么办 Win11提示无法安装程序的解决方法
  6. window.open完美替代window.showModalDialog
  7. Redis的主从复制和 哨兵模式
  8. VS+PCL的4099警告的解决方法
  9. 【Python量化】蒙特卡洛模拟法预测股价走势
  10. 初中参观机器人博物馆的作文_参观足球机器人实验室_550字
  11. Android中调用文件管理器进行选择文件(记录)
  12. 计划制定与管理-日事清
  13. 使用libimobiledevice在linux上挂载iphone6
  14. React Native 动画(Animated)笔记
  15. linux数据库管理工具
  16. 09 插件开发快速入门
  17. 攻防世界007 伪造xff_referer
  18. UE4 3D场景实现双向箭头绘制
  19. vijos1404 遭遇战
  20. 数据库复习10——PL/SQL

热门文章

  1. 有些人为什么那么努力
  2. [NOIP2007 普及组] 守望者的逃离
  3. Marahon-lb的服务发现/负载均衡
  4. 领导让你做超出本职岗位的工作,欣然接受or 坚决拒绝?
  5. 光棍节脱单有望了,让你的爱被她看见丨钛空智慧星球推荐
  6. 9.1 dfs思想 —— 【迷宫】
  7. linux6.5kdump,GitHub - figozhang/linux-5.0-kdump: Kdump+crash lab
  8. 普歌:DOM知识点大盘点(一)
  9. Java中的final,finalized,finally用法
  10. 实用版ChatBing论文阅读助手教程+新测评