【Unity Shader】新书封面 — Low Polygon风格的渲染
写在前面
最近又开心又担心,因为我的书马上就要上市了,开心当然是因为等了这么久终于可以如愿了,担心是因为不少人对它的期待都很大,我第一次写书,能力也有限,不知道能不能让大家满意,让大家也都喜欢上它。不过有不少朋友和前辈鼓励我,还是很开心滴~
之前有一些朋友觉得这次封面很漂亮,问我书的封面是不是我渲染的,以及怎么渲染的:
其实这封面并不是在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。再次感谢大家的支持 :)
参考链接:
【Unity Shader】新书封面 — Low Polygon风格的渲染的更多相关文章
- Unity Shader入门精要学习笔记 - 第14章非真实感渲染
转载自 冯乐乐的 <Unity Shader 入门精要> 尽管游戏渲染一般都是以照相写实主义作为主要目标,但也有许多游戏使用了非真实感渲染(NPR)的方法来渲染游戏画面.非真实感渲染的一个 ...
- Unity Shader 知识点总结(二)
紧接着上一篇文章的shader入门知识的总结,本文主要总结shader中的纹理贴图.透明度混合.顶点动画.后期特效处理等操作.如果有什么地方有错,请指出更正,谢谢.本文的代码主要来自开源书:unity ...
- 【我的书】Unity Shader的书 — 文件夹(2015.12.21更新)
写在前面 感谢全部点进来看的朋友.没错.我眼下打算写一本关于Unity Shader的书. 出书的目的有以下几个: 总结我接触Unity Shader以来的历程,给其它人一个借鉴.我非常明确学Shad ...
- 【我的书】Unity Shader的书 — 目录(2016.5.19最后一次更新)
写在前面 感谢所有点进来看的朋友.没错,我目前打算写一本关于Unity Shader的书. 出书的目的有下面几个: 总结我接触Unity Shader以来的历程,给其他人一个借鉴.我非常明白学Shad ...
- Unity Shader入门教程(一)
参考文献:http://www.360doc.com/content/13/0923/15/12282510_316492286.shtml Unity Shader是着色器,将纹理.网格信息输入,得 ...
- 【Unity Shader】Unity Chan的卡通材质
写在前面 时隔两个月我终于来更新博客了,之前一直在学东西,做一些项目,感觉没什么可以分享的就一直没写.本来之前打算写云彩渲染或是Compute Shader的,觉得时间比较长所以打算先写个简单的. 今 ...
- Unity Shader 学习之旅
Unity Shader 学习之旅 unityshader图形图像 纸上学来终觉浅,绝知此事要躬行 美丽的梦和美丽的诗一样 都是可遇而不可求的——席慕蓉 一.渲染流水线 示例图 Tips:什么是 GP ...
- 【转】《Unity Shader入门精要》冯乐乐著 书中彩图
为方便个人手机学习时候查阅,从网上转来这些彩图. 如属过当行为,联系本人删除. 勘错表 http://candycat1992.github.io/unity_shaders_book/unity_s ...
- Unity Shader入门精要学习笔记 - 第7章 基础纹理
转自 冯乐乐的 <Unity Shader 入门精要> 纹理最初的目的就是使用一张图片来控制模型的外观.使用纹理映射技术,我们可以把一张图“黏”在模型表面,逐纹素地控制模型的颜色. 在美术 ...
随机推荐
- Glide v4版本用法探究.md
一基本介绍 本博客是基于Glide4.0+进行探究和学习 使用配置 用法比对 二使用配置 1. Android studio 使用项目gradle配置 dependencies { //glide c ...
- [LeetCode] Student Attendance Record I 学生出勤记录之一
You are given a string representing an attendance record for a student. The record only contains the ...
- ios开发-程序压后台后,悄悄的抓取数据~~
我们使用某个app的时候,当我们将程序压到后台之后,我们希望它还能从服务器抓取一些数据,类似微博,微信,qq这些程序压后台 之后,我们依然能看到icon上显示未读数量.但是ios系统是伪多任务操作系统 ...
- 词向量:part 1 WordNet、SoW、BoW、TF-IDF、Hash Trick、共现矩阵、SVD
1.基于知识的表征 如WordNet(图1-1),包含同义词集(synonym sets)和上位词(hypernyms,is a关系). 存在的问题: 作为资源来说是好的,但是它失去了词间的细微差别, ...
- Linux(四)使用Xshell5远程登录
Xshell5和Xftp5的安装包 链接:https://pan.baidu.com/s/1q3-ch75TW3lvC3KX25klNQ 密码:m31n 说明: 公司开发的时候,具体情况是这样的: 1 ...
- [BZOJ]2194: 快速傅立叶之二
题目大意:给定序列a,b,求序列c满足c[k]=sigma(a[i]*b[i-k]) (k<=i<n).(n<=10^5) 思路:观察发现就是普通的卷积反一反(翻转ab其中一个后做卷 ...
- hdu 5451(矩阵 +Fibonacci )
题意:求 [(5 + 2*sqrt(6))^(1 + 2^x)] % M 基于hdu2256可以求(5 + 2*sqrt(6))^ n 但是n特别大,我们可以找矩阵的循环节 两种可能 1.mod-1 ...
- Codeforces Round #419 D. Karen and Test
Karen has just arrived at school, and she has a math test today! The test is about basic addition an ...
- 【CODEVS 6384 大米兔学全排列】
·大米兔学习全排列,还有一些逆序对,还有一棵二叉索引树.· ·分析: 首先肯定不是像题目上说的那样,使用next_permutation去完成这道题,因为就算是线性的它也不能承受庞大的排列 ...
- 求n个数的最小公倍数
解决的问题: 对于一个长度为n序列ai,求ai的最小公倍数 解析: 我们知道,如果求两个数a,b的LCM=a*b/gcd(a,b),多个数我们可以两两求LCM,再合并,这样会爆long long 所以 ...