作者:死性Oo不改2502917357 | 来源:互联网 | 2023-05-22 17:35
文章目录在Unity中实现三渲二,我尝试从两个途径去实现,一个是用Unity官方的可视化着色器插件shadergraph实现一.ShaderGraphshadergraph搭建设置
文章目录
- 在Unity中实现三渲二,我尝试从两个途径去实现,一个是用Unity官方的可视化着色器插件shadergraph实现
- 一.ShaderGraph
- shadergraph搭建设置请自行百度
- 最后将三个模块得到的颜色信息加起来,就能获得结果了。
- 二,使用shaderlab即编写shader代码,自由度很高,就是上手有点难。
在Unity中实现三渲二,我尝试从两个途径去实现,一个是用Unity官方的可视化着色器插件shadergraph实现
一.ShaderGraph
shadergraph搭建设置请自行百度
![《[Unityshader]在unity中尝试实现三渲二的效果》](https://img7.php1.cn/3cdc5/cc8a/42f/872225c3b05bf1e3.png)
我们先看下效果图,没有很多复杂的效果,从最简单的只有一盏光源考虑。
![《[Unityshader]在unity中尝试实现三渲二的效果》](https://img7.php1.cn/3cdc5/cc8a/42f/e1cc0f318f58d44e.gif)
在shadergraph中我们无法简单的获取光源信息,如果想要获取光源信息,需要实现自定义节点来获取光源的信息,太过复杂,所以我们先假定一个光源的方向。
给出shader图。
图有点大,看不清,我们一个组一个组来讲解。
可以看到图上分了三大块。
三大块分别为:
- diffuse漫反射
- highlight高光
- border边缘线
先看漫反射:![《[Unityshader]在unity中尝试实现三渲二的效果》](https://img7.php1.cn/3cdc5/cc8a/42f/b62f80e12d8c3f92.png)
漫反射比较简单,首先对于方向向量都要归一化(normalize),因为这样点积得到的结果才能在-1,1区间。将光和物体世界坐标的法向量点乘,得到两个向量的余弦值,以此来模拟漫反射,由于我们是想要实现二次元效果所以,不能有过渡,所以我们要使用step函数消除过渡:将大于x的值置为1,将小于x的值置为0。随后,我们希望暗部的亮度值是可以控制的,我们引入自定义属性darkSideValue(dsv)来控制结果,首先我们将得到的结果使用OneMinus(1-输入的值)节点来进行反转,这样暗部就为1,亮部为0,此时将值乘上dSV就能够改变暗部的亮度了。(图中还考虑了环境光的亮度能影响到暗部,所以先把暗部值乘上了ambient的亮度,或许改为加会好一些。)然后我们把反转后的值加回没反转之前(不用担心亮部值会爆出,因为dsv值的亮部为0),最后将结果乘上物体本身的固有色贴图采样。
再来看看高光
高光部分前面和大部分着色器一样处理,需要注意的是,Viewdirection节点获得的摄像机视角并没有归一化,需要先进行归一化处理,不然会得到很奇怪的结果。我们将使用reflection节点将光源以物体表面法线反射出去,将这个向量和摄像机视角做点乘,得到的值仍然需要使用step去过渡,得到了高光区域后,我们可以考虑使用贴图的alpha通道来改变高光的显示,使得高光能够表现出物体的结构。
最后看下边缘处理![《[Unityshader]在unity中尝试实现三渲二的效果》](https://img7.php1.cn/3cdc5/cc8a/42f/e8819ce9f7d25a66.png)
由于是在shadergraph中所以我们无法对一个物体进行多个pass渲染,只好使用边缘光的方式来模拟描边,我们可以使用菲涅尔节点来获取物体的菲涅尔信息。然后对这个值进行step处理,不过这样的结果得到的边缘是亮形式的,我们往往希望描边是黑色的,于是进行了OneMinus处理进行反转,最后将这个值乘上边缘颜色。
最后将三个模块得到的颜色信息加起来,就能获得结果了。
二,使用shaderlab即编写shader代码,自由度很高,就是上手有点难。
大部分思想和上面一样,描边原理不一样,这里采用的描边是先用一个pass去渲染物体的背面,同时把物体的体积扩大。再用一个pass绘制正常的物体。
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
// Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
Shader "Unlit/anim"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_LightTex("HighlightTex",2D)="white"{}
_BorderEdge("borderEgde",Range(-1,1))=0
_BaseColor("baseColor",Color)=(1,1,1,1)
_DarkSideBrightness("dsBrightness",Range(0,1))=1
_HighLightEdge("highLightEdge",Range(-1,1))=0
_Factor("factor",Range(0,0.1)) = 0.01 //描边粗细因子
_OutLineColor("outline color",Color) = (0,0,0,1)//描边颜色
}
SubShader
{
Tags { "RenderType"="ForwardBase" }
LOD 100
Pass
{
Cull Front //剔除前面
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct v2f
{
float4 vertex :POSITION;
};
float _Factor;
half4 _OutLineColor;
v2f vert(appdata_full v)
{
v2f o;
//将顶点沿法线方向向外扩展一下
v.vertex.xyz += v.normal * _Factor;
o.vertex = UnityObjectToClipPos(v.vertex);
return o;
}
half4 frag(v2f v) :COLOR
{
//只显示描边的颜色
return _OutLineColor;
}
ENDCG
}
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "Lighting.cginc"
float _BorderEdge;
sampler2D _MainTex;
sampler2D _LightTex;
float4 _MainTex_ST;
float4 _LightTex_ST;
fixed4 _BaseColor;
float _DarkSideBrightness;
float _HighLightEdge;
float _HighLightPower;
struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
float2 uv:TEXCOORD0;
};
struct v2f
{
float2 uv:TEXCOORD0;
float3 worldNormal:TEXCOORD1;
float3 worldPos:TEXCOORD2;
float4 vertex : POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex=UnityObjectToClipPos(v.vertex);
o.worldPos = mul(unity_ObjectToWorld,v.vertex).xyz;//获取世界空间的顶点位置
o.worldNormal=mul(unity_ObjectToWorld,v.normal);//获取世界空间的法线向量
o.uv=TRANSFORM_TEX(v.uv,_LightTex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
fixed3 lightTex=tex2D(_LightTex,i.uv);
float3 lightDir=normalize(UnityWorldSpaceLightDir(i.worldPos));
float3 viewDir=normalize(UnityWorldSpaceViewDir(i.worldPos));
// sample the texture
float3 worldNormal=normalize(i.worldNormal);
float diffuseV=dot(worldNormal,lightDir);
float diffStep=step(_BorderEdge,diffuseV);
float tmp=1-diffStep;
float ds=tmp*_DarkSideBrightness;
float highLightV=dot(viewDir,reflect(-lightDir,worldNormal));
float hlvSp=step(_HighLightEdge,highLightV);
fixed4 dsColor=(UNITY_LIGHTMODEL_AMBIENT+ds*_BaseColor);
return _LightColor0*_BaseColor*diffStep+dsColor+hlvSp*fixed4(1,1,1,1)*_LightColor0*fixed4(lightTex,1);
}
ENDCG
}
}
Fallback "Specular"
}