LowPoly

一种低多边形风格画作或效果。
参考文章:
【Unity Shader】新书封面 — Low Polygon风格的渲染
图形学进阶——曲面细分与几何着色器
效果如下:


原理


就我个人的理解来看,原始的法线如上面的左图,在片元着色器阶段,会将三角形三个法线做插值得到当前着色点的法线,从而产生平滑的效果,也就是右图。

LowPoly风格正好是不需要平滑处理的,反而就是要左图这种棱角分明的感觉,所以核心思想就是当前所在三角形只使用一个法线,让该三角形区域的着色点使用的法线都是同一个。

Shader

Shader "NPR/LowPolyStyle"
{Properties{_Color ("Color", Color) = (1,1,1,1)}SubShader{Pass{Tags {"LightMode"="ForwardBase"}CGPROGRAM#pragma multi_compile_fwdbase#pragma target 4.0#pragma vertex vert#pragma geometry geom#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"fixed4 _Color;struct v2g{float4 pos:SV_POSITION;float2 uv:TEXCOORD0;float3 worldPos:TEXCOORD1;};struct g2f{float4 pos:SV_POSITION;float2 uv:TEXCOORD0;float3 worldPos:TEXCOORD1;float3 faceNormal:TEXCOORD2;};v2g vert(appdata_base v){v2g o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;o.worldPos = mul(unity_ObjectToWorld, v.vertex);return o;}[maxvertexcount(3)] //用于定义最大输出点void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream){// 定义图元输入:point、 line、 lineadj、 triangle、 triangleadj 分别为点线面// 定义图元输出:PointStream、 LineStream、 TriangleStream 同上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);}fixed4 frag(g2f i):SV_Target{fixed3 lightDir = UnityWorldSpaceLightDir(i.worldPos);fixed3 ambient = UNITY_LIGHTMODEL_AMBIENT.xyz;fixed3 normalDir = normalize(i.faceNormal);fixed diff = saturate(dot(normalDir, lightDir));fixed3 diffuse = _LightColor0.rgb * _Color.rgb * diff;return fixed4(diffuse + ambient, 1);}ENDCG}Pass {Tags {"LightMode"="ForwardAdd"}Blend One OneCGPROGRAM#pragma multi_compile_fwdadd#pragma target 4.0#pragma vertex vert#pragma geometry geom#pragma fragment frag#include "UnityCG.cginc"#include "Lighting.cginc"#include "AutoLight.cginc"fixed4 _Color;struct v2g {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;float3 worldPos : TEXCOORD1;float4 _ShadowCoord : TEXCOORD2;};struct g2f {float4 pos : SV_POSITION;float2 uv : TEXCOORD0;float3 worldPos : TEXCOORD1;float3 faceNormal : TEXCOORD2;float4 _ShadowCoord : TEXCOORD3;};v2g vert(appdata_base v) {v2g o;o.pos = UnityObjectToClipPos(v.vertex);o.uv = v.texcoord;o.worldPos = mul(unity_ObjectToWorld, v.vertex);o._ShadowCoord = mul(unity_WorldToShadow[0], mul(unity_ObjectToWorld, v.vertex));return o;}[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));float3 worldPos = (IN[0].worldPos + IN[1].worldPos + IN[2].worldPos)/3.0;g2f o;o.pos = IN[0].pos;o.uv = IN[0].uv;o.worldPos = worldPos;o.faceNormal = fn;o._ShadowCoord = IN[0]._ShadowCoord;triStream.Append(o);o.pos = IN[1].pos;o.uv = IN[1].uv;o.worldPos = worldPos;o.faceNormal = fn;o._ShadowCoord = IN[1]._ShadowCoord;triStream.Append(o);o.pos = IN[2].pos;o.uv = IN[2].uv;o.worldPos = worldPos;o.faceNormal = fn;o._ShadowCoord = IN[2]._ShadowCoord;triStream.Append(o);}fixed4 frag(g2f i) : SV_Target {fixed3 lightDir = UnityWorldSpaceLightDir(i.worldPos);fixed3 normalDir = normalize(i.faceNormal);fixed diff = saturate(dot(normalDir, lightDir));UNITY_LIGHT_ATTENUATION(atten, i, i.worldPos);fixed3 diffuse = _LightColor0.rgb * _Color.rgb * diff * atten * atten;return fixed4(diffuse, 1);}ENDCG}}FallBack "Diffuse"
}

重点分析一下几何着色器的代码:

[maxvertexcount(3)] //用于定义最大输出点
void geom(triangle v2g IN[3], inout TriangleStream<g2f> triStream){// 定义图元输入:point、 line、 lineadj、 triangle、 triangleadj 分别为点线面// 定义图元输出:PointStream、 LineStream、 TriangleStream 同上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);
}

其中 A, B 是用来获得三角面片的法线向量,如下图:


输入了三个顶点,输出三个顶点的法线值都为当前计算得到的这个,那么在传入到片元着色器之前所做的插值其实就并未改变法线向量,因为插值的三个法线向量都一样,怎么插值都是一样的。

得到法线后,后面的代码就和普通代码一样了,总体来说原理还是比较简单的,不过想要获得更有意思的效果,应该还有很多trick,学习之路无止境啊~~~

UnityShader-LowPoly相关推荐

  1. UnityShader入门精要-3.3 UnityShader的结构

    一个UnityShader的基础结构如下所示: Shader "ShaderName"{Properties{//属性 } SubShader{//显卡A使用的子着色器 }SubS ...

  2. thymeleaf动态选中select_一些LowPoly动态渐变效果实现

    这篇文章根大家分享一些LowPoly动态效果的制作方法,由于使用的是uv采样方式效率很高,手机也可以随意使用,我们先来看一些效果的参考 本文将在Unity3D中还原这些效果,如果你学会后当然可以在你喜 ...

  3. UnityShader之遮挡透明

    UnityShader之遮挡透明 好久没写博客了,最近在学shader,不得不说,shader真的非常美妙,我沉迷其中无法自拔= = 之前做过一个遮挡透明的功能,当物体遮挡住主角时,该物体会变成半透明 ...

  4. UnityShader例子:边缘检测

    一.边缘检测 没有什么新的东西,只需了解<UnityShader26:运动模糊>这一章里面的内容就好 1):Roberts算子: 本质就是计算左上角和右下角的差值,乘上右上角和左下角的插值 ...

  5. UnityShader4:UnityShader的形式

    前置:UnityShader2:Shader与材质 一.Standard Surface Shader 代码解析 在前置中已经了解了什么是表面着色器,下面这是 Standard Surface Sha ...

  6. [UnityShader基础]06.#pragma multi_compile

    [UnityShader基础]06.#pragma multi_compile 参考链接: https://blog.csdn.net/qq826364410/article/details/8177 ...

  7. java lowpoly低多边形风格图片生成

    lowpoly风格的图片生成,java实现. 闲着没事干刷知乎,刷到这样一个问题http://www.zhihu.com/question/29856775 看看觉得还是挺好看的,那么,我也想提高b格 ...

  8. Unity Shader(一) Lowpoly动态低多边形 (QQ登录界面低边动画)

    前言 在逛论坛的时候偶然发现有人在问动态低多边形(Lowpoly)是如何实现的,因为经常编写UGUI拓展对顶点操作较为熟悉的我立马就想到利用继承UnityEngine.Graphic,重写OnPopu ...

  9. UnityShader基础案例(三)——外发光(泛光)和内发光

    基于菲涅尔反射来判断边缘所在. Shader "Custom/Test0" {Properties{_MainColor("主颜色",Color)=(0,0,0 ...

  10. UnityShader(三)基础多光照+遮罩Shader

    遮罩的原理很简单,就是用一张存储着遮罩信息的遮罩纹理来计算出片元的遮罩系数,在之前的高光反射上乘于这个系数,就能得到遮罩效果了. Shader "Custom/BaseLight&M ...

最新文章

  1. 一文读懂RocketMQ的存储机制
  2. 【转】QT事件传递与事件过滤器
  3. MyBatis设计模式总结
  4. 【完整流程】用VSCode替换Vivado默认编辑器
  5. ESP32 开发之旅② Arduino For ESP32说明
  6. CentOS 6.5 64位 安装zabbix-2.2.0
  7. vi修改文件格式编码(从dos改为unix)
  8. 盘古开源:汽车芯片短缺怎样缓解?工信部回应热点问题
  9. 字符串切分,stream,JSONObject,lambda表达式的应用
  10. tree traversal (树的遍历) - inorder traversal (中序遍历)
  11. 基于SSM的生产计划排程管理系统
  12. 帝国CMS仿玩游戏网源码大型游戏资讯网站源码
  13. Oracle数据库 表空间
  14. android 来电显示号码,android监控来电显示
  15. 河南省谷歌地球高程DEM等高线下载
  16. CS0120 对象引用对于非静态的字段、方法或属性XX是必需的
  17. 《Python从小白到大牛》第2篇 开发环境搭建
  18. App-V软件排序参考之(二):Office 2007英文版+多国语言包 (1)
  19. Pixy CMUcam5图像处理简介
  20. FPGA实例06——FPGA驱动超声波模块

热门文章

  1. 宇宙扛把子(原创勿删)
  2. twitter系统架构
  3. 怎么看vue中某个插件是否安装成功_如何在谷歌中查看VUEX(谷歌浏览器中安装 vue调试工具 vue-devtools)...
  4. window android sd卡,如何修复在Windows/Android设备中不能被识别的Micro SD卡?
  5. 使用dd命令烧写linux系统到sd卡
  6. Android之间互相的录屏直播 --点对点传输(tcp长连接发送h264)(一)
  7. 编译Android系统源码--搭建环境
  8. 流行和声(6)mMaj7和弦
  9. MULTIPLE CALL TO SEGMENT
  10. ISO 13400(DoIP)标准解读