整体效果展示:主要方案是对下面几张图做不同的处理
身体
基础颜色光照:主要贴图+卡通贴图+ramp图+法线图+光照图
金属度与高光,头发部分高光:光照图,头发部分用高光black图
深度边缘光:用额外pass DepthNormals 获取深度信息
描边:额外pass对描边进行处理,用光照图的a通道对不同区域做颜色区分
脸
方案:主要贴图+卡通贴图+ramp图+SDF+描边
需要用到的贴图
将光照图,ramp图的sRGB关闭,法线图Type改成法线
妮露基础图的a通道储存的是神之眼灰度信息
光照图的rba存储配饰信息,g通道储存AO信息
ramp图上五行是白天暗部颜色,下五行是夜晚暗部颜色
卡通图用来做底部光照体积
准备阶段
//数据准备
Properties
{
[Space][Space][Space][Space]
_AmbientColor ("基础颜色", Color) = (0.667,0.667,0.667,1)
_DiffuseColor ("漫反射颜色", Color) = (0.906,0.906,0.906,1)
_ShadowColor ("阴影颜色", Color) = (0.737,0.737,0.737,1)
[Space][Space][Space][Space]
_DiffuseTexFac("漫反射Fac",Range(0,1))=1
_DiffuseTex ("漫反射贴图", 2D) = "white" {}
[Space][Space][Space][Space]
_ToonTexFac("卡通Fac",Range(0,1))=1
_ToonTex ("卡通贴图", 2D) = "white" {}
[Space][Space][Space][Space]
_SphereTexHair ("头发高光", 2D) = "black" {}
_SphereHair("头发高光强度",Range(0,128))=68
[Space][Space][Space][Space]
_DoubleSided("双面",Range(0,1))=0
_Alpha("透明值",Range(0,1))=1
[Space][Space][Space][Space]
_MetalTex("金属贴图", 2D) = "black" {}
_SpecExpon("高光强度",Range(1,128))=58
_KsNorMetallic("非金属",Range(0,3))=1
_KsMetallic("金属度",Range(0,3))=1
[Space][Space][Space][Space]
_NormalMap("法线贴图", 2D) = "bump" {}
[Space][Space][Space][Space]
_ILM("光照贴图",2D)="black"{}
[Space][Space][Space][Space]
_RampTex("Ramp贴图", 2D) = "white" {}
_RampMapRow0("Ramp0",Range(1,5))=1
_RampMapRow1("Ramp1",Range(1,5))=4
_RampMapRow2("Ramp2",Range(1,5))=3
_RampMapRow3("Ramp3",Range(1,5))=5
_RampMapRow4("Ramp4",Range(1,5))=2
[Space][Space][Space][Space]
_OutlineOffset("描边值",Float)=0.0007
_OutlineMapColor0("描边颜色0",Color)=(0,0,0,0)
_OutlineMapColor1("描边颜色1",Color)=(0,0,0,0)
_OutlineMapColor2("描边颜色2",Color)=(0,0,0,0)
_OutlineMapColor3("描边颜色3",Color)=(0,0,0,0)
_OutlineMapColor4("描边颜色4",Color)=(0,0,0,0)
[Space][Space][Space][Space]
_rimStrength("边缘光宽度",Range(0,10))=0.8
_rimMax("边缘光强度",Range(0,20))=0.8
}
//准备pass,阴影和深度信息
Pass
{
Name"ShadowCaster"
Tags{"LightMode"="ShadowCaster"}
ZWrite On
ZTest LEqual
ColorMask 0
Cull off
HLSLPROGRAM
#pragma exclude_renderers gles gles3 glcore
#pragma target 4.5
//材质关键字
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
//显卡实例化
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
//管线配置关键字
#pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW
#pragma vertex ShadowPassVertex
#pragma fragment ShadowPassFragment
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//Shaders/LitInput.hlsl"
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//Shaders/ShadowCasterPass.hlsl"
ENDHLSL
}
Pass
{
Name"DepthNormals"
Tags{"LightMode"="DepthNormals"}
ZWrite On
Cull off
HLSLPROGRAM
#pragma exclude_renderers gles gles3 glcore
#pragma target 4.5
#pragma vertex DepthNormalsVertex
#pragma fragment DepthNormalsFragment
//材质关键字
#pragma shader_feature_local _NORMALMAP
#pragma shader_feature_local _PARALLAXMAP
#pragma shader_feature_local _ _DETAIL_MULX2 _DETAIL_SCALED
#pragma shader_feature_local_fragment _ALPHATEST_ON
#pragma shader_feature_local_fragment _SMODTHNESS_TEXTURE_ALBEDO_CHANNEL_A
//显卡实例化
#pragma multi_compile_instancing
#pragma multi_compile _ DOTS_INSTANCING_ON
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//Shaders/LitInput.hlsl"
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//Shaders/LitDepthNormalsPass.hlsl"
ENDHLSL
}
开始主题,准备好变体与顶点数据
Tags{"RenderPipeline"="UniversalPipeline"
"RenderType"="Opaque"
"LightMode"="UniversalForward"
}
Cull off
HLSLPROGRAM
#pragma multi_compile _MAIN_LIGHT_SHADOWS
#pragma multi_compile _MAIN_LIGHT_SHADOWS_CASCADE
#pragma multi_compile _SHADOWS_SOFT
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fog
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//ShaderLibrary/Core.hlsl"
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//ShaderLibrary/Lighting.hlsl"
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//ShaderLibrary/DeclareDepthTexture.hlsl"
#include "Library/PackageCache/com.unity.render-pipelines.universal@12.1.7//ShaderLibrary/Shadows.hlsl"
struct appdata
{
float4 vertex:POSITION ;
half3 normal:NORMAL ;
half4 tangent:TANGENT ;
float2 uv:TEXCOORD0 ;
half4 color:COLOR0 ;
};
struct v2f
{
float4 positionCS:SV_POSITION ;
float2 uv:TEXCOORD0 ;
float3 positionWS:TEXCOORD1;
float3 positionVS:TEXCOORD2;
float4 positionNDC:TEXCOORD3;
float3 normalWS:TEXCOORD4 ;
float3 tangentWS:TEXCOORD5 ;
float3 bitangentWS:TEXCOORD6 ;
float fogCooed:TEXCOORD7 ;
float4 shadowCooed:TEXCOORD8 ;
};
v2f vert(appdata v)
{
v2f o;
VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
o.uv = TRANSFORM_TEX(v.uv,_DiffuseTex);
o.positionWS=vertexInput.positionWS;
o.positionVS=vertexInput.positionVS;
o.positionCS=vertexInput.positionCS;
o.positionNDC=vertexInput.positionNDC;
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs(v.normal,v.tangent);
o.tangentWS = vertexNormalInput.tangentWS;
o.bitangentWS=vertexNormalInput.bitangentWS;
o.normalWS = vertexNormalInput.normalWS;
o.fogCooed=ComputeFogFactor(vertexInput.positionCS.z);
o.shadowCooed=TransformWorldToShadowCoord(vertexInput.positionWS);
return o;
}
URP中 非常便利的将需要的模型数据封装到了VertexPositionInputs中,可直接取出使用。 VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz); 注意雾和阴影的计算
接下来开始写片元着色器
准备好需要用到的函数
Light light =GetMainLight(i.shadowCooed);
float4 normalMap=tex2D(_NormalMap,i.uv);
float3 normalTS=float3(normalMap.ag*2-1,0);
normalTS.z=sqrt(1-dot(normalTS.xy,normalTS.xy));
float3 N=normalize(mul(normalTS,float3x3(i.tangentWS,i.bitangentWS,i.normalWS)));
float3 V=normalize(mul((float3x3)UNITY_MATRIX_I_V,i.positionVS*(-1)));
float3 L=normalize(light.direction);
float3 H=normalize(L+V);
float NoL=dot(N,L);
float NoH=dot(N,H);
float NoV=dot(N,V);
法线的xy分量储存在法线图的ag通道,将其映射到-1—1得到xy分量,z分量通过勾股定理算出,再乘以TBN矩阵将其转换到世界空间
视向量是将视线的反方向乘以视图矩阵的逆矩阵将其变换到世界空间(V矩阵是将世界坐标转换到观察坐标)
float3 normalVS=normalize(mul((float3x3)UNITY_MATRIX_V,N));
float2 matcapUV=normalVS.xy*0.5+0.5;
float4 baseTex=tex2D(_DiffuseTex,i.uv);
float4 toonTex=tex2D(_ToonTex,matcapUV);
float3 baseColor=_AmbientColor.rgb;
baseColor=saturate(lerp(baseColor,baseColor+_DiffuseColor.rgb,0.6));
baseColor=lerp(baseColor,baseColor*baseTex.rgb,_DiffuseTexFac);
baseColor=lerp(baseColor,baseColor*toonTex.rgb,_ToonTexFac);
再做法线matcap对toon图采样(matcap:将法线转换到视线空间,并计算到适合采样UV纹理的区间,进行采样。 问题:非物理,固定性无法与环境交互,倾向用于补光)
tex2D(sampler2D tex, float2 s)
函数,这是CG程序中用来在一张贴图中对一个点进行采样的方法
至此基础颜色部分完成,可以打开unity写写看。
明天进行光照部分
本文含有隐藏内容,请 开通VIP 后查看