模型挤压
模型挤压 重复是游戏当中最要命的一个问题之一。在游戏中创建新内容是一项费时的任务,当你要创建成千上万的敌人时,那么有很大的可能这些敌人有可能会看起来一样。这个时候利用着色器修改模型的基本几何图形,从而让模型产生不同的变化,可以说是一种 相对来说性能较好的方法。这个知识点中我们会给你演示一种叫做 法线挤压(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.00005, 0.00005)) = 0 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM // Physically based Standard lighting model, and enable shadows on all light types #pragma surface surf Lambert vertex:vert // Use shader model 3.0 target, to get nicer looking lighting #pragma target 3.0 sampler2D _MainTex; struct Input { float2 uv_MainTex; }; float _Amount; // Add instancing support for this shader. You need to check 'Enable Instancing' on materials that use the shader. // See https://docs.unity3d.com/Manual/GPUInstancing.html for more information about instancing. // #pragma instancing_options assumeuniformscaling UNITY_INSTANCING_CBUFFER_START(Props) // put more per-instance properties here UNITY_INSTANCING_CBUFFER_END void vert (inout appdata_full v) { v.vertex.xyz += v.normal * _Amount; } void surf (Input IN, inout SurfaceOutput o) { // Albedo comes from a texture tinted by color o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb; } ENDCG } FallBack "Diffuse" } 原理介绍 表面着色器(Surface shader) 分两步来工作。在前面的章节中,我们只是探索了它最后一个步骤:表面函数(surface function。这里我们接触了另一种函数:顶点修饰(vertex modifier) 。它接收一个顶点的数据结构 (通常这个数据结构叫做 appdata_full )并且对它进行转变。它让我们对于模型的几何图形做各种视觉效果给与很大的自由度。我们通过在表面着色器的预编译指令 #pragma 那里添加 vertex:vert 来告知GPU 我们添加了 自己的顶点函数。你可以查看 第六章,片元着色器和抓取通道 来学习怎么在顶点着色器和片元着色器中定义顶点修饰。 ...