JSPX和JSFF如何更改文件类型型之间的区别ADF的框架内

&img src=&/v2-454d014ed158c61ecaec5df07a7c6e34_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/v2-454d014ed158c61ecaec5df07a7c6e34_r.jpg&&&h2&0x00 前言&/h2&&p&我想很多开发游戏的小伙伴都希望自己的场景内能渲染越多物体越好,甚至是能同时渲染成千上万个有自己动作的游戏角色就更好了。&/p&&p&但不幸的是,渲染和管理大量的游戏对象是以牺牲CPU和GPU性能为代价的,因为有太多Draw Call的问题,如果游戏对象有动画的话还会涉及到cpu的蒙皮开销,最后我们必须找到其他的解决方案。那么本文就来聊聊利用GPU实现角色的动画效果,减少CPU端的蒙皮开销;同时将渲染10,000个带动画的模型的Draw Call从10,000+减少到22个。(模型来自:&a href=&/?target=https%3A//www./en/%23%21/content/86576& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&RTS Mini Legion Footman Handpainted&i class=&icon-external&&&/i&&/a&)&/p&&img src=&/v2-1afc961f5be3d9d1ea111df7f85c750f_b.jpg& data-rawwidth=&1162& data-rawheight=&623& data-thumbnail=&/v2-1afc961f5be3d9d1ea111df7f85c750f_b.jpg& class=&origin_image zh-lightbox-thumb& width=&1162& data-original=&/v2-1afc961f5be3d9d1ea111df7f85c750f_r.gif&&&p&&br&&/p&&h2&0x01 Animator和SkinnedMeshRender的问题&/h2&&p&正常情况下,大家都会使用Animator来管理角色的动画,而角色也必须使用SkinnedMeshRender来进行渲染。&/p&&img src=&/v2-80b8fa52fff4f0da714cc_b.jpg& data-rawwidth=&1162& data-rawheight=&623& data-thumbnail=&/v2-80b8fa52fff4f0da714cc_b.jpg& class=&origin_image zh-lightbox-thumb& width=&1162& data-original=&/v2-80b8fa52fff4f0da714cc_r.gif&&&p&&br&&/p&&p&例如在我的测试场景中,默认情况下渲染10,000个带动作的士兵模型,可以看到此时的各个性能指标十分糟糕:CPU 320+ms,DrawCall:8700+。&/p&&img src=&/v2-8b3ba84e7edcaceeec59_b.png& data-rawwidth=&799& data-rawheight=&196& class=&origin_image zh-lightbox-thumb& width=&799& data-original=&/v2-8b3ba84e7edcaceeec59_r.png&&&p&&br&&/p&&p&因此,可以发现如果要渲染的动画角色数量很大时主要会有以下两个巨大的开销:&/p&&ul&&li&CPU在处理动画时的开销。&/li&&/ul&&p&&br&&/p&&ul&&li&每个角色一个Draw Call造成的开销。&/li&&/ul&&p&&br&&/p&&p&CPU的这两大开销限制了我们使用传统方式渲染大规模角色的可能性。因此一些替代方案——例如广告牌技术——被应用在这种情况下。但是实事求是的说,在这种情境下广告牌技术的实现效果并不好。&/p&&p&那么有没有可能让我们使用很少的开销就渲染出大规模的动画角色呢?&/p&&p&其实我们只需要回过头看看造成开销很大的原因,解决方案已经藏在问题之中了。&/p&&p&首先,主要瓶颈之一是角色动画的处理都集中在CPU端。因此一个简单的想法就是我们能否将这部分的开销转移到GPU上呢?因为GPU的运算能力可是它的强项。&/p&&p&其次,瓶颈之二是CPU和GPU之间的Draw Call问题,如果利用批处理(包括Static Batching和Dynamic Batching)或是从Unity5.4之后引入的GPU Instancing就可以解决这个问题。但是,不幸的是这两种技术都不支持动画角色的SkinnedMeshRender。&/p&&p&那么解决方案就呼之欲出了,那就是将动画相关的内容从CPU转移到GPU,同时由于CPU不需要再处理动画的逻辑了,因此CPU不仅省去了这部分的开销而且SkinnedMeshRender也可以替换成一般的Mesh Render,我们就可以很开心的使用GPU Instancing来减少Draw Call了。&/p&&h2&0x02 Vertex Shader和AnimMap&/h2&&p&写过shader的小伙伴可能很清楚,我们可以很方便的在vs中改变网格的顶点坐标。因此,一些简单的动画效果往往可以在vs中实现。例如飘扬的旗帜或者是波浪等等。&/p&&img src=&/v2-560b1bf6db389e410fcbba0_b.jpg& data-rawwidth=&896& data-rawheight=&972& data-thumbnail=&/v2-560b1bf6db389e410fcbba0_b.jpg& class=&origin_image zh-lightbox-thumb& width=&896& data-original=&/v2-560b1bf6db389e410fcbba0_r.gif&&&p&&br&&/p&&p&(来源于bing搜索)&/p&&p&那么我们能否利用vs设置顶点坐标的方式来展现我们的角色动画呢?&/p&&img src=&/v2-f9c2f729cb110f490a51f019c4c4a14c_b.jpg& data-rawwidth=&663& data-rawheight=&490& data-thumbnail=&/v2-f9c2f729cb110f490a51f019c4c4a14c_b.jpg& class=&origin_image zh-lightbox-thumb& width=&663& data-original=&/v2-f9c2f729cb110f490a51f019c4c4a14c_r.gif&&&p&&br&&/p&&p&答案当然是可行。只不过和飘扬的旗帜那种简单的效果不同,这次我们不仅仅利用几个简单的vs的属性来实现动画效果,而是将角色的动画信息烘焙成一张贴图供vs使用。&/p&&p&简单来说,我们按照固定的频率对角色动画取样并记录取样点时刻角色网格上各个顶点的位置信息,并利用贴图的纹素的颜色属性(Color(float r, float g, float b, float a))保存对应顶点的位置(Vector3(float x, float y, float z))。当然利用颜色属性保存顶点的位置信息时需要考虑到一个小问题,在下文我会再说。&/p&&p&这样该贴图就记录了整个动画时间内角色网格顶点在各个取样点时刻的位置,这个贴图我把它称为AnimMap。&/p&&p&一个AnimMap的结构就是下图这样的:&/p&&img src=&/v2-fd767d1ce6_b.png& data-rawwidth=&500& data-rawheight=&425& class=&origin_image zh-lightbox-thumb& width=&500& data-original=&/v2-fd767d1ce6_r.png&&&p&&br&&/p&&p&在实际工程中,AnimMap是这个样子的。水平方向记录网格各个顶点的位置,垂直方向是时间信息。&/p&&img src=&/v2-2948dddcf8c7df282ad6dff96c8a205a_b.png& data-rawwidth=&503& data-rawheight=&410& class=&origin_image zh-lightbox-thumb& width=&503& data-original=&/v2-2948dddcf8c7df282ad6dff96c8a205a_r.png&&&img src=&/v2-55ffb62ee2ebafb493aba_b.jpg& data-rawwidth=&926& data-rawheight=&596& data-thumbnail=&/v2-55ffb62ee2ebafb493aba_b.jpg& class=&origin_image zh-lightbox-thumb& width=&926& data-original=&/v2-55ffb62ee2ebafb493aba_r.gif&&&p&&br&&/p&&p&上图是将角色的Animator或Animation去掉,将SkinnedMeshRender更换为一般的Mesh Render,只使用AnimMap利用vs来随时间修改顶点坐标实现的动画效果。&/p&&p&到这里我们就完成了将动画效果的实现从CPU转移到GPU运算的目的,可以看到在CPU的开销统计中已经没有了动画相关的内容。但是在渲染的统计中,Draw Call并没有减少,此时渲染8个角色的场景内仍然有10个Draw Call的开销。因此下一步我们就来利用GPU Instancing技术减少Draw Call。&/p&&h2&0x03 效果不错的GPU Instancing&/h2&&p&除了使用批处理,提高图形性能的另一个好办法是使用GPU Instancing(批处理可以合并不同的mesh,而GPU Instancing主要是针对同一个mesh来的)。&/p&&p&GPU Instancing的最大优势是可以减少内存使用和CPU开销。当使用GPU Instancing时,不需要打开批处理,GPU Instancing的目的是一个网格可以与一系列附加参数一起被推送到GPU。要利用GPU Instancing,则必须使用相同的材质,并传递额外的参数到着色器,如颜色,浮点数等。&/p&&p&不过GPU Instancing是不支持SkinnedMeshRender的,也就是正常情况下我们带动画的角色是无法使用GPU Instancing来减少Draw Call的,所以我们必须先完成上一小节的目标,将动画逻辑从CPU转移到GPU后就可以只使用Mesh Render而放弃SkinnedMeshRender了。&/p&&img src=&/v2-369d9f9a408bfcd11505_b.png& data-rawwidth=&403& data-rawheight=&256& class=&content_image& width=&403&&&p&&br&&/p&&p&很多build-in的shader默认是有开启GPU Instancing的选项的,但是我们利用AnimMap实现角色动画效果的shader显然不是build-in,因此需要我们自己开启GPU Instancing的功能。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&#pragma multi_compile_instancing//告诉Unity生成一个开启instancing功能的shader variant
struct appdata
float2 uv : TEXCOORD0;
UNITY_VERTEX_INPUT_INSTANCE_ID//用来给该顶点定义一个instance ID
v2f vert(appdata v, uint vid : SV_VertexID)
UNITY_SETUP_INSTANCE_ID(v);//让shader的方法可以访问到该instance ID
&/code&&/pre&&/div&&p&使用GPU Instancing之后,我们渲染10,000个士兵的Draw Call就从10,000左右降低到20上下了。&/p&&img src=&/v2-b_b.png& data-rawwidth=&1175& data-rawheight=&631& class=&origin_image zh-lightbox-thumb& width=&1175& data-original=&/v2-b_r.png&&&p&&br&&/p&&p&当然,关于GPU Instancing的更多内容各位可以在文末的参考链接中找到。&/p&&h2&0x04 颜色精度和顶点坐标&/h2&&p&还记得之前我说过在利用贴图的纹素的颜色属性保存对应顶点的位置时需要考虑到的一个小问题吗?&/p&&p&是的,那就是颜色的精度问题。&/p&&p&由于现在rgb分别代表了坐标的x、y、z,因此rgb的精度就要好好考虑了。例如rgba32,每个通道只有8位,也就是某一个方向上的位置只有256种可能性,这对位置来说是一个不好的限制。&/p&&p&那么有没有解决方案呢?&/p&&p&&br&&/p&&p&当然还是有的。既然这是一个和颜色的精度相关的问题,那么最简单的方案就是增加精度。例如在写本文的时我的Demo就是采用的这种方式,我使用了RGBAHalf这种纹理格式,而它的精度是每个通道16bit。当然,移动平台上渲染大量角色的需求往往对动画的精确程度的要求没有那么高,因此8bit的精度问题应该也不大。&/p&&p&完整的项目可以到这里到这里下载:&/p&&p&&a href=&/?target=https%3A///chenjd/Render-Crowd-Of-Animated-Characters& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&chenjd/Render-Crowd-Of-Animated-Characters&i class=&icon-external&&&/i&&/a&&/p&&h2&ref:&/h2&&p&【1】&a href=&/?target=https%3A///Manual/GPUInstancing.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Unity - Manual: GPU instancing&i class=&icon-external&&&/i&&/a&&/p&&p&【2】&a href=&/?target=http%3A///blogs/TequilaWorks/347/How_to_take_advantage_of_textures_in_the_vertex_shader.php%29%25E3%%25E3%5BGPU& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&How to take advantage of textures in the vertex shader&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&/?target=http%3A///blogs/TequilaWorks/347/How_to_take_advantage_of_textures_in_the_vertex_shader.php%29%25E3%%25E3%5BGPU& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&【3】&i class=&icon-external&&&/i&&/a&&u&&a href=&/?target=https%3A///gpugems/GPUGems3/gpugems3_ch02.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&GPU Gems&i class=&icon-external&&&/i&&/a&&/u&&/p&&p&【4】题图来自《全面战争:阿提拉》&/p&&p&各位如果觉得有趣的话,欢迎点个赞。&/p&&p&-EOF-&/p&&p&最后打个广告,欢迎支持我的书&a href=&/?target=https%3A///%25E5%259B%25BE%25E4%25B9%25A6/dp/B01LWUI34H/ref%3Dsr_1_12%3Fs%3Dbooks%26ie%3DUTF8%26qid%3D%26sr%3D1-12%26keywords%3Dunity& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Unity 3D脚本编程》&i class=&icon-external&&&/i&&/a&&/p&&p&&br&&/p&&img src=&/v2-aec4df4f86ae6a51ca6013e7deb5a9bc_b.jpg& data-rawwidth=&522& data-rawheight=&668& class=&origin_image zh-lightbox-thumb& width=&522& data-original=&/v2-aec4df4f86ae6a51ca6013e7deb5a9bc_r.jpg&&&p&&br&&/p&&p&欢迎大家关注我的公众号慕容的游戏编程:chenjd01&/p&&img src=&/v2-0c05b713cc4d73a5f79459eaf472c771_b.png& data-rawwidth=&400& data-rawheight=&400& class=&content_image& width=&400&&&p&&/p&
0x00 前言我想很多开发游戏的小伙伴都希望自己的场景内能渲染越多物体越好,甚至是能同时渲染成千上万个有自己动作的游戏角色就更好了。但不幸的是,渲染和管理大量的游戏对象是以牺牲CPU和GPU性能为代价的,因为有太多Draw Call的问题,如果游戏对象有动画…
之前在公司内做的培训计划中,基础内容大概有以下这些:&br&&br&三维几何学基础:&br&&ol&&li&三维坐标系统&br&&/li&&li&点与矢量&br&&/li&&li&矩阵与几何变换&br&&/li&&li&四元数与三维旋转&br&&/li&&/ol&&br&实时渲染管道:&br&&ol&&li&应用阶段(场景管理、可见性剔除、分组排序、提交图元)&br&&/li&&li&几何阶段(顶点着色、图元组装、面向剔除、三角形裁剪、透视除法、视区变换)&br&&/li&&li&光栅化阶段(扫瞄转换、scissor/stencil/alpha 测试、alpha 混合)&br&&/li&&/ol&&br&游戏中的光照与阴影:&br&&ol&&li&实时光照分类(正向渲染、延迟渲染、Tile 正向/延迟渲染)&/li&&li&局部光照中的光源(环境光、方向光、点光、聚光、cookie)&br&&/li&&li&阴影(平面阴影、阴影体积、阴影贴图、PCF、VSM、CSM)&br&&/li&&li&全局光照(光照贴图、幅照度环境贴图、球谐函数)&br&&/li&&/ol&&br&材质着色原理与实践:&br&&ol&&li&材质反射模型(渲染方程、BRDF、Lambertian、Phong、Blinn-Phong)&br&&/li&&li&材质着色器编程(环境光、环境遮蔽、发光物体、贴图采样、环境贴图、法线贴图、轮廓光、纹理坐标动画)&br&&/li&&li&特殊着色器(卡通渲染、Kajiya-Kay、??)&br&&/li&&/ol&&br&由浅入深可先看[1],然后[2]。数学方面可参考[3]。&br&&br&[1] 《游戏引擎架构》,叶劲峰译,电子工业出版社,2014&br&[2] Akenine-M?ller, Tomas, Eric Haines, and Naty Hoffman. Real-time rendering Third Edition, CRC Press, 2008.&br&[3] Lengyel, Eric. Mathematics for 3D game programming and computer graphics. Cengage Learning, 2012.
之前在公司内做的培训计划中,基础内容大概有以下这些: 三维几何学基础: 三维坐标系统 点与矢量 矩阵与几何变换 四元数与三维旋转 实时渲染管道: 应用阶段(场景管理、可见性剔除、分组排序、提交图元) 几何阶段(顶点着色、图元组装、面向剔除、三角形…
守望先锋应该算是暴雪一次自我突破,第一次同步登录本时代主流主机平台,第一次使用和业内接轨的3A游戏美术生产流程。所以我尝试从3A游戏的美术制作流程上解读一下守望先锋的美术风格,并分析此类风格的游戏是如何制作出来的,以期起到一些抛砖引玉的作用。&br&&br&&br&&b&先看美术风格&/b&&br&按欧美大厂的惯例,通常一款3A级作品进入正式开发之前,会在预研阶段先确定一个风格指南。他们通常称为Art Bible,这个风格指南会概述这个项目中美术需要遵守的一切规则,以保证项目风格的统一,通常由美术总监和资深概念设计师共同敲定。&br&&br&这是死亡空间的Art Bible,从目录中可以看到里面包含的内容。详细介绍了项目的配色,参考元素,光照,环境,角色,武器,特效,UI等设计规范。&br&&img src=&/c3e48c9fb534aa4b3747091_b.png& data-rawwidth=&716& data-rawheight=&841& class=&origin_image zh-lightbox-thumb& width=&716& data-original=&/c3e48c9fb534aa4b3747091_r.png&&&img src=&/2e9292cdb26b8d7e5c7a84e40dfc673f_b.png& data-rawwidth=&663& data-rawheight=&836& class=&origin_image zh-lightbox-thumb& width=&663& data-original=&/2e9292cdb26b8d7e5c7a84e40dfc673f_r.png&&以下图为例,图中用一个标尺界定了死亡空间中哥特元素的应用程度。&br&&img src=&/46dbed692f1be_b.png& data-rawwidth=&594& data-rawheight=&492& class=&origin_image zh-lightbox-thumb& width=&594& data-original=&/46dbed692f1be_r.png&&&br&以此范例来推敲守望先锋的Art Bible,首先应该确定的是整个项目在写实与卡通之间的尺度。&br&我找了几个游戏作为参照,以1为完全写实,10为完全卡通为标准估算,守望先锋的卡通化程度为6到7之间。&br&&img src=&/528d5cfc7d9db0dcf942db_b.jpg& data-rawwidth=&1738& data-rawheight=&380& class=&origin_image zh-lightbox-thumb& width=&1738& data-original=&/528d5cfc7d9db0dcf942db_r.jpg&&卡通化的方向有很多种,一句卡通化并不能精确说明守望先锋风格表现。像波斯王子4和双重国度这种也是卡通化的作品。但是和守望先锋相比他们之间的风格差异还是很大的。&br&波斯王子4&br&&img src=&/6d42cd39b80aa9befb74d2b8_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/6d42cd39b80aa9befb74d2b8_r.jpg&&双重国度&br&&img src=&/1d5bcaf16a1_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/1d5bcaf16a1_r.jpg&&守望先锋&br&&img src=&/aa42a14a3b439ffccdfa1_b.jpg& data-rawwidth=&1920& data-rawheight=&1200& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/aa42a14a3b439ffccdfa1_r.jpg&&这两种卡通风格的主要区别在于:波斯王子4和双重国度侧重点在于卡通渲染,用手绘贴图来表现材质,渲染上通过对shader(着色器)和光照的处理,让整体画面呈现出类似于2D动画的赛璐璐风格效果&br&而守望先锋更接近于由皮克斯和迪斯尼所引领的3D卡通动画风格。材质和光照都尽量真实,但是弱化物体表面纹理和细节,对造型进行适度夸张。是一种重造型,轻细节的扁平化卡通风格。&br&&img src=&/478c18e6b46d89e66f71ded38256be07_b.jpg& data-rawwidth=&1889& data-rawheight=&917& class=&origin_image zh-lightbox-thumb& width=&1889& data-original=&/478c18e6b46d89e66f71ded38256be07_r.jpg&&守望先锋的风格和皮克斯动画更接近。他们在进行美术设计的时候一定没有少参考动画界同行作品。&br&&img src=&/dddc3f447a5f8901dda7b_b.jpg& data-rawwidth=&1878& data-rawheight=&1000& class=&origin_image zh-lightbox-thumb& width=&1878& data-original=&/dddc3f447a5f8901dda7b_r.jpg&&&img src=&/ea606ba82df6fe89e2e2a56c9d7e3f3e_b.jpg& data-rawwidth=&990& data-rawheight=&556& class=&origin_image zh-lightbox-thumb& width=&990& data-original=&/ea606ba82df6fe89e2e2a56c9d7e3f3e_r.jpg&&&br&&b&再看设计思路&/b&&br&确定好大体方向,那么如何保证整个项目的风格都统一在一个框架内呢?游戏中有那么多角色和道具,还有建筑,环境等等数不清的美术资源,参与制作的美术人员水平肯定也参差不齐,必须确定他们设计和制作出来的效果都像出自一人之手游戏整体效果才和谐。&br&&br&在3A游戏的Art Bible中,会详细规定哪些是必须出现的,哪些是不能出现的。画定好范围,这样会缩小犯错空间。下图同样是死亡空间的范例,图中就列出了例如铆钉焊缝这种不符合游戏世界观的东西,因此是禁止出现的。&br&&img src=&/abb9b9c564e9f404f0afbc8f02810e42_b.png& data-rawwidth=&668& data-rawheight=&594& class=&origin_image zh-lightbox-thumb& width=&668& data-original=&/abb9b9c564e9f404f0afbc8f02810e42_r.png&&&br&从守望先锋的角色概念设计中可以看出以下几点原则:&br&1.角色身上的颜色一般在5种以上,范围为通常是5到8种之间。&br&2.会有大面积的纯色作为角色主体色。点缀小面积的补色以平衡整体观感。&br&3.脏旧和污渍等日常生活中常见的细节被去掉了。&br&4.细节纹理被弱化了。&br&5,.毛发等细节部位做为一个整体处理,强调块面感。对肩膀、手部、臀部(这是重点)、腿部造型做了夸张处理。以突出角色剪影效果。&br&&img src=&/cdcd5d8ff92e9cc4d69cb_b.jpg& data-rawwidth=&2560& data-rawheight=&1600& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&/cdcd5d8ff92e9cc4d69cb_r.jpg&&&img src=&/800afae957675_b.jpg& data-rawwidth=&2560& data-rawheight=&1600& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&/800afae957675_r.jpg&&&img src=&/4839ca4cbcdbf58e_b.jpg& data-rawwidth=&2560& data-rawheight=&1600& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&/4839ca4cbcdbf58e_r.jpg&&对比秘境探险4的角色(这是官方译名),能更明显看出守望先锋做的取舍。在写实游戏中,环境和战斗对角色造成的影响都有表现。毛发,皮肤,皮革,布料各种材质之间效果通常都还原得非常到位。&br&&img src=&/adafd20ed846bbdfb71249_b.jpg& data-rawwidth=&1920& data-rawheight=&905& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/adafd20ed846bbdfb71249_r.jpg&&&img src=&/cb69cf52ce3d64d3b71cb813b4a98a5d_b.jpg& data-rawwidth=&1913& data-rawheight=&1001& class=&origin_image zh-lightbox-thumb& width=&1913& data-original=&/cb69cf52ce3d64d3b71cb813b4a98a5d_r.jpg&&&img src=&/fae310b1f6609dc50afb031_b.jpg& data-rawwidth=&1920& data-rawheight=&2025& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/fae310b1f6609dc50afb031_r.jpg&&&br&守望先锋在场景设计上的思路也和角色一致。确立每张地图的主色调,大面积使用高纯度颜色,去掉材质上的纹理细节,只保留大块结构。&br&&img src=&/ede2d95a253b2fc2b5c935fa87f54f3d_b.jpg& data-rawwidth=&1600& data-rawheight=&968& class=&origin_image zh-lightbox-thumb& width=&1600& data-original=&/ede2d95a253b2fc2b5c935fa87f54f3d_r.jpg&&&img src=&/2c85ccc09f467e44769be43_b.jpg& data-rawwidth=&1500& data-rawheight=&909& class=&origin_image zh-lightbox-thumb& width=&1500& data-original=&/2c85ccc09f467e44769be43_r.jpg&&&img src=&/f0beeff1c71c1ffbed1b_b.jpg& data-rawwidth=&1200& data-rawheight=&792& class=&origin_image zh-lightbox-thumb& width=&1200& data-original=&/f0beeff1c71c1ffbed1b_r.jpg&&对比写实表现的游戏就可以看出,写实游戏的概念设计上会体现出时间,气候,大自然对物体产生影响,并有大量细节。&br&&img src=&/fee754f10d712f89c30d276d999bfdb0_b.jpg& data-rawwidth=&1920& data-rawheight=&963& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/fee754f10d712f89c30d276d999bfdb0_r.jpg&&&br&&b&然后分析制作流程&/b&&br&因为省略了很多细节,守望先锋的模型和贴图在制作上相比写实游戏要省事许多。当然步骤依然是高精度模型——低精度模型——烘焙法线贴图——纹理贴图的流程,这点和其他游戏流程一样。&br&&img src=&/ccf6aa70fbeb8dee64f6_b.jpg& data-rawwidth=&2560& data-rawheight=&1600& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&/ccf6aa70fbeb8dee64f6_r.jpg&&&br&值得一提的是材质部分,守望先锋的制作是暴雪第一次引入PBR(基于物理渲染)流程,也可以说是暴雪第一次采用主流3A游戏的制作流程。在此之前的项目,无论是魔兽世界,星际争霸2,暗黑3美术采用的生产管线都是略微落后于欧美业内其他大厂的。&br&简单的说,PBR流程改善了物体的着色方式,将金属质地与粗糙度整合到材质属性中。美术只用选择对应的参数就可以呈现出正确的材质效果。而在此之前,物体的高光。反射等效果都是由美术绘制控制的,主观因素占绝大部分,效果正确与否完全看美术水平,难以量化。&br&&br&对比从星际争霸2和守望先锋的角色就可以看出两个流程的区别。刀锋女王身上的光泽由美术绘制的高光贴图控制,脸部和身体衣服的光泽效果并不能得到很好的区分,无法彻底呈现出材质本身的应有质感。&br&&img src=&/8835dbbcec0b3c0512095fde_b.jpg& data-rawwidth=&1680& data-rawheight=&1050& class=&origin_image zh-lightbox-thumb& width=&1680& data-original=&/8835dbbcec0b3c0512095fde_r.jpg&&而黑百合衣服上的光泽由反射产生,很好的呈现出亚光材质的效果。&br&&img src=&/533a80df23af1c50a7c977_b.jpg& data-rawwidth=&2560& data-rawheight=&1300& class=&origin_image zh-lightbox-thumb& width=&2560& data-original=&/533a80df23af1c50a7c977_r.jpg&&场景制作也是同样的标准。可以看出金属拱顶和石头墙面明显的质感区别。不过在场景材质类型上守望先锋并未做细致的划分,所以植物、泥土、石头、木材之间的区别并不是很明显。&br&&img src=&/2e4ba5d7d8879aba20bdb1_b.jpg& data-rawwidth=&1920& data-rawheight=&1200& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/2e4ba5d7d8879aba20bdb1_r.jpg&&在需要使用重复纹理的大面积区域,融合了多张贴图以破除重复感。&br&&img src=&/5ef2b85cebf5ef_b.jpg& data-rawwidth=&1764& data-rawheight=&986& class=&origin_image zh-lightbox-thumb& width=&1764& data-original=&/5ef2b85cebf5ef_r.jpg&&&img src=&/bc1a95e399aa781fee7b173ae61f2e70_b.jpg& data-rawwidth=&1458& data-rawheight=&911& class=&origin_image zh-lightbox-thumb& width=&1458& data-original=&/bc1a95e399aa781fee7b173ae61f2e70_r.jpg&&&br&对比秘境探险4的游戏画面可以看到更加细腻的材质表现是什么样子的。植物的叶片在光照下呈现出漂亮的透光效果(次表面反射材质),在没有直接光照的情况下,坚硬的石头也对环境光反射出正确的光泽。&br&&img src=&/b989f75af4c9ff36c77c3b767ca87798_b.jpg& data-rawwidth=&1920& data-rawheight=&1144& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/b989f75af4c9ff36c77c3b767ca87798_r.jpg&&&img src=&/c310fbf08_b.jpg& data-rawwidth=&1920& data-rawheight=&656& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/c310fbf08_r.jpg&&&img src=&/b6b21d88d14f6f72da996_b.jpg& data-rawwidth=&1920& data-rawheight=&1152& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/b6b21d88d14f6f72da996_r.jpg&&有人可能认为这种差异是在美术风格取舍造成的,对此可以参考风格一脉相承的守望先锋动画短片。动画中的植被也呈现出同样通透的光泽,地面也反射了正确的环境细节。游戏中对此类细节刻画有所欠缺,可能引擎在这方面有些短板。&br&&img src=&/73d3db9e467fc80c7eaf0a943db70a07_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/73d3db9e467fc80c7eaf0a943db70a07_r.jpg&&&img src=&/5fcb887ad979a7b9c3d026_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/5fcb887ad979a7b9c3d026_r.jpg&&&b&光照&/b&&br&守望先锋的画面效果主要得益于它的光照表现。和写实游戏相比较,游戏刻意提高了光照的强度和饱和度,对阴影的颜色也做了提高纯度的调整,使得游戏画面效果整体非常明快,另外刻意提高了暗部光照的光线反弹强度来模拟全局光照效果,让暗部效果也十分通透。&br&&img src=&/47c215ac1c8f6feb37aac2d7ce3234fa_b.jpg& data-rawwidth=&1920& data-rawheight=&1172& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/47c215ac1c8f6feb37aac2d7ce3234fa_r.jpg&&所谓全局光照,简单来说就是模拟光线在环境中的反射一种技术。在自然环境中,光从太阳照射到地面,不是简单的只照亮物体表面,而是会在物体之间相互反射,从而影响整个环境。通常直接照亮物体的光线被称为直接光,发生反射后照亮物体的光线被称为间接光,二者综合为全局光照。这是游戏制作领域的一个基本概念,就连拍电视剧的都知道全局光照对游戏画面提升的作用(微微一笑很倾城)。&br&&img src=&/554fd0d8ff3a620b3e3c_b.jpg& class=&content_image&&&img src=&/8d6e7fdb8b_b.jpg& class=&content_image&&&img src=&/ebf026a839418_b.jpg& class=&content_image&&&img src=&/c38af61df8cbfbd2d709d5_b.jpg& class=&content_image&&当然了,剧中的台词是一句正确的废话。关于全局光对游戏画面提升可以看下图。下面是量子破碎的技术展示,图片从左到右依次为:直接光照、全局光照,间接光照、实时间接光。应用全局光照技术的游戏场景从亮部到暗部有丰富的渐变过度,场景内空间层次效果更加明显。&br&&img src=&/853e2a1eced1e40ccd71e2fc2a5c7bd4_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/853e2a1eced1e40ccd71e2fc2a5c7bd4_r.jpg&&光照效果对游戏画面的影响巨大,光照漂亮的游戏,即便使用非常简单的贴图和材质,也能出现赏心悦目的效果。比如镜之边缘。可以看出守望先锋的光照风格和镜之边缘是有几分类似的。&br&&img src=&/72eaa9fa9b793fa83a4d6d_b.jpg& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&/72eaa9fa9b793fa83a4d6d_r.jpg&&可能有人会对暴雪爸爸和业界毒瘤EA游戏风格居然有相似之处感到不爽,不过先别激动,风格相似其实也不奇怪,因为这两个游戏的灯光师是同一个人。除了镜之边缘和守望先锋,他参与的项目还有战地3,极品飞车,星战前线。&br&&img src=&/d6fde0ec616a8dd05c6ba_b.png& data-rawwidth=&1366& data-rawheight=&656& class=&origin_image zh-lightbox-thumb& width=&1366& data-original=&/d6fde0ec616a8dd05c6ba_r.png&&守望先锋刻意加强了对暗部效果的表现,下图可以看到游戏中的地面部分阴影为紫色,而墙上的阴影受地面光线反弹的影响,则呈现为红色。&br&&img src=&/6b0f5ccdca_b.jpg& data-rawwidth=&1166& data-rawheight=&727& class=&origin_image zh-lightbox-thumb& width=&1166& data-original=&/6b0f5ccdca_r.jpg&&对比一下没有模拟全局光照的游戏画面(天涯明月刀),游戏的暗部仅靠一个整体环境光照亮,因此画面内物体暗部颜色和阴影颜色基本混在一起。显得比较单调。&br&&img src=&/ebcaba258d0_b.png& data-rawwidth=&1920& data-rawheight=&1014& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/ebcaba258d0_r.png&&当然我不是在黑腾讯,大名鼎鼎的巫师3也有这个毛病,大场景的动态光照本来就不好搞,有很多局限性。目前也就crytek的cryengine引擎有这个实力可以一战。&br&&img src=&/c5cbf8e6fce4beb65ef15ef5_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/c5cbf8e6fce4beb65ef15ef5_r.jpg&&注意我一直在说守望先锋是模拟全局光,因为守望先锋里并没有用到全局光照技术,游戏里的光照效果是靠美术手动调整实现的。守望先锋场景里并没有昼夜变化,光源环境是固定的,所以很多效果可以用手动补光的方式去实现。另外我不能确定守望先锋有没有使用光照烘焙,我个人倾向于没有。&br&对比一下使用了全局光照技术的游戏,可以看出在细节层次上,尤其的暗部场景和室内,在光影的丰富程度上有明显差别。比如间接光照产生的模糊投影,光线充足的地方反射会更强烈等效果,在守望先锋里是看不到的。用比较通俗的话来讲,就是更真实的光影会显得更柔和一些。当然这种差异对一般玩家来说感受并不明显。&img src=&/f3d92ceba73da69bc5172_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/f3d92ceba73da69bc5172_r.jpg&&&img src=&/665fc072bc271bf746cbb_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/665fc072bc271bf746cbb_r.jpg&&&img src=&/c9fd889086fffa3ce946eb5d2ac33cba_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/c9fd889086fffa3ce946eb5d2ac33cba_r.jpg&&我知道又有人还会认为这种差异是在美术风格取舍造成的,对此可以接着参考风格一脉相承的守望先锋动画短片。可以理解为并不是美术团队不想把游戏的光照做得更加生动,而是引擎瓶颈或者为了照顾低配置玩家做出的妥协。&br&&img src=&/18f7c7df322be_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/18f7c7df322be_r.jpg&&&b&特效和UI&/b&&br&之前说过守望先锋是典型的扁平化风格,这种风格的特点是注重造型而省略细节,可以让美术把精力放在设计上而不是生产环节中去。扁平化UI是这几年游戏UI的主流,而早期游戏UI通常以制作精细的拟物化风格为主。究其原因,在早期游戏画面还很粗糙的年代,绘制细腻而又不怎么消耗硬件渲染资源的拟物化UI能让一个游戏看来显得制作更精良一些。而随着图形技术的提升,游戏画面越来越精致,简单的UI能让玩家更多的把精力放在游戏内容上,太复杂的设计反而会产生干扰,UI设计也逐渐剥离美化装饰的需求而回归到本身的功能属性上。&br&&br&早期荣誉勋章的UI设计,可以看出子弹数量,罗盘,游戏道具的图标都比较写实。&br&&img src=&/f9e76f7bbbceeae5de374bd_b.jpg& data-rawwidth=&1024& data-rawheight=&768& class=&origin_image zh-lightbox-thumb& width=&1024& data-original=&/f9e76f7bbbceeae5de374bd_r.jpg&&&br&守望先锋的UI设计和目前主流射击游戏一致,用一目了然的简单图形概括自身的功能。主色调为白色,提醒色为黄色,警告色为红色,另有少量青色作为能量槽等功能的补充说明颜色。游戏的UI颜色使用被规范在此框架内。&br&&img src=&/b515bd7ea0e_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/b515bd7ea0e_r.jpg&&随着VR的兴起,未来UI的发展趋势应该是UI空间化。也就是游戏UI和游戏环境融为一体。死亡空间系列是此类UI设计的代表作。可以看到子弹数量和血槽的显示是直接整合在枪和角色身上的。&br&&img src=&/563e472c6fba58d1139da_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/563e472c6fba58d1139da_r.jpg&&在特效处理上,守望先锋并没有选择和迪斯尼动画类似的写实卡通风格,而是选择了类似2D动画的赛璐璐风格,以色块和线条来概括游戏里的爆炸,火光烟雾等效果。这也是它和其他类似风格游戏的最大区别。这样的搭配方式,也让游戏整体扁平化的风格趋势更加明显。&br&&img src=&/fd017ebb14ab9f96d27cb22ef424bd31_b.png& data-rawwidth=&1272& data-rawheight=&798& class=&origin_image zh-lightbox-thumb& width=&1272& data-original=&/fd017ebb14ab9f96d27cb22ef424bd31_r.png&&守望先锋的特效风格和使用卡通渲染风格的游戏比较接近,图中游戏为罪恶装备。&img src=&/96fb03c97aef460cf8ed85a76d6a152c_b.jpg& data-rawwidth=&1200& data-rawheight=&675& class=&origin_image zh-lightbox-thumb& width=&1200& data-original=&/96fb03c97aef460cf8ed85a76d6a152c_r.jpg&&而风格类似的军团要塞的特效依然是写实纹理&br&&img src=&/dbff9f4a6cb_b.jpg& data-rawwidth=&1280& data-rawheight=&690& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/dbff9f4a6cb_r.jpg&&如果要客观评价一下守望先锋的美术水平,从游戏效果来看,可以说是优秀,算不上顶级。单独把游戏里的任何一个模块拿出来比较,不管是设计,还是模型、贴图、材质、光照等,在业内都有比它更好的。但游戏是一个综合工程,任何一个效果的实现都是美术和程序共同努力的结果,另外还要考虑到游戏定位,市场受众,玩家配置等许多客观因素。从游戏整体效果来看,明快的美术风格和爽快的游戏节奏结合得相得益彰,给玩家非常愉悦的体验,从这点来说,守望先锋做到了顶级。毕竟把所有环节都做到最好并不等于就是最合适的。如何站在游戏整体体验的高度去把控项目的取舍平衡,才是所有游戏开发人员需要学习的。
守望先锋应该算是暴雪一次自我突破,第一次同步登录本时代主流主机平台,第一次使用和业内接轨的3A游戏美术生产流程。所以我尝试从3A游戏的美术制作流程上解读一下守望先锋的美术风格,并分析此类风格的游戏是如何制作出来的,以期起到一些抛砖引玉的作用。 …
&img src=&/v2-f748fda06d505eae959bf6_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/v2-f748fda06d505eae959bf6_r.jpg&&《塞尔达传说:荒野之息》的制作人青沼英二在介绍荒野之息的时候,表示他想让这个游戏看起来具有&b&日本动画片(Anime)的风格&/b&。同时,他又希望对于荒野的描绘有&b&外光派(Plein-Air)的感觉&/b&。《塞尔达传说:荒野之息》把这两点都做到了,而且也印证了目前游戏美术风格的发展风向。&img src=&/v2-bd8947afed489b847bf3dc_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/v2-bd8947afed489b847bf3dc_r.jpg&&&p&&b&卡通渲染&/b&&/p&&p&青沼英二想实现的日本动画片风格是什么样的呢?就是&b&物体亮面暗面分明&/b&的赛璐璐(Cel-Shading)风格。做动画时,动画师往往只是把亮面和暗面概括出来,这样比涂抹中间渐变色省了很多时间,而且也能够展现角色的立体感。比如下图中人物身上没有渐变,男孩的衣服要么是亮面浅绿色,要么是暗面深绿色。这种动画风格要如何展现在游戏中呢?&img src=&/v2-d6bd2e70f3d16a92de4c_b.jpg& data-rawwidth=&1440& data-rawheight=&900& class=&origin_image zh-lightbox-thumb& width=&1440& data-original=&/v2-d6bd2e70f3d16a92de4c_r.jpg&&当今大多数游戏都采用了物理渲染(Physical Rendering)的方式来表现写实感。比如我现在把一个木偶通过物理渲染的方式展现出来:&br&&/p&&p&&img src=&/v2-4bfad3cedd6bff5a5a78c_b.png& data-rawwidth=&800& data-rawheight=&600& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&/v2-4bfad3cedd6bff5a5a78c_r.png&&可以看到,物理渲染准确的计算每个面的角度和他们的漫反射和高光,形成柔和的渐变。无论是缝隙之间的环境光遮蔽,还是肩膀与躯干连接处明显的全局光,都力图在游戏中还原最真实的世界。&/p&&p&然而这和我们想要的简洁,清晰的日本动画风相差甚远。为了在游戏中完成赛璐璐风格,我们需要使用卡通渲染(Toon Rendering):&/p&&p&&img src=&/v2-3c0d24ac40_b.png& data-rawwidth=&800& data-rawheight=&600& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&/v2-3c0d24ac40_r.png&&在这里,同样的一个木偶,我们可以看到使用卡通渲染后,暗面,亮面和高光界限分明,没有含糊的余地。具体做法是在引擎里定义材料(Material)的时候使用Cel材质,定义物体的暗面,亮面和高光分别对应着什么颜色。这就可以有很大的艺术自由,因为你可以定义暗面是紫色的,亮面是黄色的,虽然在现实中不符合光学,但是却别有风格。&/p&&p&我们现在来看一下《塞尔达传说:荒野之息》中人物的表现:&img src=&/v2-ba98fe8e2c1_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/v2-ba98fe8e2c1_r.jpg&&&/p&&br&&p&图中可以看到人物的高光范围很窄,而且衣服上的一些高光都是材质画上去的。而这些都给予了艺术家足够的自由。比如让光的强度达到一定值后才使用高光颜色。比如下图,我就缩小了高光的范围,加大了亮面的范围,更加倾向于游戏中的画面。&/p&&img src=&/v2-8f7af186e7f1cc64380fc1afd38970cf_b.png& data-rawwidth=&898& data-rawheight=&68& class=&origin_image zh-lightbox-thumb& width=&898& data-original=&/v2-8f7af186e7f1cc64380fc1afd38970cf_r.png&&&img src=&/v2-ee1f6bec2b988_b.png& data-rawwidth=&898& data-rawheight=&70& class=&origin_image zh-lightbox-thumb& width=&898& data-original=&/v2-ee1f6bec2b988_r.png&&&p&&img src=&/v2-5b6fb9e59aa43e318e986a34a7ab887a_b.png& data-rawwidth=&800& data-rawheight=&600& class=&origin_image zh-lightbox-thumb& width=&800& data-original=&/v2-5b6fb9e59aa43e318e986a34a7ab887a_r.png&&卡通渲染对比物理渲染有诸多好处,首先就是它的&b&渲染量非常小&/b&,不需要计算全局光和环境光遮蔽,也无需计算复杂的材质反射,大大减轻了硬件负担。在任天堂Switch的小身板里也能畅快游玩。第二就是它&b&不容易过时&/b&。毕竟物理渲染年年革新,写实风格一年比一年强。当时惊艳于GTA4的你已经习惯了GTA5的写实城市,对之前世代的写实游戏嗤之以鼻。而像《Firewatch》这种风格化的作品却永远不会有人吐槽画面差。这次的塞尔达也利用了卡通渲染保证了风格化的感官体验。&/p&&p&&b&外光派&/b&&br&&/p&&br&&p&外光派指的是在户外描绘风景,因为户外的光线变换很快,画家需要迅速抓住景色特征,用笔触和色块高度概括,在光线明显变化前完成作品。&br&&/p&&p&&img src=&/v2-1e4e766ed5bf7fc5ade862c2c0d9dbc3_b.jpg& data-rawwidth=&600& data-rawheight=&346& class=&origin_image zh-lightbox-thumb& width=&600& data-original=&/v2-1e4e766ed5bf7fc5ade862c2c0d9dbc3_r.jpg&&而《塞尔达传说:荒野之息》就试图用“笔触感”,和大色块来展现新的荒野气息:无论是偏蓝绿色的天空和具有手绘材质的云彩,以及夸张的大气透视,都给玩家一种看到水粉画的感觉。这也是制作人青沼英二想要带给观众的感觉。&img src=&/v2-80de6a761ee355f733ae_b.jpg& data-rawwidth=&1280& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1280& data-original=&/v2-80de6a761ee355f733ae_r.jpg&&&/p&&p&&b&特效&/b&&/p&&p&我在&a href=&/question//answer/& class=&internal&&如何评价暴雪游戏《守望先锋》及其场景和美术设计? - 任泽宇的回答 - 知乎&/a&中提到了游戏更加倾向于使用逐帧动画作为特效的趋势。之前的游戏很普遍的使用粒子生成器来用程序生成粒子爆炸特效。但是现在逐帧画出的特效越来越流行。因为它们更加清晰,有打击感,有辨识度。在塞尔达的例子里,这种风格更有日本动画的感觉。&br&&/p&&p&&img src=&/v2-fc4c04d19f5b12a57df649_b.png& data-rawwidth=&1736& data-rawheight=&1246& class=&origin_image zh-lightbox-thumb& width=&1736& data-original=&/v2-fc4c04d19f5b12a57df649_r.png&&如上图,爆炸的烟雾和火焰都是精致的逐帧动画,而非简单的粒子。&/p&&p&&b&总结&/b&&/p&&p&从《塞尔达传说:荒野之息》中可以看到现在游戏美术的一些流行趋势:&/p&&p&&b&1. 高对比度,低多边形的卡通渲染。&/b&&/p&&p&这种风格计算量低,制作成本小,但是富有风格。例子:《The Long Dark》,《The Wild Eight》&/p&&p&&img src=&/v2-ae892abcedd6e9cba388_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/v2-ae892abcedd6e9cba388_r.jpg&&&b&2. 通过艺术化的颜色来展现世界,而非纯粹追求写实。&/b&&/p&&p&真实的世界其实饱和度是偏低的,但现在的游戏开始具有浪漫主义色彩。用色也更加考量整体的观感,以及配色的美感。例子:GTA5(没错),《Firewatch》。&/p&&img src=&/v2-8b1acfd3c66fdc0e72b3_b.jpg& data-rawwidth=&1920& data-rawheight=&1080& class=&origin_image zh-lightbox-thumb& width=&1920& data-original=&/v2-8b1acfd3c66fdc0e72b3_r.jpg&&&p&&b&3. 手绘风格特效&/b&&/p&&p&这个其实每个游戏都有一些,但是现在越来越突出手绘感,对粒子系统的考量也开始发生变化。例子:守望先锋&/p&&p&&img src=&/v2-bcd1faa831e8b48e3170d_b.jpg& data-rawwidth=&640& data-rawheight=&400& class=&origin_image zh-lightbox-thumb& width=&640& data-original=&/v2-bcd1faa831e8b48e3170d_r.jpg&&希望我的文章能对你有所帮助。让我们一起期待《塞尔达传说:荒野之息》。&/p&
《塞尔达传说:荒野之息》的制作人青沼英二在介绍荒野之息的时候,表示他想让这个游戏看起来具有日本动画片(Anime)的风格。同时,他又希望对于荒野的描绘有外光派(Plein-Air)的感觉。《塞尔达传说:荒野之息》把这两点都做到了,而且也印证了目前游戏美…
&img src=&/v2-b7cacf322c7e42e844cad7_b.png& data-rawwidth=&1909& data-rawheight=&844& class=&origin_image zh-lightbox-thumb& width=&1909& data-original=&/v2-b7cacf322c7e42e844cad7_r.png&&&h2&简介&/h2&&p&《塞尔达传说
风之杖》是一款由任天堂开发的任天堂GameCube平台上的动作冒险游戏,一经发布就广受好评,之后任天堂在WiiU上还发布了HD版本。其别具一格的卡通美术风格现如今看来都不算过时,甚至给最近火的一塌糊涂的《塞尔达传说
荒野之息》带来了很大的影响。&/p&&img src=&/v2-4b7c06cc155af5b9ff109e8_b.png& data-rawwidth=&1277& data-rawheight=&670& class=&origin_image zh-lightbox-thumb& width=&1277& data-original=&/v2-4b7c06cc155af5b9ff109e8_r.png&&&img src=&/v2-0e6fdb30a8fc_b.png& data-rawwidth=&1204& data-rawheight=&720& class=&origin_image zh-lightbox-thumb& width=&1204& data-original=&/v2-0e6fdb30a8fc_r.png&&&p&虽说gamebox上的版本马赛克比较重,但是link的表情表现的非常的到位,从简单的眨眼,到各种神情的变化,都特别的到位,比如下面这个他被用木桶投掷到岛上的过场&/p&&img src=&/v2-b4d5169e29bae1b70e2fe60af44c500a_b.png& data-rawwidth=&653& data-rawheight=&308& class=&origin_image zh-lightbox-thumb& width=&653& data-original=&/v2-b4d5169e29bae1b70e2fe60af44c500a_r.png&&&img src=&/v2-2bb1551cfc078b4e44cded1_b.png& data-rawwidth=&626& data-rawheight=&302& class=&origin_image zh-lightbox-thumb& width=&626& data-original=&/v2-2bb1551cfc078b4e44cded1_r.png&&&img src=&/v2-c532e44dc6be51d9e25e0aca_b.png& data-rawwidth=&669& data-rawheight=&327& class=&origin_image zh-lightbox-thumb& width=&669& data-original=&/v2-c532e44dc6be51d9e25e0aca_r.png&&&p&非常带感。&br&&/p&&br&&p&今天要分析的是游戏中的角色渲染和表情系统,并且在Unity中进行实现。&/p&&p&&b&工具&/b&&/p&&p&Unity3D 5.3.5&/p&&p&Maya 2014&/p&&h2&模型处理&/h2&&p&原始的模型可以从&a href=&/?target=https%3A//www./submitter/Mystie/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&这里&i class=&icon-external&&&/i&&/a&下载到。最原始的模型是obj的模型,要放到Unity里的话,首先要将其转化成fbx。&/p&&p&打开Maya,选择导入模型&/p&&img src=&/v2-8b98acd2fefde_b.png& data-rawwidth=&670& data-rawheight=&631& class=&origin_image zh-lightbox-thumb& width=&670& data-original=&/v2-8b98acd2fefde_r.png&&&p&导入之后的mesh是一个完整的mesh,先把它打撒。选中模型,然后
网格-&分离,Mesh就被打散了&/p&&img src=&/v2-845d020bc9c43aa1d38f23af879f0356_b.png& data-rawwidth=&306& data-rawheight=&140& class=&content_image& width=&306&&&br&&p&看下面数,不到3000&/p&&img src=&/v2-607ecdf00c780c9d7a28ca4_b.png& data-rawwidth=&273& data-rawheight=&114& class=&content_image& width=&273&&&br&&p&衣服的贴图尺寸180*96,怎么”挤” 进去的?&/p&&img src=&/v2-76eedf0ccceaf6d30cdcb93558befacc_b.png& data-rawwidth=&726& data-rawheight=&270& class=&origin_image zh-lightbox-thumb& width=&726& data-original=&/v2-76eedf0ccceaf6d30cdcb93558befacc_r.png&&&br&&p&由于衣服大部分的地方都是大块的纯色,不同于常规的展UV的方法,纹理也是一些很简单的颜色,uv就直接被放到对应的色块上。&/p&&p&在看最重要的面部。&/p&&img src=&/v2-d641b1baec1ae2b1e63e1c0dedf52890_b.png& data-rawwidth=&658& data-rawheight=&203& class=&origin_image zh-lightbox-thumb& width=&658& data-original=&/v2-d641b1baec1ae2b1e63e1c0dedf52890_r.png&&&p&嘴巴部分是专门用了一块mesh来处理,这样只要在材质中切换贴图就能够达到换表情的作用。&/p&&p&嘴巴部分由于是切割的mesh,所以在导入的时候生成法线会出问题&/p&&img src=&/v2-f8d76e50684cdd66712c82_b.png& data-rawwidth=&787& data-rawheight=&388& class=&origin_image zh-lightbox-thumb& width=&787& data-original=&/v2-f8d76e50684cdd66712c82_r.png&&&br&&p&嘴巴部分的的法线和面部的法线不是连续的,这样会导致后面处理光照的时候会很奇怪。&/p&&p&处理方法是用Maya的法线工具&/p&&img src=&/v2-3e3f4da7ec46f_b.png& data-rawwidth=&687& data-rawheight=&431& class=&origin_image zh-lightbox-thumb& width=&687& data-original=&/v2-3e3f4da7ec46f_r.png&&&br&&p&会生成一个合并好的mesh,&/p&&img src=&/v2-e7bbe278cc3d0f76ed00ff8b3ea431c0_b.png& data-rawwidth=&658& data-rawheight=&209& class=&origin_image zh-lightbox-thumb& width=&658& data-original=&/v2-e7bbe278cc3d0f76ed00ff8b3ea431c0_r.png&&&br&&p&这下正常了。再看眼睛,眼睛的表现分为三个部分。眉毛,眼白,眼睛。这里的处理方法不是用面部的网格切一块下来了,而是在眼睛出罩一些片mesh&/p&&img src=&/v2-9ceb3ff7a64e59da94c877_b.png& data-rawwidth=&427& data-rawheight=&287& class=&origin_image zh-lightbox-thumb& width=&427& data-original=&/v2-9ceb3ff7a64e59da94c877_r.png&&&p&每一边的眼睛都覆盖了三个mesh片,分别是眉毛,眼白,瞳孔(为了看清楚将它们拉开了一些)。&/p&&p&实际上是往外拉了一点点,防止Z-Fighting&/p&&img src=&/v2-dbc643eae2cb_b.png& data-rawwidth=&737& data-rawheight=&307& class=&origin_image zh-lightbox-thumb& width=&737& data-original=&/v2-dbc643eae2cb_r.png&&&br&&p&接下来可以导出模型了,文件-&导出,选fbx,默认设置。&/p&&br&&h2&角色渲染&/h2&&p&角色渲染的话就是最简单的卡通渲染,根据direction light的方向和法线的角度得到一个shadow值,和纹理的颜色相乘。&/p&&br&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span&&span class=&n&&Shader&/span& &span class=&s&&&Custom/celshading&&/span&
&span class=&p&&{&/span&
&span class=&n&&Properties&/span&
&span class=&p&&{&/span&
&span class=&p&&[&/span&&span class=&n&&NoScaleOffset&/span&&span class=&p&&]&/span& &span class=&n&&_MainTex&/span&&span class=&p&&(&/span&&span class=&s&&&Texture&&/span&&span class=&p&&,&/span& &span class=&mi&&2&/span&&span class=&n&&D&/span&&span class=&p&&)&/span& &span class=&o&&=&/span& &span class=&s&&&white&&/span& &span class=&p&&{}&/span&
&span class=&p&&}&/span&
&span class=&n&&SubShader&/span&
&span class=&p&&{&/span&
&span class=&n&&Pass&/span&
&span class=&p&&{&/span&
&span class=&n&&Tags&/span&&span class=&p&&{&/span& &span class=&s&&&LightMode&&/span& &span class=&o&&=&/span& &span class=&s&&&ForwardBase&&/span& &span class=&p&&}&/span&
&span class=&n&&CGPROGRAM&/span&
&span class=&cp&&#pragma vertex vert&/span&
&span class=&cp&&#pragma fragment frag&/span&
&span class=&cp&&#include&/span& &span class=&cpf&&&UnityCG.cginc&&/span&&span class=&cp&&&/span&
&span class=&k&&struct&/span& &span class=&n&&v2f&/span&
&span class=&p&&{&/span&
&span class=&n&&float2&/span& &span class=&nl&&uv&/span& &span class=&p&&:&/span& &span class=&n&&TEXCOORD0&/span&&span class=&p&&;&/span& &span class=&c1&&// texture coordinate&/span&
&span class=&n&&float4&/span& &span class=&nl&&vertex&/span& &span class=&p&&:&/span& &span class=&n&&SV_POSITION&/span&&span class=&p&&;&/span& &span class=&c1&&// clip space position&/span&
&span class=&n&&half3&/span& &span class=&nl&&worldNormal&/span& &span class=&p&&:&/span& &span class=&n&&TEXCOORD1&/span&&span class=&p&&;&/span&
&span class=&p&&};&/span&
&span class=&c1&&// vertex shader&/span&
&span class=&n&&v2f&/span& &span class=&nf&&vert&/span&&span class=&p&&(&/span&&span class=&n&&appdata_base&/span& &span class=&n&&v&/span&&span class=&p&&)&/span&
&span class=&p&&{&/span&
&span class=&n&&v2f&/span& &span class=&n&&o&/span&&span class=&p&&;&/span&
&span class=&c1&&// transform position to clip space&/span&
&span class=&c1&&// (multiply with model*view*projection matrix)&/span&
&span class=&n&&o&/span&&span class=&p&&.&/span&&span class=&n&&vertex&/span& &span class=&o&&=&/span& &span class=&n&&mul&/span&&span class=&p&&(&/span&&span class=&n&&UNITY_MATRIX_MVP&/span&&span class=&p&&,&/span& &span class=&n&&v&/span&&span class=&p&&.&/span&&span class=&n&&vertex&/span&&span class=&p&&);&/span&
&span class=&c1&&// just pass the texture coordinate&/span&
&span class=&n&&o&/span&&span class=&p&&.&/span&&span class=&n&&uv&/span& &span class=&o&&=&/span& &span class=&n&&v&/span&&span class=&p&&.&/span&&span class=&n&&texcoord&/span&&span class=&p&&;&/span&
&span class=&n&&o&/span&&span class=&p&&.&/span&&span class=&n&&worldNormal&/span& &span class=&o&&=&/span& &span class=&n&&UnityObjectToWorldNormal&/span&&span class=&p&&(&/span&&span class=&n&&v&/span&&span class=&p&&.&/span&&span class=&n&&normal&/span&&span class=&p&&);&/span&
&span class=&k&&return&/span& &span class=&n&&o&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&c1&&// texture we will sample&/span&
&span class=&n&&sampler2D&/span& &span class=&n&&_MainTex&/span&&span class=&p&&;&/span&
&span class=&c1&&// returns low precision (&fixed4& type)&/span&
&span class=&n&&fixed4&/span& &span class=&nf&&frag&/span&&span class=&p&&(&/span&&span class=&n&&v2f&/span& &span class=&n&&i&/span&&span class=&p&&)&/span& &span class=&o&&:&/span& &span class=&n&&SV_Target&/span&
&span class=&p&&{&/span&
&span class=&c1&&// sample texture and return it&/span&
&span class=&n&&fixed4&/span& &span class=&n&&col&/span& &span class=&o&&=&/span& &span class=&n&&tex2D&/span&&span class=&p&&(&/span&&span class=&n&&_MainTex&/span&&span class=&p&&,&/span& &span class=&n&&i&/span&&span class=&p&&.&/span&&span class=&n&&uv&/span&&span class=&p&&);&/span&
&span class=&kt&&float&/span& &span class=&n&&shadow&/span& &span class=&o&&=&/span& &span class=&n&&dot&/span&&span class=&p&&(&/span&&span class=&n&&i&/span&&span class=&p&&.&/span&&span class=&n&&worldNormal&/span&&span class=&p&&,&/span& &span class=&n&&normalize&/span&&span class=&p&&(&/span&&span class=&n&&_WorldSpaceLightPos0&/span&&span class=&p&&.&/span&&span class=&n&&xyz&/span&&span class=&p&&));&/span&
&span class=&n&&col&/span& &span class=&o&&*=&/span& &span class=&n&&smoothstep&/span&&span class=&p&&(&/span&&span class=&mf&&0.0&/span&&span class=&p&&,&/span& &span class=&mf&&0.1&/span&&span class=&p&&,&/span& &span class=&n&&shadow&/span&&span class=&p&&)&/span& &span class=&o&&*&/span& &span class=&mf&&0.4&/span& &span class=&o&&+&/span& &span class=&mf&&0.6&/span&&span class=&p&&;&/span&
&span class=&c1&&//fixed4 col = 0;&/span&
&span class=&c1&&//col.rgb = i.worldNormal*0.5 + 0.5;&/span&
&span class=&c1&&//col.rgb = _WorldSpaceLightPos0.&/span&
&span class=&k&&return&/span& &span class=&n&&col&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&n&&ENDCG&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&&p&不加光照&/p&&img src=&/v2-45ac68aa62ad449dad4fc03_b.png& data-rawwidth=&842& data-rawheight=&385& class=&origin_image zh-lightbox-thumb& width=&842& data-original=&/v2-45ac68aa62ad449dad4fc03_r.png&&&p&加上之后得到结果&/p&&img src=&/v2-54a0d8dcf5dd0fdee0310dbf_b.png& data-rawwidth=&854& data-rawheight=&379& class=&origin_image zh-lightbox-thumb& width=&854& data-original=&/v2-54a0d8dcf5dd0fdee0310dbf_r.png&&&img src=&/v2-37cecacff0fae_b.png& data-rawwidth=&903& data-rawheight=&367& class=&origin_image zh-lightbox-thumb& width=&903& data-original=&/v2-37cecacff0fae_r.png&&&br&&p&用到了一个内置函数&/p&&p&smoothstep
- interpolate smoothly between two input
values based on a third&/p&&p&目的是为了让明暗交接的地方不要太锋利,过度的平滑一些。&/p&&p& 加上阴影&/p&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span&&span class=&c1&&// shadow caster rendering pass, implemented manually&/span&
&span class=&c1&&// using macros from UnityCG.cginc&/span&
&span class=&n&&Pass&/span&
&span class=&p&&{&/span&
&span class=&n&&Tags&/span&&span class=&p&&{&/span& &span class=&s&&&LightMode&&/span& &span class=&o&&=&/span& &span class=&s&&&ShadowCaster&&/span& &span class=&p&&}&/span&
&span class=&n&&CGPROGRAM&/span&
&span class=&cp&&#pragma vertex vert&/span&
&span class=&cp&&#pragma fragment frag&/span&
&span class=&cp&&#pragma multi_compile_shadowcaster&/span&
&span class=&cp&&#include&/span& &span class=&cpf&&&UnityCG.cginc&&/span&&span class=&cp&&&/span&
&span class=&k&&struct&/span& &span class=&n&&v2f&/span& &span class=&p&&{&/span&
&span class=&n&&V2F_SHADOW_CASTER&/span&&span class=&p&&;&/span&
&span class=&p&&};&/span&
&span class=&n&&v2f&/span& &span class=&nf&&vert&/span&&span class=&p&&(&/span&&span class=&n&&appdata_base&/span& &span class=&n&&v&/span&&span class=&p&&)&/span&
&span class=&p&&{&/span&
&span class=&n&&v2f&/span& &span class=&n&&o&/span&&span class=&p&&;&/span&
&span class=&n&&TRANSFER_SHADOW_CASTER_NORMALOFFSET&/span&&span class=&p&&(&/span&&span class=&n&&o&/span&&span class=&p&&)&/span&
&span class=&k&&return&/span& &span class=&n&&o&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&span class=&n&&float4&/span& &span class=&nf&&frag&/span&&span class=&p&&(&/span&&span class=&n&&v2f&/span& &span class=&n&&i&/span&&span class=&p&&)&/span& &span class=&o&&:&/span& &span class=&n&&SV_Target&/span&
&span class=&p&&{&/span&
&span class=&n&&SHADOW_CASTER_FRAGMENT&/span&&span class=&p&&(&/span&&span class=&n&&i&/span&&span class=&p&&)&/span&
&span class=&p&&}&/span&
&span class=&n&&ENDCG&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&&img src=&/v2-8b6d2f9ac5bcf33ed0d64e_b.png& data-rawwidth=&919& data-rawheight=&454& class=&origin_image zh-lightbox-thumb& width=&919& data-original=&/v2-8b6d2f9ac5bcf33ed0d64e_r.png&&&br&&h2&面部表情&/h2&&p&嘴巴部分最简单,用的和身体一样的shader,要变换嘴型的时候,只需要切换材质的贴图。&/p&&img src=&/v2-7f11aade073eba6b35f194_b.png& data-rawwidth=&450& data-rawheight=&165& class=&origin_image zh-lightbox-thumb& width=&450& data-original=&/v2-7f11aade073eba6b35f194_r.png&&&img src=&/v2-4aa22f4b7ea7dfb1a17a925_b.png& data-rawwidth=&490& data-rawheight=&128& class=&origin_image zh-lightbox-thumb& width=&490& data-original=&/v2-4aa22f4b7ea7dfb1a17a925_r.png&&&img src=&/v2-4db3db0d3e12c4c9d6a0_b.png& data-rawwidth=&477& data-rawheight=&127& class=&origin_image zh-lightbox-thumb& width=&477& data-original=&/v2-4db3db0d3e12c4c9d6a0_r.png&&&br&&p&眼睛部分会比较复杂。眼睛和眉毛的shader是一样的,就是基本的transparent&/p&&img src=&/v2-e1adcb5d5_b.png& data-rawwidth=&502& data-rawheight=&122& class=&origin_image zh-lightbox-thumb& width=&502& data-original=&/v2-e1adcb5d5_r.png&&&br&&p&记住左右眉毛和左右眼睛得用不同的材质,因为不同的表情左右可能是不对称的。&/p&&p&眉毛和眼睛正常了,但是眼珠不正常,这里需要在shader中给眼珠加一个mask,将当前眼白的部分叠加到眼珠上得到最终的结果。&/p&&div class=&highlight&&&pre&&code class=&language-cpp&&&span&&/span&&span class=&n&&fixed4&/span& &span class=&nf&&frag&/span&&span class=&p&&(&/span&&span class=&n&&v2f&/span& &span class=&n&&i&/span&&span class=&p&&)&/span& &span class=&o&&:&/span& &span class=&n&&SV_Target&/span&
&span class=&p&&{&/span&
&span class=&c1&&// sample texture and return it&/span&
&span class=&n&&fixed4&/span& &span class=&n&&col&/span& &span class=&o&&=&/span& &span class=&n&&tex2D&/span&&span class=&p&&(&/span&&span class=&n&&_PupilTex&/span&&span class=&p&&,&/span& &span class=&n&&i&/span&&span class=&p&&.&/span&&span class=&n&&uv&/span&&span class=&p&&);&/span&
&span class=&n&&fixed4&/span& &span class=&n&&mask&/span& &span class=&o&&=&/span& &span class=&n&&tex2D&/span&&span class=&p&&(&/span&&span class=&n&&_EyeMaskTex&/span&&span class=&p&&,&/span& &span class=&n&&i&/span&&span class=&p&&.&/span&&span class=&n&&uv&/span&&span class=&p&&);&/span&
&span class=&n&&col&/span& &span class=&o&&*=&/span& &span class=&n&&mask&/span&&span class=&p&&;&/span&
&span class=&k&&return&/span& &span class=&n&&col&/span&&span class=&p&&;&/span&
&span class=&p&&}&/span&
&/code&&/pre&&/div&&br&&img src=&/v2-a1dc8c8e8f7596eba7bfe6b45c3813bb_b.png& data-rawwidth=&562& data-rawheight=&164& class=&origin_image zh-lightbox-thumb& width=&562& data-original=&/v2-a1dc8c8e8f7596eba7bfe6b45c3813bb_r.png&&&br&&p&需要注意的是眼珠的EyeMaskTex 需要和眼白的maintex要同步好,不然就会很囧。&/p&&img src=&/v2-efb45b9bc764a90e45dad1b968b43a82_b.png& data-rawwidth=&641& data-rawheight=&223& class=&origin_image zh-lightbox-thumb& width=&641& data-original=&/v2-efb45b9bc764a90e45dad1b968b43a82_r.png&&&br&&p&&b&瞳孔的放大缩小&/b&&/p&&p&Link眼睛的瞳孔的位置也是可以控制的,用来表现看的方向&/p&&img src=&/v2-46bfba2801efe9b0c825c66_b.png& data-rawwidth=&460& data-rawheight=&223& class=&origin_image zh-lightbox-thumb& width=&460& data-original=&/v2-46bfba2801efe9b0c825c66_r.png&&&br&&p&同时也是可以放大缩小的,比如说上面的用来表示惊恐的表情&/p&&p&瞳孔的位置处理直接叠加上一个uv偏移就可以了。&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&_XOffset(&X Offset&, float) = 0
_YOffset(&Y Offset&, float) = 0
float2 finalUv = i.uv + float2(_XOffset, _YOffset)
fixed4 col = tex2D(_PupilTex, finalUv);
&/code&&/pre&&/div&&br&&p&调一个结果&/p&&img src=&/v2-7cf32a16aba5c9bd9b765fd_b.png& data-rawwidth=&721& data-rawheight=&278& class=&origin_image zh-lightbox-thumb& width=&721& data-original=&/v2-7cf32a16aba5c9bd9b765fd_r.png&&&br&&p&惊悚的表情需要进行UV缩放,注意不是将uv直接乘以scale值,这样会从左下角为中心缩放,我们的目的是从贴图的中心开始缩放,需要一个简单的换算&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&float2 scaleCenter = float2(0.5f, 0.5f);
float2 finalUv = (i.uv + float2(_XOffset, _YOffset) - scaleCenter) * _Scale + scaleC
fixed4 col = tex2D(_PupilTex, finalUv);
&/code&&/pre&&/div&&p&调个简单的结果&/p&&img src=&/v2-d0f0d838bf6de4db02e05f2_b.png& data-rawwidth=&737& data-rawheight=&213& class=&origin_image zh-lightbox-thumb& width=&737& data-original=&/v2-d0f0d838bf6de4db02e05f2_r.png&&&p&还有一个点要注意,瞳孔的纹理的wrap mode 要设置为&/p&&img src=&/v2-d53adf950b3e7e414b63a2ec9d2397b7_b.png& data-rawwidth=&354& data-rawheight=&81& class=&content_image& width=&354&&&br&&p&不然会出现…&/p&&img src=&/v2-66fae26a10fb9b6e578d6d212ecfa78f_b.png& data-rawwidth=&437& data-rawheight=&185& class=&origin_image zh-lightbox-thumb& width=&437& data-original=&/v2-66fae26a10fb9b6e578d6d212ecfa78f_r.png&&&br&&p&&b&头发不会挡住眼睛&/b&&/p&&p&游戏中是这样的就像下面这样&br&&/p&&img src=&/v2-6a3ebec7ef689b443d3df_b.png& data-rawwidth=&756& data-rawheight=&337& class=&origin_image zh-lightbox-thumb& width=&756& data-original=&/v2-6a3ebec7ef689b443d3df_r.png&&&br&&p&虽然有时候看起来有点奇怪&/p&&img src=&/v2-d5ce00e8e4ef2f1f0fa89d4_b.png& data-rawwidth=&963& data-rawheight=&341& class=&origin_image zh-lightbox-thumb& width=&963& data-original=&/v2-d5ce00e8e4ef2f1f0fa89d4_r.png&&&p&但是整体表现还是挺好的。&/p&&p&这里使用的方法是利用Stencil buffer来处理,首先标记出被遮挡的部分,然后清掉那一部分的zbuffer,最后绘制出来,下面是具体的实现。&/p&&p&首先单独给头发一个shader,用来写stencil&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&Stencil
Comp always
Pass replace
&/code&&/pre&&/div&&p&其余部分和身体的shader一样,头发绘制过的地方Stencil都变成了1。&/p&&p&眼睛分为三个pass绘制,&/p&&p&第一个pass标记出stencil为1,且ztest fail的部位&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&Stencil
Comp Equal
Pass replace
ZFail IncrSat
&/code&&/pre&&/div&&p&ZFail
IncrSat表示通过stencil test,Ztest失败之后,将stencil的值+1.所以被头发遮挡住的地方stencil变成了2.下面蓝色部分就是&/p&&img src=&/v2-45acc372baf6de322fefb22_b.png& data-rawwidth=&442& data-rawheight=&192& class=&origin_image zh-lightbox-thumb& width=&442& data-original=&/v2-45acc372baf6de322fefb22_r.png&&&br&&p&第二个pass,清掉标记区的Zbuffer&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&ZTest Greater
Comp Equal
&/code&&/pre&&/div&&br&&p&第三个pass,就是最简单的transparent&/p&&div class=&highlight&&&pre&&code class=&language-text&&&span&&/span&Pass
Tags{ &IgnoreProjector& = &True& &RenderType& = &Transparent& }
// use &vert& function as the vertex shader
#pragma vertex vert
// use &frag& function as the pixel (fragment) shader
#pragma fragment frag
#include &UnityCG.cginc&
// vertex shader outputs (&vertex to fragment&)
struct v2f
float2 uv : TEXCOORD0; // texture coordinate
float4 vertex : SV_POSITION; // clip space position
// vertex shader
v2f vert(appdata_base v)
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
// texture we will sample
sampler2D _MainT
fixed4 frag(v2f i) : SV_Target
fixed4 col = tex2D(_MainTex, i.uv);
&/code&&/pre&&/div&&br&&p&最终结果&/p&&img src=&/v2-a64bb1b988a331c260d59f_b.png& data-rawwidth=&695& data-rawheight=&290& class=&origin_image zh-lightbox-thumb& width=&695& data-original=&/v2-a64bb1b988a331c260d59f_r.png&&&img src=&/v2-553fe26df467bbe50e7757cbd1751e33_b.png& data-rawwidth=&832& data-rawheight=&330& class=&origin_image zh-lightbox-thumb& width=&832& data-original=&/v2-553fe26df467bbe50e7757cbd1751e33_r.png&&&br&&p&最后来摆几个Pose&/p&&br&&img src=&/v2-751f72b9c0de946f05da21_b.png& data-rawwidth=&778& data-rawheight=&320& class=&origin_image zh-lightbox-thumb& width=&778& data-original=&/v2-751f72b9c0de946f05da21_r.png&&&br&&img src=&/v2-90c0b1fa4f_b.png& data-rawwidth=&801& data-rawheight=&339& class=&origin_image zh-lightbox-thumb& width=&801& data-original=&/v2-90c0b1fa4f_r.png&&&br&&img src=&/v2-20e58c2e68fcbf0051a4_b.png& data-rawwidth=&1092& data-rawheight=&533& class=&origin_image zh-lightbox-thumb& width=&1092& data-original=&/v2-20e58c2e68fcbf0051a4_r.png&&&br&&h2&小结&/h2&&p&相对于UnityChan中完全用骨骼驱动的表情系统(王者荣耀里面角色展示的部分似乎也是这样处理的)&/p&&img src=&/v2-280b79c0ebea6aaf69e9fe1_b.png& data-rawwidth=&621& data-rawheight=&319& class=&origin_image zh-lightbox-thumb& width=&621& data-original=&/v2-280b79c0ebea6aaf69e9fe1_r.png&&&br&&br&&p&这套表情系统的特点是&/p&&p&非常节省资源,几乎没有什么消耗(也许贴图还可以再pack一下?)。&/p&&p&和美术风格非常的搭。&/p&&p&面部的所有细节都不会糊掉。&/p&&p&无法使用macanim动画系统,需要自己写一套控制角色表情的脚本。&/p&&p&对于在移动平台上想自己实现一个的表情系统的卡通风格项目可以考虑用这种方案。&/p&&h2&参考&/h2&&p&&a href=&/?target=http%3A//www.benjones.us/twilight-princess-eyes-breakdown/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Twilight Princess Eyes Breakdown&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&a href=&/?target=http%3A///2013/07/animated-facial-textures-in-maya-and_26.html& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&http://&/span&&span class=&visible&&&/span&&span class=&invisible&&/2013/07/animated-facial-textures-in-maya-and_26.html&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&a href=&/?target=https%3A///%40gordonnl/links-expressions-eb7beae2c62c& class=& external& target=&_blank& rel=&nofollow noreferrer&&&span class=&invisible&&https://&/span&&span class=&visible&&/@gordonnl/li&/span&&span class=&invisible&&nks-expressions-eb7beae2c62c&/span&&span class=&ellipsis&&&/span&&i class=&icon-external&&&/i&&/a&&br&&/p&&p&&a href=&/?target=http%3A///bitzhuwei/p/explain-offset-and-tiling-with-Unity-and-3ds.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&图文详解Unity3D中Material的Tiling和Offset是怎么回事 - BIT祝威 - 博客园&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&/?target=http%3A///blog/puppet_master/article/p-6362899.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Unity Shader-渲染队列,ZTest,ZWrite,Early-Z&i class=&icon-external&&&/i&&/a&&/p&&p&&a href=&/?target=http%3A//blog.csdn.net/silangquan/article/details/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Unity3D游戏开发从零单排(十) - 进击的Shader续&i class=&icon-external&&&/i&&/a&&/p&
简介《塞尔达传说
风之杖》是一款由任天堂开发的任天堂GameCube平台上的动作冒险游戏,一经发布就广受好评,之后任天堂在WiiU上还发布了HD版本。其别具一格的卡通美术风格现如今看来都不算过时,甚至给最近火的一塌糊涂的《塞尔达传说
荒野之息》带来了很大…
&img src=&/v2-23feb29a1c3eaf68ceeb048f3a88bc4f_b.png& data-rawwidth=&738& data-rawheight=&756& class=&origin_image zh-lightbox-thumb& width=&738& data-original=&/v2-23feb29a1c3eaf68ceeb048f3a88bc4f_r.png&&&p&还记得最初学图形学时,被 OpenGL 一堆非常底层的 API 搞得晕头转向。这时候,跑来一个学长(是交大的学长没错),指着&a href=&/?target=https%3A///subject/4311129/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&红宝书&i class=&icon-external&&&/i&&/a&上类似这样的一个图,语重心长地说:“图形学啊,你只要记住这个图就吼啦!”&/p&&img src=&/v2-a6a451ed33a_b.jpg& data-rawwidth=&636& data-rawheight=&282& class=&origin_image zh-lightbox-thumb& width=&636& data-original=&/v2-a6a451ed33a_r.jpg&&图片来源:&a href=&/?target=http%3A///devnet/flashplayer/articles/how-stage3d-works.html& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&&i class=&icon-external&&&/i&&/a&&p&当然啦,我当时只是似懂非懂地点了点头。&/p&&br&&p&很多年过去了,后来的研究和现在的工作却总也绕不开这张图。这感觉,就好像你一早就拿到了一本武林至尊秘笈,但是在你掌握看懂它的方法之前,它对你始终而言就是一本天书。&/p&&p&其实不仅仅是前端,图形渲染对于整个软件工程来说,都是一个很特定的研究领域。这就意味着,大部分情况下,你可能并没有那么迫切的需求去学习它。这也是为什么,WebGL 标准推出了那么多年,在前端的各种分享会上,即使介绍,也永远都是 Hello World。&/p&&p&是的,WebGL 不容易,没有扎实的数学和图形学基础,很难深入地理解。所幸,在 &a href=&/?target=http%3A//threejs.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Three.js&i class=&icon-external&&&/i&&/a& 这类库的帮助下,对于没有图形学基础的前端工程师,想要快速地创建出三维场景,也并非天方夜谭。Three.js 的教程我在&a href=&/?target=https%3A///ebook/7412854/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&《Three.js 入门指南》&i class=&icon-external&&&/i&&/a& 中已经做了很浅近的说明,这里不再重复。&/p&&h1&关于本系列&/h1&&p&这一系列主要&strong&针对使用着色器实现不同效果的渲染算法&/strong&作介绍。&/p&&p&在这一篇文章中,我将通过&a href=&/?target=https%3A//zh.wikipedia.org/wiki/%25E5%258D%25A1%25E9%E6%25B8%25B2%25E6%259F%2593& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&卡通渲染&i class=&icon-external&&&/i&&/a&的例子,介绍如何写一个非常简单的着色器。在本文结束的时候,我们将能够实现一种将画面中的颜色分为若干颜色层次的卡通渲染效果。&/p&&p&这一系列教程的源代码可以在 GitHub 的 &a href=&/?target=https%3A///Ovilia/cezanne& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Ovilia/cezanne&i class=&icon-external&&&/i&&/a& 项目访问到,欢迎关注项目。&/p&&p&通过这套教程,希望能够把晦涩难懂的数学理论,通过浅显易懂的比喻和实际的例子,帮助大家更快速地掌握着色器编程。虽然就起实现而言,是使用 &a href=&/?target=http%3A//threejs.org/& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Three.js&i class=&icon-external&&&/i&&/a& 基于 WebGL 的,对其他平台上的着色器编程也有一定参考价值。&/p&&p&同时,对我自己而言,这也是一个能够让我系统化、更深入地理解着色器编程的一个途径。希望能够坚持写高质量的教程,欢迎大家多多支持!&/p&&h1&着色器能做什么&/h1&&p&要回答这个问题,我们先简单了解一下,着色器是什么。&/p&&p&着色器全称着色器程序,是运行在 GPU 中负责渲染算法的一类总称。相对地,我们通常写的代码是执行在 CPU 中的,因此,我们可以自豪地说,我在写 GPU 程序呢!&/p&&p&GLSL(OpenGL Shading Language)是在 OpenGL 对应的着色器语言。相对地,DirectX 对应的着色器语言是 High-Level Shading Language(HLSL)。&/p&&p&好好好,我们不说概念了,知道你已经想关闭网页了……&/p&&p&我们还是来看一些着色器实现的酷炫效果吧!&/p&&img src=&/v2-bdb3b79a309_b.jpg& data-rawwidth=&1000& data-rawheight=&851& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&/v2-bdb3b79a309_r.jpg&&&p&预告一下,这是 &a href=&/people/fba5ac7480f0& data-hash=&fba5ac7480f0& class=&member_mention& data-editable=&true& data-title=&@沈毅& data-hovercard=&p$b$fba5ac7480f0&&@沈毅&/a&
大神正在闭关开发中的参数曲面效果,用不了多久,你也可以使用 &a href=&/?target=http%3A///& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&ECharts&i class=&icon-external&&&/i&&/a& 创建这样酷炫的三维图表啦!&/p&&p&事实上,着色器通常是用来做一些渲染效果上的事,比如水面的渲染、马赛克效果、素描风格化渲染等等……&/p&&img src=&/v2-6c72a21e70aba4d0167f8_b.jpg& data-rawwidth=&1000& data-rawheight=&625& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&/v2-6c72a21e70aba4d0167f8_r.jpg&&&img src=&/v2-d721dd9d4bcbf3d39cf17d1de7c8bfd5_b.jpg& data-rawwidth=&1000& data-rawheight=&625& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&/v2-d721dd9d4bcbf3d39cf17d1de7c8bfd5_r.jpg&&&img src=&/v2-b160276decd744c2694fcd_b.jpg& data-rawwidth=&1000& data-rawheight=&625& class=&origin_image zh-lightbox-thumb& width=&1000& data-original=&/v2-b160276decd744c2694fcd_r.jpg&&&p&可以说,那些让人觉得母牛不下崽(牛逼坏了……我昨天新学的歇后语,容我用用!)的效果,通常都离不开着色器代码。&/p&&h1&着色器的分类&/h1&&p&最常用到的两种着色器分别为&em&顶点着色器&/em&(&em&Vertex Shader&/em&)和&em&片元着色器&/em&(&em&Fragment Shader&/em&)。&/p&&p&首先需要明确的概念是,&strong&片元着色器是在顶点着色器之后被调用的&/strong&,因而也可以从顶点着色器往片元着色器传递参数。&/p&&blockquote&&p&其他类型的着色器参阅 &a href=&/?target=https%3A//www.khronos.org/opengl/wiki/Shader& class=& wrap external& target=&_blank& rel=&nofollow noreferrer&&Shader - OpenGL Wiki - Khronos Group&i class=&icon-external&&&/i&&/a&。&/p&&/blockquote&&h2&顶点着色器&/h2&&p&什么是顶点呢?&/p&&p&比如你用 OpenGL 画一个三角形,那就是创建了三个顶点。&/p&&p&而&strong&顶点着色器就是每个顶点调用一次的程序&/strong&。&/p&&p&在顶点着色器中,可以访问到顶点的三维位置、颜色、法向量等信息。可以通过修改这些值,或者将其传递到片元着色器中,实现特定的渲染效果。&/p&&h2&片元着色器&/h2&&p&“片元”的概念大家可能相对陌生一些。但是一个相似的概念是“像素”,这你一定听说过。&/p&&p&场景渲染到显示器的过程中,有一个步骤叫&em&光栅化&/em&(&em&Rasterization&/em&)。由于我们现在的显示器绝大多数是基于像素的(就是由一个个非常小

我要回帖

更多关于 更改文件类型 的文章

 

随机推荐