XLua框架,Unity3D,WEBGL,报错ArgumentException-Destination-array-was-not-long-enough

Unity使用XLua框架,打WEBGL包,运行时报错:ArgumentException: Destination array was not long enough 具体的错误如下: dangerArgumentException: Destination array was not long enough. Check destIndex and length, and the array's lower bounds {: .prompt-danger } 由于我们UI使用的时FGUI,所以这个错误的具体表现是: 错误表现 在编辑器中运行良好,没有任何问题 打包成WEBGL运行就报这个错,但不是每次都报错, 如果报错,那么UI逻辑是正常的,如果不报错,那么UI逻辑异常,比如按钮的绑定事件错乱 解决办法 我在XLua的Issue中,找到了大佬的解决办法。是XLua在释放资源时的Lock操作引起的。原issue地址。但是大佬的贴的代码,不能直接运行,需要稍加修改才行【大佬可能给的时伪代码】。我在这里把解决步骤归纳一下: 1.添加一个非锁互斥队列【也可以不用添加,就用系统的也行】: using System.Threading; namespace XLua { public class LockFreeQueue<T> { internal class SingleLinkNode<U> where U : T { public SingleLinkNode<U> Next; public U Item; } static private bool CAS<T>(ref T location, T comparand, T newValue) where T : class { return comparand == Interlocked....

October 31, 2022 · 2 min · 376 words · Link

实现范围体爆炸

实现范围体爆炸 对于实现游戏中的艺术效果,有时候需要在画质和运行效率上进行巧妙的权衡。在实现爆炸效果上尤其如此;因为它是很多游戏的核心效果,但是在它之后的一些物理计算通常都会超过现代计算机的算力。爆炸本质上就是一团温度非常高的火红气体;所以正确模拟它的唯一方式就是在游戏中用流体模拟来模拟它。正如你所想的一样,这在运行时是不可行的,在很多的游戏中都是通过粒子来模拟。当一个物体爆炸的时候,通常会同时产生很多的火花,烟雾和一些散落的碎片,这样可以获得一个比较像的爆炸。不幸的是,这种模拟方法很容易被看破而且可能不是很真实。这里我们会了解一种折中的技术来实现爆炸效果,并且画质更好:范围体爆炸(volumetric explosions)。这个知识点背后的思考是我们不再把爆炸当作是一系列粒子的模拟;它们现在进阶到3D物体了,而不仅仅是扁平的2D贴图。 始前准备 我们通过下面的几个步骤来讲解这个知识点: 为这个效果创建一个新的着色器 创建一个新的材质,并且关联该着色器 把这个材质关联到一个球体模型上。你可以在编辑器上直接创建一个球体模型,通过菜单 GameObject | 3D Object | Sphere。 注意 使用标准的Unity球体就可以很好的演示这个知识点,但是如果你想要更大范围的爆炸,那么你可能需要面数更多的球体。事实上,顶点函数只能修改网格的顶点。所有其他的点都可以通过修改相邻顶点的位置的方式来修改它们。顶点数越少,那么爆炸效果的精细度也就越低。 这个知识点中,你需要一个渐变纹理(ramp texture),这个纹理需要有你爆炸的所有颜色梯度。你可以用GIMP或者PhotoShop工具创建一个跟下面类似的纹理: 当你有了这个图片后,把它导入到你的Unity中。然后在检查器面板(Inspector)中,确保Filter Mode设置为Bilinear,然后Wrap Mode设置为Clamp。这两个设置是为了确保对渐变纹理平滑采样。 最后,你还需要一张噪音纹理(noisy texture)。你可以在网上搜索免费的噪音纹理。一般我们都使用Perlin noise。【这里我自己找到一个网站http://kitfox.com/projects/perlinNoiseMaker/】 操作步骤 这个效果我们分两步来实现:通过顶点函数改变几何形状,通过表面函数给与正确的颜色。这两个步骤如下: 添加下面的属性到着色器中: _RampTex("Color Ramp", 2D) = "white" {} _RampOffset("Ramp offset", Range(-0.5,0.5))= 0 _NoiseTex("Noise tex", 2D) = "gray" {} _Period("Period", Range(0,1)) = 0.5 _Amount("_Amount", Range(0, 1.0)) = 0.1 _ClipRange("ClipRange", Range(0,1)) = 1 添加相应变量,让着色器的Cg代码可以访问到它们: sampler2D _RampTex; half _RampOffset; sampler2D _NoiseTex; float _Period; half _Amount; half _ClipRange; 修改输入结构体(Input structure),这样可以让它接收渐变纹理的UV数据: struct Input { float2 uv_NoiseTex; }; 添加下面的顶点函数: void vert(inout appdata_full v) { float3 disp = tex2Dlod(_NoiseTex, float4(v....

October 23, 2022 · 2 min · 236 words · Link

实现下雪效果着色器

实现下雪效果着色器 在游戏中模拟下雪效果一直都是一件有挑战的事情。大部分的游戏都会简单的直接在模型的纹理上包含雪,让这些模型看起来雪白。然而要是其中某个模型开始旋转了呢?雪并不是敷衍了事的表面工作;它应该被当做是一些材料的合理的堆积【意思是物体表面 的雪是雪花一点一点堆积起来的,而不是简简单单的给它一张白色的贴图】。在这个知识点中将会向你展示如何用一个着色器让你的模型看起来有种下雪的样子。 要完成这个效果有两个步骤。首先,对于朝向天空的三角面我们给它白色。其次,通过挤压顶点来模拟雪的堆积效果。你可以从下图看到最终的效果: 注意 本知识点并无意去创建那种超真实的下雪效果。它只是抛砖引玉,但在你的游戏当中,最终的效果定位,还是取决于你们的艺术家们,通过他们设置正确的纹理和参数来达到你的要求。 始前准备 这个效果完全基于着色器来实现,所以请按照下面的步骤操作: 1.为雪的效果创建一个新的着色器。 2.为这个着色器创建一个新的材质。 3.把这个材质添加到你想表现雪的效果的模型上去。 操作步骤 为了创建下雪的效果,请打开你的着色器,然后做以下的修改: 1.把下面的属性块替换掉你原来的着色器属性块: _MainColor("Main Color", Color) = (1.0,1.0,1.0,1.0) _MainTex("Base (RGB)", 2D) = "white" {} _Bump("Bump", 2D) = "bump" {} _Snow("Level of snow", Range(1, -1)) = 1 _SnowColor("Color of snow", Color) = (1.0,1.0,1.0,1.0) _SnowDirection("Direction of snow", Vector) = (0,1,0) _SnowDepth("Depth of snow", Range(0,1)) = 0 2.添加与属性块对应的变量: sampler2D _MainTex; sampler2D _Bump; float _Snow; float4 _SnowColor; float4 _MainColor; float4 _SnowDirection; float _SnowDepth; 3....

July 17, 2022 · 2 min · 232 words · Link

模型挤压

模型挤压 重复是游戏当中最要命的一个问题之一。在游戏中创建新内容是一项费时的任务,当你要创建成千上万的敌人时,那么有很大的可能这些敌人有可能会看起来一样。这个时候利用着色器修改模型的基本几何图形,从而让模型产生不同的变化,可以说是一种 相对来说性能较好的方法。这个知识点中我们会给你演示一种叫做 法线挤压(normal extrusion) 的技术,可以用来创建胖的或者瘦的模型,就比如下图所示的来自Unity的demo中的士兵: 始前准备 在这个知识点中,我们需要获取要挤压的模型的着色器。获得该着色器后,复制它,因为这样能安全的编辑拷贝的着色器。我们可以按照下面的步骤进行: 1.找到模型使用的着色器[原着色器就是一个标准的着色器,没有找到就自己新建一个也行],通过快捷键 Ctrl + D 复制它。 2.复制模型原有的材质,并且将之前复制的着色器添加给它。 3.把这个新的材质添加到模型上,并且开始编辑它。 为了达到效果,你的模型还要有 法线(normals) 。 操作步骤 为了创建这个效果,我们先来编辑刚刚复制的着色器: 1.首先给我们的着色器添加一个属性,用于调整压缩效果。我们这里的调节范围是从 -0.00005 到 0.00005 【书上是-1到1,但实际上书上的范围太大了,各位可以自己试试】,当然你可以根据自己的需要调节这个范围【 _MainTex 是需要的,因为人物是需要贴图的。】: _MainTex("Texture", 2D) = "white" {} _Amount ("Extrusion Amount", Range(-0.00005, 0.00005)) = 0 2.我们的属性和变量是成对出现的,在着色器中定义下面的变量: float _Amount; 3.修改 pragma 预编译指令让Unity知道我们要使用 顶点修饰(vertex modifier) 。然后在它后面添加 vertex:function_name,function_name就是你自定义的方法名,当我我们这里叫 vert: #pragma surface surf Lambert vertex:vert 4.添加下面的顶点修改代码: void vert (inout appdata_full v) { v.vertex.xyz += v.normal * _Amount; } 5.这样着色器就写好了;这样你就可以在 检查器面板(Inspactor) 中通过修改材质上的 Amount 参数来控制士兵的胖瘦了。【书本写的不清楚,其实还有贴图的代码,作者没有交代,所以完整的代码如下:】 Shader "Custom/Normal Extrusion" { Properties { _MainTex ("Albedo (RGB)", 2D) = "white" {} _Amount ("Extrusion Amount", Range(-0....

July 11, 2022 · 2 min · 354 words · Link

对表面着色器中的顶点使用动画

对表面着色器中的顶点使用动画 我们现在知道了如何访问每个顶点数据的一些基础知识,这次让我们更进一步的了解一些其他类型的数据和顶点的位置。 使用顶点函数,我们可以访问网格中每个顶点位置。具体来说就是可以在着色器处理渲染的过程中,这些函数可以让我们单独对每一个顶点进行修改。 这个知识点当中,我们会创建一个着色器,并且用三角函数的正弦函数(sine wave)来修改网格当中的每一个顶点。该技术可以用来创建旗子飘动或者海浪等物体动画。 始前准备 我们把资源都放一块儿,这样方便我们为顶点着色器( Vertex Shader )编写代码: 1.创建一个新的场景,并且创建一个平面网格( plane mesh ),把它放在场景正中央,位置归零。 2.然后创建一个新的材质和着色器。 3.最后,把着色器挂到材质上,在把材质挂到平面网格上。 最终,你的场景看起来应该跟下图一样: 操作步骤 场景创建好后,鼠标双击打开刚刚我们创建的着色器: 1.让我们给着色器的属性块下面的预设值: Properties { _MainTex ("Base (RGB)", 2D) = "white" {} _tintAmount ("Tint Amount", Range(0,1)) = 0.5 _ColorA ("Color A", Color) = (1,1,1,1) _ColorB ("Color B", Color) = (1,1,1,1) _Speed ("Wave Speed", Range(0.1, 80)) = 5 _Frequency ("Wave Frequency", Range(0, 5)) = 2 _Amplitude ("Wave Amplitude", Range(-1, 1)) = 1 } 2.接下来我们通过下面的声明告诉Unity,我们需要使用顶点函数了,添加声明的位置在: #pragma statement: CGPROGRAM #pragma surface surf Lambert vertex:vert 3....

July 9, 2022 · 1 min · 204 words · Link

顶点函数

第五章 顶点函数 **着色器(shader)**这个术语最开始源于Cg领域,它主要用于模拟现实中的光照(阴影)在3D模型中的表现。而如今,着色器的用途远不止上面这些。它不仅可以定义物体的外观表现方式,还可以完全重新定义它们的形状。 如果你想学习如何通过着色器来修改3D模型的几何形状,这一章的内容非常适合你。 在这一章,你将会学习下面这些知识点: 在表面着色器(Surface Shader)中访问顶点颜色 对表面着色器中的顶点使用动画 模型挤压 实现下雪效果着色器 实现范围体爆炸 介绍 在第一章,创建你的第一个着色器中,我们 解释了3D模型不仅仅是一些三角形的集合。每一个顶点都包含了要正确渲染这个模型所必须的一些数据。这一章,为了在着色中能使用这些数据,我们将探索如何访问这些信息。而且我们还将探索如何使用Cg代码对物体进行形变的具体细节。 在表面着色器中访问顶点颜色 在这个章节,让我们来看看如何在着色器中用顶点函数来访问这些模型的顶点信息。这些知识旨在让我利用模型顶点包含的信息元素来创造一些真正实用的和引人入胜的视觉效果。 顶点函数中的顶点能返回一些我们想要的信息。你可以用float3这类值来获得顶点的法线方向信息,顶点的位置信息。你甚至可以将颜色值保存在每个顶点中,并且用float4这类值来返回该颜色。这些将是这个知识点我们将要讲的东西。 我们需要理解在表面着色器(Surface Shader)中,如何将颜色信息保存到顶点中以及如何获取这些颜色信息。 始前准备 为了编写这个着色器,我们需要准备一些资源。下面这些步骤是我们创建这个顶点着色器(Vertex Shader)的准备和设置: 1.为了能够看见顶点颜色,我们需要一个顶点设置了颜色的模型。当然你可以用Unity来添加这些颜色,这样的话你不得不编写一个工具来单独的应用这些颜色,或者编写一些脚本来获取刚刚添加的颜色。但是在这里,我们简单的利用Maya 来把颜色应用到我们的模型顶点上。但是现在这个模型你可以在这本书的支持页面获得https://www.packtpub.com/books/content/support【实际上这个地址根本没有这个模型,这本书 的代码我放在这里了本书的代码包】 2.创建一个新的场景,并且把导入的模型放到场景中。 3.创建一个新的着色器和一个新的材质。完成创建后,把着色器添加到材质上,然后把材质添加到模型上。 你的场景看起来应该跟下面的屏幕截图一样: 操作步骤 随着我们的场景,着色器,材质这些创建好后,我们就可以开始为我们的着色器编写代码了。我们在编辑器的Project面板中双击我们创建的Shader打开它。然后跟着下面的步骤走: 1.因为我们创建的着色器很简单,所以在着色器的 属性(Properties) 块中没有必要包含任何属性。但我们仍然需要有一个全局的tint颜色,仅仅是为了跟书中的其他着色器形式上保持一致而已。在着色器的属性块中写入以下代码: Properties { _MainTint("Global Color Tint", Color) = (1,1,1,1) } 2.下面这一步中, 是告诉Unity我们将在着色器中包含一个顶点函数: CGPROGRAM #pragma surface surf Lambert vertex:vert 3.跟往常一样,如果我们在属性块中包含了属性,那么我们要确保在 CGPROGRAM 声明中定义与之对应的变量才行。我们在 #pragma 声明的正下方输入下面的代码: float4 _MainTint; 4.接下来我们要关注 输入结构体(Input struct)。我们还要再定义一个新的变量,主要是给我们的 surf() 方法用,用来接收从 vert() 这个函数中返回的数据: struct Input { float2 uv_MainTex; float4 vertColor; }; 5....

June 26, 2022 · 1 min · 181 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