当前位置:网站首页>UnityShader-LowPoly
UnityShader-LowPoly
2022-07-27 05:21:00 【122&&113】
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 One
CGPROGRAM
#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,学习之路无止境啊~~~
边栏推荐
- What tools are needed to make video post effects?
- 剪枝-量化-转onnx中文系列教程
- C语言-文件操作
- What has been updated in the Chinese version of XMIND mind map 2022 v12.0.3?
- Greedy high performance neural network and AI chip application research and training
- AE 3D粒子系统插件:Trapcode Particular
- [song] rebirth of me in py introduction training (5): List
- 编程学习记录——第8课【数组与设计五子棋,扫雷游戏】
- 力扣题解 动态规划(7)
- 韦东山 数码相框 项目学习(三)freetype的移植
猜你喜欢
随机推荐
1半自动爬虫
Unity 窗口界面的简单介绍
IOT operating system
物联网操作系统
std::bind与std::function的一些应用
编程学习记录——第8课【数组与设计五子棋,扫雷游戏】
Day 2. Depressive symptoms, post-traumatic stress symptoms and suicide risk among graduate students
Acwing the number of square arrays of one question per day
What has been updated in the Chinese version of XMIND mind map 2022 v12.0.3?
[headline] Rebirth: the basis of CNN image classification
AE 3D particle system plug-in: Trapcode particle
C#文件的读写
安全帽反光衣检测识别数据集和yolov5模型
这是我的博客
[first song] Introduction to data science of rebirth -- return to advanced level
常见的SQL优化方法
Unity Hub登录无响应
Weidongshan digital photo frame project learning (III) transplantation of freetype
[first song] machine learning of rebirth - linear regression
力扣题解 动态规划(5)









