范围内获取不重复的随机数

C#范围内生成不重复随机数 范围为 [startNum, endNum] , 其中0<=startNum<endNum 。 生成的个数为needNum,并且needNum <= endNum - startNum + 1 因为C#的Random类不进行种子设置的话是伪随机,所以我们要改进一下Random类的Next方法,让它尽可能朝着真随机靠近。 优化后的代码如下: public static int Random(int starNum, int endNum) { byte [] randomBytes = new byte[4]; RNGCryptoServiceProvider rngProvider = new RNGCryptoServiceProvider(); rngProvider.GetBytes(randomBytes); Int32 iSeed = BitConverter.ToInt32(randomBytes, 0); Random random = new Random(iSeed); return random.Next(starNum, endNum + 1); } public static bool IsParameterValid(int startNum, int endNum, int needCount) { if (startNum < 0 || endNum <0 || startNum > endNum || needCount == 0 || needCount > endNum - startNum + 1) { return false; } return true; } 方法一 使用两个数组,从第一个数组中随机位置抽取一个,放到第二个数组中,并且在第一个数组中删除这个值, 接下来从第一个数组的剩余数据中重复上面的步骤,直到第二个数组中获得了目标个数的值停止。 代码如下:...

April 16, 2022 · 2 min · 240 words · Link

在Unity的Hierarchy面板上添加鼠标右键菜单

在Unity的Hierarchy面板上添加右键菜单 这里添加的是复制一个模型的节点信息的功能,从子节点自身开始复制,一直到模型的父节点终止。因为有时候模型的子节点比较多,一个一个的去点开查找比较麻烦,或者想查看子节点的路径对不对。记得priority要写。 代码如下: public static class EditorTool { [MenuItem("GameObject/EditorTool/CopyPath", priority = 0)] static string CopyPath() { if (Selection.gameObjects.Length == 1) { GameObject selectObj = Selection.gameObjects[0]; StringBuilder pathSB = new StringBuilder(selectObj.name); while (selectObj.transform.parent != null) { pathSB.Insert(0, selectObj.transform.parent.name + "/"); selectObj = selectObj.transform.parent.gameObject; } GUIUtility.systemCopyBuffer = pathSB.ToString(); return pathSB.ToString(); } return ""; } } {: .shadow width = “50%” }

May 25, 2021 · 1 min · 59 words · Link

烘培场景中的光

烘培场景中的光 渲染光照的过程是非常消耗新能的。即使是目前最好的[state-of-the-art]1GPU,要准确的计算光的运动(light transport) [是指光在物体表面之间反射]也要花好些小时。 为了在游戏中让这个过程可行,光的实时渲染是必须要有的。如今的游戏引擎会在画面和效率上采取一个合理的折中方案;大部分的计算都在一个叫**光烘焙(light baking)**过程中事先计算好了。这一个知识点将会讲解光烘焙是如何工作的并且你该如何充分的利用它。 始前准备 光的烘焙需要你先准备一个场景。里面要有一些几何体,当然光也一定要有。这个知识点我们会基于Unity的标准特性,所以没有必要创建新的着色器或者材质。为了更好的控制这个过程,你可能需要访问Lighting窗口。如果你没有看见这个窗口,可以通过菜单 Window | Lighting打开,并且停靠到一个你方便使用的位置。 操作步骤 光的烘培需要一些自定义的配置。你需要做三个必要的独立步骤。 场景中静态几何体的配置 配置的时候必须按照下面的步骤: 确认好你的场景中所有不会改变位置,大小和材质的游戏物体。一般可能的是建筑物,墙,地形,道具,树木等等。 在场景中选择这些类型的游戏对象,并且在检查器面板(Inspector tab)中勾选Static这个勾选框,就如下图所示。如果任何一个被选择的对象有子对象,Unity编辑器会询问是否想把这些子对象也作为静态对象。如果它们也满足(固定的位置,大小和材质),则在弹出的对话框中选择 是,子对象也变为静态(Yes change children): 如果想让光照即影响静态游戏对象又影响非静态游戏对象,请确认把Baking属性设置为Mixed。如果只希望影响到静态游戏对象,那么把它设置为Baked。 光探针的设置 在你的游戏场景中有些游戏对象是会移动的,比如主角,敌人和NPC(non-playable characters)。如果它们进入了一个被照亮的静态区域,那么你也许想要放置一些光照探针在他们的周围。为了做到这些,请按下面的操作步骤走: 在编辑器菜单中,依次选择GameObject | Light | Light Probe Group。一个名为**光探针组(Light Probe Group)的新游戏对象就出现在检查器面板(Inspector tab)**中了。 一旦你选中这个光探针组,八个相互链接球体会出现。点击选中它,并且在场景中移动它,让它尽可能把你的角色会进入的静态区域围起来。 下图展示的就是如何用光照探针把静态的办公区域空间给围起来的例子: 3. 选择会进入光照探针区域的移动游戏对象。 4. 在检查面板(Inspector tab)中,展开渲染组件(renderer component) [通常是网格渲染器(Mesh Renderer)] 并且确认Use Light Probes这个选项被勾选了(如下图所示): 决定什么时候和什么情况下去使用光照探针是一个很关键的问题;关于此的更详细信息会在原理介绍部分介绍。 光的烘培 请按照下面的步骤进行光照的烘焙: 终于到了烘焙光照了,打开光照(Lighting)窗口并且选择光照贴图面板(Lightmaps tab)。 如果自动(Auto)勾选框勾选了,Unity编辑器将会在后台自动执行烘培过程。如果没有勾选,那就自己点击Build按钮手动烘培。 注意 即使是为相对较小场景进行光的烘培也可能会花费几个小时。如果你不断移动静态游戏对象或者光线,Unity就会从头开始光的烘培过程,这会让Unity编辑器的运行异常的慢。你可以在通过窗口Lighting | Lightmaps取消勾选Auto的勾选框来阻止Unity自动烘培,这样你就可以手动开始这个烘培过程。 原理介绍 光线的传输是渲染中最复杂的部分。 在这个阶段中,GPU会计算光线是如何在物体之间反射的。 如果一个游戏对象和它所在的光线环境不会变化,那么这个计算可以只计算一次就行了,因为在游戏中它们永远都不会变化。把游戏对象标记为**静态(Static)**就是告诉Unity可以做上面说的那样的优化。 笼统的讲,光照的烘培是关于静态游戏对象的全局光照的计算过程并且把计算的结果保存在一个叫lightmap的数据文件中。当烘培过程结束后,Lightmaps就可以在Lighting窗口中的Lightmaps页签中找到: 光的烘焙会消耗大量的内存。其实这是给这些静态表面贴上了新的纹理,这些纹理包含了光照信息。让我们想象一下,假如我们有一片森林,森林中所有的树木都共享同一个纹理。当我把这些树木都设置为静态对象,这样每一棵树都会有它独有的纹理【前面共享纹理的一部分】。 可想而知,如果不思考而无差别的使用光的烘焙,不仅会增加游戏的大小,还会大量增加内存对纹理的消耗。 在这个知识点中要讲的另一个方面是光探针(Light probing)。光的烘焙可以为静态的几何图形生成质量非常高的光照结果,但是对于运动的物体却不行。如果你的游戏角色正在进入一个静态的区域,那么他看起来跟环境就有种莫名其妙的割裂感。 它们的阴影跟周围看起来并不匹配,导致整体的美术表现看起来不尽人意。还有另外一些物体,比如一些带蒙皮的网格渲染器,即使把它们设置为静态物体,它们也不会受到全局光照的影响。所以在实时渲染中使用烘焙光照是不可能的,所以我们需要 光照探针这个有效的替代方案。每一个光照探针会在空间中的一个特殊点对全局光照进行采样。而一组光照探针就可以在空间中的多个点采样,这样的话就可以在一个特殊的空间中修改全局光照。这样我们在移动的物体上就可以投射更好的光照表现, 即使全局光照仅仅是计算了仅有的几个点。有个很重要的点是记得用这些光照探针把这个特殊的空间包裹起来,这样光照探针才能起作用。最好把这些光照探针放在光照条件经常突然发生变化的区域。和光照贴图一样,光照探针也会增加内存的消耗, 同时摆放的位置也要巧妙。记住,它只为非静态图形存在。...

May 21, 2021 · 1 min · 78 words · Link

创建镜子和反射面

创建镜子和反射面 当我们从一定的角度看高光材质物体时,物体会反射光。然而可惜的是,即使是最精确的光照模型之一:菲涅尔反射Fresnel reflection,也不能完全准确的反射来自周围物体的光。前一个章节验证过的光照模型只考虑了一些光源,但是却忽略了来自其他表面的反射光。很显然,用目前我们学的关于着色的知识,来创建一面镜子是不可能的。但是全局光照Global illumination技术提供了这种可能性,这需要提供包含了周围光照信息的PBR着色器。 这就要求物体不仅需要有高光部分,还需要有依赖周围其他物体的真实的反射部分。实时的反射非常消耗性能并且需要一些自定义的设置和调整才能工作,它们可以用来创建类似高光的效果,就如下图所示: 始前准备 这个知识点中不会涉及新的着色器。恰恰相反,大部分的工作都可以直接在编辑器上完成。就像下面的步骤展示的那样: 创建一个新场景 然后在场景中创建一个quad,这个quad会用来作为镜子。 创建一个新的材质并且把它跟这个镜子关联起来。 把这个quad放在另一个游戏对象前面。 在Unity菜单中通过GameObject | Light | Reflection Probe的步骤创建一个反射探针reflection probe并且把它放在quad的前面。 操作步骤 如果正确的按照前面的步骤操作,那么在你的场景中间会有一个quad,靠近它还有一个反射探针。为了让它出现在镜子中,还需要做西面的这些改变: 把材质的着色器类型改成Standard并且把Rendering Mode设置成Opaque。【这里的属性英文不翻译把,因为Unity大部分人都是用的英文,我担心找不到】 把Metallic和Smoothness这两个的属性设置为1。你可以看到材质会很清晰的反射天空盒。 选择反射探针并且修改Size和Probe Origin直到它刚好在quad的前面,并且让探针包含你想反射的物体。 最后把Type改成Realtime。确定Culling Mask设置的是Everything。 这样的话,你的反射探针就设置好了,看起来就跟下图一样: 原理介绍 当着色器想要周围环境信息的时候,它自己提供了一个叫做cube maps的数据结构。它在第一章,创建你的第一个着色器 简短的提及过,跟Color,2D,Float和Vector这些结构一样,都是Cg语言中的一种数据结构。笼统一点来说,cube maps就是2D纹理的3D数据结构。它们表示从中心点看过来的360度的世界视角。 Unity5可以通过特殊的投影预览cube maps,如下图所示: 当cube maps关联到一个摄像机时,它们会被天空盒skyboxes引用,因为它们此时时被用于反射天空的一种方式。它们能用于反射不在实际场景中的几何体,比如星云,云朵,星星等等。 之所以会把它们叫做**立方体贴图(cube maps)原因跟它们的创建方式有关:一个立方体贴图是由6张不同的纹理组成的,立方的每个面都有一张纹理。你可以手动的创建一个立方体贴图然后把它放到一个反射探针(reflection probe)**上。你可以把反射探针想象成一个拥有6个摄像机,拥有周围环境360度贴图的几何体。 这也解释了为什么探针的性能消耗会这么高。 在我们的场景中创建一个反射探针,这样允许Unity知道那些游戏对象再镜子的周围。如果你需要更多的反射面,那你可以添加多个探针。探针此时可以工作了,你无需再做进一步的操作。**标准着色器(Standard Shaders)**会自动使用它们。 需要注意的是当它们被设置成实时(Realtime)的时候,它们会在每一帧的开始渲染立方体贴图。这里有一个技巧可以让这个过程更快;如果你知道你想反射的几何体的哪个部分是不会移动的,你可以对反射进行烘焙。这意味着Unity可以在游戏开始前就将反射预先计算好,可以允许更精确(计算量更大)的计算。 为了做这个操作,那么你的反射探针需要设置成烘培(Baked),于此同时游戏对象也要标记为**静态(Static)**才行。静态的游戏对象没法移动和改变,因此它们特别适合地形,建筑和道具。只要静态游戏对象发生变化,Unity都会为烘焙的反射探针重新生成立方体贴图。这可能要花费几分钟到几个小时。 为了让你的游戏更加的贴近现实,有时候你需要把**实时(Realtime)和烘培(Baked)**这两种探针综合来使用。 烘培过的探针能获得高质量的环境反射,然而实时探针可以用于移动的游戏对象比如汽车或者镜子。下一个知识点 烘培场景中的光 将会解释如何进行光的烘培的具体细节。 相关补充 如果你像学习更多关于反射探针的内容,你应该通过下面的链接学习: https://docs.unity3d.com/Manual/class-ReflectionProbe.html

May 17, 2021 · 1 min · 52 words · Link

Unity 5中基于物理原理的渲染

第四章 Unity 5中基于物理原理的渲染 基于物理原理的渲染physically-based rendering是Unity5中加入的最大的变化之一,也就是我们常说的PBR。前面的一些章节重复提到过它但是没有却没向大家过多的展现。如果你不仅想知道PBR的工作原理,还想搞明白如何构建它们,那么这一张正是你需要阅读的。 在这一章,你将会学习下面的几个知识点: 理解金属质感的设置 向PBR中添加透明度 创建镜子和反射面 烘培场景中的光 介绍 我们在**第三章,理解光照模型 中介绍了所有的光照模型,简单的讨论了一下光是如何表现的。在编写它们的时候效率efficiency是最重要的方面。实时渲染的开销是很大的,类似于Lambertian和BlinnPhong这样的光照模型技术,也仅仅是在模拟现实和性能开销中的折中方案。拥有了更加强劲的GPU(graphics processing unit)后,我们就可以编写更加精细的光照模型和渲染引擎,目的就是为了模拟光的真实行为。简单概括前面的来说,这就是PBR后面的哲学。正如它的名字所表达的那样, 它是尽可能的去接近真实的物理,来处理每一个不同材质,让他们看起来都不一样。不仅如此,PBR这个术语被广泛的用于市场营销,它更像是艺术级的渲染(state-of-the-art rendering),而不是一个简单的技术。Unity5通过引入两个重要的改变,实现了PBR。首先是一个全新的光照模型(叫Standard**)。表面着色器允许开发人员指定材质的物理属性,但是他们却没有对它们应用任何的物理原理限制。PBR用新的光照模型来弥补了这个差距,应用了一些物理原理,比如能量守恒(energy conservation)[一个物体反射的光线不可能多于接收的光线],微表面散射(microsurface scattering) [粗糙表面比光滑表面的反射更没有规律],菲涅尔反射(Fresnel reflectance)[高光反射出现在掠射角内],和表面阻塞(surface occlusion)[一些角落的暗部和一些几何体很难照亮]。所有说的这方面,还有一些其他的,都被用来计算标准光照模型。第二方面让PBR开起来如此真实技术叫全局光照(Global Illumination [GI]),它是对基于物理原理的光线传输的模拟。也就是说,如果这些物体是独立的实体,那么它们不会被绘制[不会反光只吸收光的的物体,这种绝对黑体是看不见的]。它们会影响最终的渲染效果,因为光线在碰到其他物体前首先会从它们身上反射。虽然在着色器中不会自动提及这方面,但是对于了解渲染引擎是如何工作来说是很重要的部分。然而令人难过的是,实时的精确模拟光线在物体表面到底是如何反弹,这已经超出了现代GPU的能力范围。Unity5做了一些很聪明的优化,即保持了视觉质量有没有牺牲性能。然而大部分的一些进阶技术(比如反射) 需要用户的输入。上面说的这些方面都会在本章介绍。 不过希望各位留意的是,即使是PBR或者GI这些技术也不能保证你的游戏可以获得照片级的画质。要获得照片级的画面是一项很有挑战性的工作,跟每一门艺术一样,需要非常专业和杰出的技巧。 理解金属质感的设置 Unity5提供了两种不同类型的PBR着色器; 它们指的是材质的检查器面板(Inspector)中的下拉列表中的Standard着色器和Standard (Specular setup)着色器。两者的主要区别在于前者为我们暴露了Metallic这个属性,而后者没有Metallic,但暴露了Specular这个属性。metallic 属性和specular 属性代表了初始化PBR材质不同方式。推动PBR的概念之一是提供给开发人员和艺术家一种有目的性的,基于物理相关的一些属性,让他们可以调整和把玩它们。 有些材质的属性更容易用来表示它们的质金属质感强度指标,而其他的另一些属性则直接于定义了光是如何反射的,也很重要。如果你过去使用过Unity4,那么对于Standard (Specular setup)着色器应该看起来更熟悉。这个知识点会教你如何有效的使用金属质感设置(metallic setup)。有个重点需要各位注意,金属质感的工作流不仅仅用于金属材质;它是根据表面的金属质感或者非金属质感来定义材质的视觉效果的一种方式。尽管呈现的是两种不同的类型的着色器,但这**金属(Metallic )和高光(Specular)**这两种方案通常来说是相等的表示。 就像Unity文档中所展示的:http://docs.unity3d.com/Manual/StandardShaderMetallicVsSpecular.html,这两种设置都可以创建同样的材质(如下图所示): 始前准备 在这个知识点中我们将用Unity5提供的标准着色器,所以我们没有必要重新创建一个。我们通过下面的步骤来开始学习这个知识点: 创建一个新的材质球。 在这个材质球的检查器(Inspector)面板,确保Shader这个下拉菜单中选择的是Standard。 同时你需要一个带有纹理的3D模型。 操作步骤 在标准着色器中有两个主要的纹理需要配置:Albedo和Metallic。为了有效地使用金属化工作流,我们需要正确的初始化这些映射: Albedo映射应该用3D模型的**unlit(不受光照影响)**纹理初始化。 创建Metallic映射之前,先复制一份文件用留给Albedo映射。你可以在项目(Project)面板中中选择要复制的贴图,然后通过快捷键Ctrl + D**复制。 用白色 (#000000)给表示纯金属的材质的贴图区域上色。而其他要用的的颜色都用黑色(#000000)。灰色的着色应该用于表示满是灰尘的,风化的和磨损的金属表面,还有生锈表面,有刮擦的绘画等等。事实上,Unity仅仅使用了红颜色(R)通道来保存金属质感的值;而绿颜色通道(G)和蓝颜色通道(B)则被忽略了。 用图片的的alpha通道来提供材质的**光滑度(Smoothness)**信息。 把**金属质感(Metallic)**贴图关联到材质球中。**金属质感(Metallic)和光滑度(Smoothness)**的滑动条都会消失,因为这两个属性现在由贴图控制了。 原理介绍 旧着色器中的光照模型条件让艺术家们很难创造出贴近现实视觉效果。之所以会这样,是因为旧的表面着色器中所有的属性间没有关联。通过介绍金属质感的工作流,Unity5将强制对游戏对象的表现将添加更多系统参数,这样的话艺术家们就能更易创建合理的材质。 金属是电的良导体;而光是电磁波的一种形式,也就是说相比于不良导体(经常被称为绝缘体(insulators)),几乎所的金属都有相似的行为表现。导体的反射率很高,能反射大部分的光子(70-100%)。然后剩余没有被反射的光就被吸收了,不是漫反射出来,也就是说导体的漫反射元素很黑[其实我觉得翻译成很低也能说的通]。相反的是,绝缘体反射率很低(%4)而剩余的光在表面被散射掉了,所以漫反射效果明显。 在标准着色器中,纯金属材质拥有较黑的漫反射元素并且它的高光反射的颜色由Albedo贴图来定义。相反的,对于纯粹的非金属材料来说,Albedo贴图定义的是它们的漫反射元素; 而它们的高光高光颜色其实是由射进来的光颜色决定的遵守这些规则在金属工作流中可以把albedo和specular结合进Albedo贴图中去,实行精确的物理行为。在牺牲材质视觉效果控制的前提下,这能让我们节省更多的空间,而且极大的提升运行速度。 相关补充 想获得更多关于金属质感的设置的信息,你可以参考下面链接的信息: 校准图表(Calibration chart):如何校准一个金属质感的材质球 (http://blogs.unity3d.com/wp-content/uploads/2014/11/UnityMetallicChart.png) 材质图表(Material chart): 如何为一些常用的材质初始化标准着色器的参数 (http://docs.unity3d.com/Manual/StandardShaderMaterialCharts.html) Quixel MEGASCANS: 一个巨量的材质素材仓库[网站],还包括纹理和PBR的参数设置[网站已经变了,我纠正一下]...

March 15, 2021 · 1 min · 79 words · Link

向PBR中添加透明度

向PBR中添加透明度 透明度是游戏中很重要的一个方面,标准着色器支持三种不同的实现方式。 如果你想让你的材质获得很逼真的透明或者半透明属性,这个知识点非常有用。玻璃,玻璃瓶子,玻璃窗和各种结晶体都很适合PBR透明着色器。这是因为你依然可以获得PBR带来的包含透明和半透明的效果的逼真效果。 如果你想让UI或者像素艺术这样的不同的东西也具有半透明效果,这里由更加高效的可选方法,就是在第二章 表面着色器和纹理贴图 这一章节中,创建一个带透明度的材质 这个知识点。 注意 为了能获得一个有透明度的标准材质,仅仅是修改它的Albedo颜色属性的alpha通道是不够的。除非你把Rendering Mode设置成transparent,否则你的材质是不会产生透明度的。 始前准备 这个知识点将会使用标准着色器(Standard Shader),所以我们没有必要创建新的着色器了: 创建一个新的材质球 在材质球的检查器(Inspector)面板确保Shader这个属性设置为了Standard或者Standard (Specular setup)。 然后把这个新创建好的材质球应邀到你想要实现透明度的3D模型上。 操作步骤 标准着色器提供了三种不同类型的透明度。尽管非常的相似,但是它们仍然又细微的差别,并且适用的情形也是不同的。 半透明材质 像干净的塑料,晶体和玻璃这些材料是半透明的。 这就意味着它们都需要PBR这种逼真的效果(比如高光高光,菲涅尔折射和反射)而且允许几何体后面也能被看见的话。如果这是你想要的效果,就按照下面的步骤走: 在材质球的检查器(Inspector)面板,把Rendering Mode这个属性设置为Transparent。 透明度的数值由Albedo颜色或者Albedo贴图(如果有)的alpha通道来决定。 下图展示的是Unity5校准场景中四种高度抛光过的塑料球。从左到右,它们的透明度逐渐增高。最后的一个球是完全透明的,但依然保有PBR中添加的效果: 你需要注意的是大部分的透明材质不会投射阴影。 除此之外,材质的Metallic和Smoothness也会影响到透明效果。镜子似的表面可以通过把alpha设置为0获得,但是如果它反射所有入射光的话,它就不会表现出透明效果。 渐隐的游戏对象 有时候,你想用渐隐效果让一个游戏对象完全消失。在这个例子中,高光反射,菲涅尔折射 和反射等效果也会消失。当一个渐隐的游戏对象完全透明,它应该是看不见的。为了完成这些,按照下面的步骤操作: 在材质的检查器(Inspector)面板,把Rendering Mode设置为Fade。 如前面一样,用Albedo的颜色或者贴图的alpha通道来决定最终的透明度。 下图展示了一个渐隐的球体。从图中明显可以看出PBR效果也随着渐隐效果逐渐消失。正如你从下面图见到的那样,往右最后的那个球近乎消失不见了: 这个渲染模式最适合**非真实(non-realistic)**物体,比如全息投影,镭射光线,人造光线,幽灵和粒子等效果。 有洞的固态几何体 在游戏中遇到的大多数材质都是不透明的,也就是说光没有办法穿透它们。与此同时,很多物体还有非常复杂的几何面(还有平面)。如果用3D s 模型来制作叶子和草未免右点太复杂了。一个更加高效的方式使用**quad(其实是一个矩形)**加一个叶子的纹理来制作。但是叶子本身是不透明的,那剩下的那张纹理就完全是透明的。 如果你想做这种效果,就按照下面的步骤操作: 再材质的检查器(Inspector)面板,把Rendering Mode设置成Cutout。 然后使用Alpha Cutoff滑动条来调整裁剪阈值。在Albedo贴图中所有alpha值等于或者小于Alpha Cutoff值的像素点都会被隐藏。 下图截取至Unity官方的PBR教程(https://www.youtube.com/watch?v=fD_ho_ofY6A)[需要用梯子],向你演示了Cutout渲染模式效果如何在几何体上打一个孔洞: 值得注意的是Cutout并不允许几何体背面被看见。在前面的示例中,你不能看到球体的内部体积部分。如果你需要这样的一个效果,你需要创建自己的着色器并且确定几何体的背部不会被踢除。 相关补充 这个知识的演示,使用了Unity商城中的ShaderCalibration Scene免费资源,地址如下[已经失效了]: https://www.assetstore.unity3d.com/en/#!/content/25422。 更多关于albedo和transparency的信息,可以通过下面的链接查询: http://docs.unity3d.com/Manual/StandardShaderMaterialParameterAlbedoColor.html。

March 15, 2021 · 1 min · 55 words · Link

创建各向异性类型的高光反射着色器

创建各向异性类型的高光反射着色器 **各向异性(Anisotropic)**类型可以用来模拟高光或者反射,常用于表面凹槽的方向和高光在垂直方向上的扭曲形变。当你想模拟金属抛光表面的时候这种类型的着色器就会非常有用,因为这种表面并不干净,光滑和明亮。 你可以想象当你看CD或者VCD光盘的数据那面时的高光或者底面被打磨过的金属盘子和盆子。 当你仔细检查这些表面的时候你会发现,表面的这些沟纹是有方向的,通常就是被抛光的方向。当你对这样的表面应用高光时,在垂直方向上会被扭曲。 这个知识点中我们会向你介绍不同的抛光表面高光概念。在将来的一些知识点中,我们会探索如何使用这个知识点介绍的一些概念来获得一些类似于头发的扭曲反射效果,但是在这里我们还是要先学习这个技术的一些原理知识。我们自定义的各向异性着色器将使用下面这个着色器作为参考: http://wiki.unity3d.com/index.php?title=Anisotropic_Highlight_Shader 下图展示了使用**各向异性(Anisotropic)**着色器能获得的不同类型高光效果: 始前准备 让我们开始学习新的知识点吧,先按照下面的步骤在场景中创建一个着色器,材质和一些光源: 创建一个新的场景,在场景中添加一些游戏对象,添加一个平行光源,这样我们好可视化的调试我们的着色器。 创建一个新的着色器和材质,它们都应用到刚刚创建的游戏对象上去。 最后,我们需要某种法线贴图,它能指出我们各向异性类型高光的方向。 下图展示的就是这个知识点要用的各向异性类型的法线贴图。在本书的支持网页中可以获得[就在本书附带的工程代码中,获取方法前面有介绍]: https://www.packtpub.com/books/content/support 操作步骤 为了获得各向异性效果,我们需要对我们前面创建的着色器进行如下的修改: 首先得再着色器中添加我们需要用到的一些属性。这些属性允许我们控制很多中艺术效果从而最终决定表面的效果呈现: { _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 Direction", 2D) = "" {} _AnisoOffset ("Anisotropic Offset", Range(-1,1)) = -0.2 } 接着我们要让我们的**SubShader{}代码块跟我们的属性(Properties)块关联起来,这样才能让我们使用属性(Properties)**中的数据: sampler2D _MainTex; sampler2D _AnisoDir; float4 _MainTint; float4 _SpecularColor; float _AnisoOffset; float _Specular; float _SpecPower; 接下来我们要创建我们自己的光照函数,用来处理物体表面的各向异性效果。我们的代码如下: fixed4 LightingAnisotropic(SurfaceAnisoOutput s, fixed3 lightDir, half3 viewDir, fixed atten) { fixed3 halfVector = normalize(normalize(lightDir) + normalize(viewDir)); float NdotL = saturate(dot(s....

February 26, 2021 · 2 min · 285 words · Link

创建 BlinnPhong 类型的高光反射着色器

创建 BlinnPhong 类型的高光反射着色器 Blinn是另一种计算和模拟高光的更有效的方法。它只要视角方向和光线方向向量的中间向量就可以计算出来。这个高光是Jim Blinn带入到Cg世界中的。 他发现比起计算反射向量来,只要中间向量的效率更好。它减少了代码量和处理时间。 如果你在UnityCG.cginc文件中查看了Unity内建的BlinnPhong光照模型的话,它也是用了中间向量,因此它被命名为BlinnPhong 。它只是完整Phong光照计算中的一种简单的版本。 始前准备 让我们按照下面的步骤开始学习这个知识点: 这次我们不创建新的场景,就用原来场景和场景内的对象就好,然后我们需要创建一个新的着色器和材质,并且把名字都叫BlinnPhong。 当我们创建好着色器后,双击它,开始编辑。 操作步骤 按照下面的步骤走,我们来创建BlinnPhong光照模型: 首先,我们需要在着色器的**属性(Properties)**块中添加我们需要用到的属性,这样好让我们控制高光效果: 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 } 接下来在CGPROGRAM块中添加与属性对应的变量,这样我们就可以获得来自**属性(Properties)**中的数据: sampler2D _MainTex; float4 _MainTint; float4 _SpecularColor; float _SpecPower; 接下来就是要创建我们自定义的光照模型了,用来处理漫反射和高光的计算,代码如下所示: 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....

February 25, 2021 · 1 min · 204 words · Link

创建一个Phong镜面类型的高光反射着色器

创建一个Phong类型类型的高光反射着色器 一个物体表面的高光,可以简单的理解为它表面的亮度。这种类型的着色器常用于视野特效(view-dependent effects)。这是因为 为了在着色器中获得贴近现实的高光效果,你需要考虑到摄像机和人的朝向因素。而Phong高光效果是最基础和性能较好的一种着色器效果。它根据人的朝向和光的反射方向,通过计算获得一个有方向的反射。 在应用程序中,这种高光模型非常常见,涵盖游戏行业到电影等产业。虽然它在高光反射模型的精确度上不是最接近现实的,但是在大多数情况下,它大致都能满足而且性能不赖。此外,如果你的游戏对象离摄像机很远,就没有必要在提供准确的高光,这对你的高光效果着色器来说是好事。 在这个知识点中,我们会涉及到如何使用表面着色器的**输入(Input)**结构体中的一些新参数进行逐顶点和逐像素的操作。我们会了解它们之间的区别,而且还会讨论什么时候以及为什么要用这两种不同的实现方式,来应对不同的情况。 始前准备 我们按照下面的步骤来学习这次的知识点: 分别创建一个新的着色器,材质和游戏对象,为了在后面你容易照到它们,请给它们恰当命名。 创建一个新场景,在创建一个新的游戏对象,把着色器应用到材质,然后再把材质应用到游戏对象上。 再添加一个平行光源,这是为了让我们方便看我们着色器代码的高光效果。 操作步骤 请按照下面的步骤创建一个Phong类型的光照模型: 此时你可能发现了一个模式,在我们开始写着色器的时候都有的步骤:着色器属性的创建。所以,让我们先在着色器中添加下面的一些属性: 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,30)) = 1 } 接下来在CGPROGRAM块中的**SubShader{}**块中,添加与之对应的一些变量: float4 _SpecularColor; sampler2D _MainTex; float4 _MainTint; float _SpecPower; 现在我们要添加我们自定义的光照模型,因为我们要计算自己的Phong高光。如果你现在还不能理解下面的代码也不用担心;在原理介绍的部分我们会解释每一行代码的作用。在着色器的**SubShader{}**中添加下述代码: fixed4 LightingPhong (SurfaceOutput s, fixed3 lightDir, half3 viewDir,fixed atten) { // Reflection float NdotL = dot(s.Normal, lightDir); float3 reflectionVector = normalize(2....

February 25, 2021 · 1 min · 181 words · Link

创建一个Toon风格的着色器

创建一个Toon风格的着色器 **Toon着色器(toon shading)**是游戏中最常使用的效果之一,也被称作(AKA)cel shading(cel是celluloid的缩写[中文也叫 赛璐珞])。它是一种非真实渲染技术,可以让3D模型呈现一种平面效果。许多游戏中用这种着色器把3D的物体渲染成一种手绘物体的效果。下图中你能看到这两者的区别,右边的是标准着色器,左边的是Toon着色器: 始前准备 开始学习这个知识点之前,我们先创建一个着色器和对应的材质球,而且需要导入一个特殊的纹理,步骤如下: 创建一个新的着色器;在这例子中,我们会用上一个知识点的着色器进行扩展 为着色器创建一个新的材质,并且把它应用到3D模型中。 拥有曲面的模型对于toon着色器来说最好。 这个知识点需要一张额外的纹理,叫做ramp贴图[如果要全译,我把它叫梯度贴图]。有一点很重要,在导入的时候把Wrap Mode改为Clamp,如果你想让颜色的边缘变得灵敏,就把Filter Mode设置为Point : 操作步骤 通过下面的步骤我们可以获得toon风格的特殊审美呈现: 添加一个新的叫**_RampTex**纹理属性: _RampTex ("Ramp", 2D) = "white" {} 同时在CGPROGRAM块中添加对应的变量: sampler2D _RampTex; 修改**#pragma指示 ,从而让着色器使用一个叫LightingToon()**的函数: #pragma surface surf Toon 使用下面这个光照模型: fixed4 LightingToon(SurfaceOutput s ,fixed3 lightDir,fixed atten) { half NdotL = dot(s.Normal,lightDir); NdotL = tex2D(_RampTex,fixed2(NdotL,0.5)); fixed4 c; c.rgb = s.Albedo * _LightColor0.rgb*NdotL*atten; c.a = s.Alpha; return c; } 原理介绍 toon风格着色器的主要特征是它的光的渲染方式;表面并非均匀的着色。为了能达这种效果,我们需要一张ramp贴图。他的作用是对Lambertian的光线强度NdotL重新映射,然后把值赋值给另一个值。我们使用一张ramp贴图而不是一个梯度值,是为了强制光线按照步骤渲染。下图展示了ramp贴图是如何纠正光的强度的: 额外内容 我们有很多不同方式来获得toon着色器效果。 我们可以使用不同的ramp贴图来让我们的模型看起来更有吸引力,这就需要你们自己去试试了,然后找到一张你认为最好的。 还有另一种可选方法对纹理进行梯度采样,就是通过对光强度NdotL进行截断取值,这样就只能在0到1的范围内给它赋值特定的值: fixed4 LightingToon(SurfaceOutput s ,fixed3 lightDir,fixed atten) { half NdotL = dot(s....

February 23, 2021 · 1 min · 100 words · Link