UnityShader-LowPoly
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相关推荐
- UnityShader入门精要-3.3 UnityShader的结构
一个UnityShader的基础结构如下所示: Shader "ShaderName"{Properties{//属性 } SubShader{//显卡A使用的子着色器 }SubS ...
- thymeleaf动态选中select_一些LowPoly动态渐变效果实现
这篇文章根大家分享一些LowPoly动态效果的制作方法,由于使用的是uv采样方式效率很高,手机也可以随意使用,我们先来看一些效果的参考 本文将在Unity3D中还原这些效果,如果你学会后当然可以在你喜 ...
- UnityShader之遮挡透明
UnityShader之遮挡透明 好久没写博客了,最近在学shader,不得不说,shader真的非常美妙,我沉迷其中无法自拔= = 之前做过一个遮挡透明的功能,当物体遮挡住主角时,该物体会变成半透明 ...
- UnityShader例子:边缘检测
一.边缘检测 没有什么新的东西,只需了解<UnityShader26:运动模糊>这一章里面的内容就好 1):Roberts算子: 本质就是计算左上角和右下角的差值,乘上右上角和左下角的插值 ...
- UnityShader4:UnityShader的形式
前置:UnityShader2:Shader与材质 一.Standard Surface Shader 代码解析 在前置中已经了解了什么是表面着色器,下面这是 Standard Surface Sha ...
- [UnityShader基础]06.#pragma multi_compile
[UnityShader基础]06.#pragma multi_compile 参考链接: https://blog.csdn.net/qq826364410/article/details/8177 ...
- java lowpoly低多边形风格图片生成
lowpoly风格的图片生成,java实现. 闲着没事干刷知乎,刷到这样一个问题http://www.zhihu.com/question/29856775 看看觉得还是挺好看的,那么,我也想提高b格 ...
- Unity Shader(一) Lowpoly动态低多边形 (QQ登录界面低边动画)
前言 在逛论坛的时候偶然发现有人在问动态低多边形(Lowpoly)是如何实现的,因为经常编写UGUI拓展对顶点操作较为熟悉的我立马就想到利用继承UnityEngine.Graphic,重写OnPopu ...
- UnityShader基础案例(三)——外发光(泛光)和内发光
基于菲涅尔反射来判断边缘所在. Shader "Custom/Test0" {Properties{_MainColor("主颜色",Color)=(0,0,0 ...
- UnityShader(三)基础多光照+遮罩Shader
遮罩的原理很简单,就是用一张存储着遮罩信息的遮罩纹理来计算出片元的遮罩系数,在之前的高光反射上乘于这个系数,就能得到遮罩效果了. Shader "Custom/BaseLight&M ...
最新文章
- 一文读懂RocketMQ的存储机制
- 【转】QT事件传递与事件过滤器
- MyBatis设计模式总结
- 【完整流程】用VSCode替换Vivado默认编辑器
- ESP32 开发之旅② Arduino For ESP32说明
- CentOS 6.5 64位 安装zabbix-2.2.0
- vi修改文件格式编码(从dos改为unix)
- 盘古开源:汽车芯片短缺怎样缓解?工信部回应热点问题
- 字符串切分,stream,JSONObject,lambda表达式的应用
- tree traversal (树的遍历) - inorder traversal (中序遍历)
- 基于SSM的生产计划排程管理系统
- 帝国CMS仿玩游戏网源码大型游戏资讯网站源码
- Oracle数据库 表空间
- android 来电显示号码,android监控来电显示
- 河南省谷歌地球高程DEM等高线下载
- CS0120 对象引用对于非静态的字段、方法或属性XX是必需的
- 《Python从小白到大牛》第2篇 开发环境搭建
- App-V软件排序参考之(二):Office 2007英文版+多国语言包 (1)
- Pixy CMUcam5图像处理简介
- FPGA实例06——FPGA驱动超声波模块
热门文章
- 宇宙扛把子(原创勿删)
- twitter系统架构
- 怎么看vue中某个插件是否安装成功_如何在谷歌中查看VUEX(谷歌浏览器中安装 vue调试工具 vue-devtools)...
- window android sd卡,如何修复在Windows/Android设备中不能被识别的Micro SD卡?
- 使用dd命令烧写linux系统到sd卡
- Android之间互相的录屏直播 --点对点传输(tcp长连接发送h264)(一)
- 编译Android系统源码--搭建环境
- 流行和声(6)mMaj7和弦
- MULTIPLE CALL TO SEGMENT
- ISO 13400(DoIP)标准解读