【Unity Shader】新书封面 — Low Polygon风格的渲染

本文介绍了如何在Unity中实现Low Polygon风格的渲染,包括原理、直接使用Unity的设置方法、程序生成网格的处理以及利用Geometry Shader的复杂方法。通过调整模型的硬边和法线计算,实现独特的复古风格渲染效果。

写在前面

最近又开心又担心,因为我的书马上就要上市了,开心当然是因为等了这么久终于可以如愿了,担心是因为不少人对它的期待都很大,我第一次写书,能力也有限,不知道能不能让大家满意,让大家也都喜欢上它。不过有不少朋友和前辈鼓励我,还是很开心滴~

之前有一些朋友觉得这次封面很漂亮,问我书的封面是不是我渲染的,以及怎么渲染的:

这里写图片描述

其实这封面并不是在Unity里渲染的,是男朋友在C4D里面渲染的。我特别喜欢他上学时候的一次作品(有机会放个视频哈哈),就是这种low polygon的风格,所以当时想要设计书的封面的时候就想要用这个素材。构图是我们讨论后的结果,我特意要他把Unity的Logo放到旗帜上面,然后让画面中间的男孩停在走进屋子的位置上,以此来寓意“入门”。之后就发给一些朋友看,问他们觉得怎么样,会不会太粉嫩、女生化?大家反馈说,这样放在书架上会很显眼,让人有想看的欲望,还有一些人说挺好的,不少游戏都这种风格,不过大部分技术人员说无所谓……技术书内容好就行~Anyway,之后发给了编辑,经过出版社美编同学的一些修改后就成了现在这个样子,希望大家还满意 :)

说到游戏里面low polygon风格的渲染,一直都是一种很有特色的渲染。因为男朋友是设计师,所以他总会拿一些美图来熏陶我,我每次看到这种风格的就会想多看几眼,大概是因为我还没度过小女生的年纪吧……例如下面这张(更多这种风格的设计图案可以参见这个网站):

这里写图片描述

Low polygon风格其实是一种复古风格,在早期的不支持插值渲染的年代,这种风格随处可见,因为模型简单、渲染也不复杂,在早期游戏中被大量使用。

回到技术上来,那么这种low polygon风格在游戏里怎么渲染呢?

原理

Low polygon风格的渲染也被称为flat shading。虽然把这篇文章归到Shader类别里,但其实是完全可以用非Shader的方法来解决的。下面两张图片,左边是我们不希望得到的结果,而右边是我们想要得到的效果。

这里写图片描述 这里写图片描述

做美术的同学都知道上面模型的区别就是“硬边”和“软边”的问题。左图里就是软边的效果,软边意味着相邻三角形之间共用顶点,这些被共用顶点的法线(蓝线)通常是根据毗连三角形的面法线加权平均计算得到的,如下图所示(图片来源):

这里写图片描述

由于共用顶点的存在,光栅化阶段的插值使得这些三角面片中间每个点的点法线都是有三个顶点的法线插值得到的,而这三个法线各不相同, 使得面片有平滑过渡的效果,从而形成软边。在其他风格的渲染中,模型大多都会使用软边,这不仅可以减少顶点数目提高性能,还能让渲染效果更加平滑。

但flat shading显然不想要平滑的渲染效果,我们希望就算光栅化插值后同一个三角面片中每个点的法线都应该是相同的(都等于面法线),只有这样它们光照计算的结果才会是相同的。如下图所示(图片来源):

这里写图片描述

要实现这样的效果就是把所有相连的边在建模软件中设置成硬边,Hard Edge。这样软件背后就会进行拆顶点的工作,每个三角形有各自属于自己的三个顶点,不与他人共用,这三个顶点的点法线计算不会受毗连三角形的影响,而仅仅是由该三角面片的面法线决定。

因此,我们有了解决方案一:在建模软件中把边设置成硬边

直接使用Unity

值得高兴的是,就算你在建模软件里忘记了设置硬边,Unity也是可以直接帮我们做到软硬边的转换的。它的原理其实就是重新拆点、重新计算点法线。

这里写图片描述

在我们导入一个模型后,可以在模型的导入面板中的Normals & Tangents块中,把Normals设置成Calculate模式、把Smoothing Angle设置成0就可以得到硬边的效果。如上图所示。

这样的模型可以直接使用任何普通的Shader进行渲染,就会得到flat shading的效果。

程序产生的网格

之前群里有人问程序产生的网格怎么实现这种效果。原理也是一样的,我们只需要保证不要共用顶点、正确计算顶点法线即可。在我的NPR项目里,有这样一个例子,把任何模型强制转化成没有共用顶点的模型。其中关键代码是长这个样子的:

Vector3[] oldVerts = mesh.vertices;
Vector4[] oldTangents = mesh.tangents;
Vector2[] oldUVs = mesh.uv;
int[] triangles = mesh.triangles;
Vector3[] newVerts = new Vector3[triangles.Length];
Vector4[] newTangents = new Vector4[triangles.Length];
Vector2[] newUVs = new Vector2[triangles.Length];
for (int i = 0; i < triangles.Length; i++) {
    newVerts[i] = oldVerts[triangles[i]];
    newTangents[i] = oldTangents[triangles[i]];
    newUVs[i] = oldUVs[triangles[i]];
    triangles[i] = i;
}
mesh.vertices = newVerts;
mesh.tangents = newTangents;
mesh.triangles = triangles;
mesh.uv = newUVs;
mesh.RecalculateBounds();
mesh.RecalculateNormals();

因此,如果你是通过程序方法产生网格的,可以使用类似上面的代码来进行网格转换,再使用普通的Shader即可。

更复杂的方法:Geometry Shader

上面转化硬边的方法会增加顶点数目,有一种完全不需要对网格进行任何处理的方法就是使用Geometry Shader。这种方法的原理就是在光栅化前、在Geometry Shader里给每个顶点增加一个属性,面法线faceNormal。由于Geometry Shader中可以知道同一个三角面片中的所有三个顶点的信息,因此我们可以为它们计算一个相同的面法线值。这样,即便在经过光栅化插值后,同一个三角面片中的面法线也是一样的。关键代码如下:

[maxvertexcount(3)]
void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream) {
    float3 A = IN[1].worldPos.xyz - IN[0].worldPos.xyz;
    float3 B = IN[2].worldPos.xyz - IN[0].worldPos.xyz;
    float3 fn = normalize(cross(A, B));

    g2f o;
    o.pos = IN[0].pos;
    o.uv = IN[0].uv;
    o.worldPos = IN[0].worldPos;
    o.faceNormal = fn;
    triStream.Append(o);

    o.pos = IN[1].pos;
    o.uv = IN[1].uv;
    o.worldPos = IN[1].worldPos;
    o.faceNormal = fn;
    triStream.Append(o);

    o.pos = IN[2].pos;
    o.uv = IN[2].uv;
    o.worldPos = IN[2].worldPos;
    o.faceNormal = fn;
    triStream.Append(o);
}

这种方法有点小题大做,因为geometry shader是SM 4.0中的特性,移动终端大多达不到这样的要求。

写在最后

如果大家真的想做low polygon风格的游戏,可以考虑一个插件PolyWorld,看着很不错的样子。

最后,希望大家喜欢《Unity Shader入门精要》这本书(源码下载),任何问题欢迎联系我的邮箱(lelefeng1992 # gmail DOT com)或在Github上发issue。再次感谢大家的支持 :)

参考链接:

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标准的Java组件或 EJBs。 Quartz的优势: 1、Quartz是一个任务调度框架(库),它几乎可以集成到任何应用系统中。 2、Quartz是非常灵活的,它让您能够以最“自然”的方式来编写您的项目的代码,实现您所期望的行为 3、Quartz是非常轻量级的,只需要非常少的配置 —— 它实际上可以被跳出框架来使用,如果你的需求是一些相对基本的简单的需求的话。 4、Quartz具有容错机制,并且可以在重启服务的时候持久化(”记忆”)你的定时任务,你的任务也不会丢失。 5、可以通过Quartz,封装成自己的分布式任务调度,实现强大的功能,成为自己的产品。6、有很多的互联网公司也都在使用Quartz。比如美团 Spring是一个很优秀的框架,它无缝的集成了Quartz,简单方便的让企业级应用更好的使用Quartz进行任务的调度。   课程说明:在我们的日常开发中,各种大型系统的开发少不了任务调度,简单的单机任务调度已经满足不了我们的系统需求,复杂的任务会让程序猿头疼, 所以急需一套专门的框架帮助我们去管理定时任务,并且可以在多台机器去执行我们的任务,还要可以管理我们的分布式定时任务。本课程从Quartz框架讲起,由浅到深,从使用到结构分析,再到源码分析,深入解析Quartz、Spring+Quartz,并且会讲解相关原理, 让大家充分的理解这个框架和框架的设计思想。由于互联网的复杂性,为了满足我们特定的需求,需要对Spring+Quartz进行二次开发,整个二次开发过程都会进行讲解。Spring被用在了越来越多的项目中, Quartz也被公认为是比较好用的定时器设置工具,学完这个课程后,不仅仅可以熟练掌握分布式定时任务,还可以深入理解大型框架的设计思想。
评论 52
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值