本篇主要用于记录自己的实战操作,以及一些碎碎念(观后感),如果有什么好想法或者本篇出现什么错误,请多指教~
本篇的内容参考视频:庄懂的技术美术入门课(美术向)
使用软件:Unity 2019 3.6f1 ,ShaderForge
本篇内容主要包括:赛博小人制作及相关知识点总结;
1.模型准备
首先还是先对顶点着色,以便之后仅对身体产生变换;
再来导出两份UV,左边是叠加的,右边是整理好的;
为了得到网格效果,专门渲染一张纯黑白的网格图,然后右边的图则是在Alpha通道里用于UV分块
2.SD中准备
基于UV1烘焙一张位置信息图;
然后根据需求制作三张贴图,一张经描边处理再反向的网格图,一张乱序的类似麻袋的面随机灰度遮罩图,一张面坡度遮罩图,然后存到一张RGBA图中;
最后的节点图如下:
还有一张用位置信息加噪波扰动的图:
3.shader编写
最后代码:
Shader "Unlit/co18-cyber"
{
Properties
{
[Header(Texture)]
_MainTex ("RGB:基础颜色,A:环境遮罩", 2D) = "white" {}//这里将AO贴图与颜色贴图整合到了一张图里
_NormalTex ("RGB:法线贴图",2D) = "bump" {}
_SpecTex ("RGB:高光颜色,A:高光次幂",2D) = "gray" {}
_EmitTex ("RGB:自发光贴图",2d) = "black" {}
_Cubemap ("RGB:环境贴图Cubemap",Cube) = "_Skybox" {}
[Header(Diffuse)]
_BaseColor ("基础颜色",color) = (1.0,1.0,1.0,1.0)
_EnvUpColor ("环境天顶颜色",color) = (1.0,1.0,1.0,1.0)
_EnvMidColor ("环境侧部颜色",color) = (1.0,1.0,1.0,1.0)
_EnvDowColor ("环境底部颜色",color) = (1.0,1.0,1.0,1.0)
_EnvDiffuse ("环境漫反射强度",range(0,1)) = 0.2
[Header(Specular)]
_SpecularPow ("高光次幂",range(1,90)) = 25
_EnvSpecInt ("高光强度",range(0,5)) = 1
_FresenlPow ("菲涅尔次幂",range(0,10)) = 3
_CubemapMip ("环境球Mip",range(0,7)) = 0
[Header(Emission)]
_Emitint ("自发光强度",range(1,10)) = 5
[Header(Effect)]
_Effmap01 ("特效纹理1",2D) = "gray"{}
_Effmap02 ("特效纹理2",2D) = "gray"{}
[HDR] _Effcol ("光效颜色",color) = (0.0,0.0,0.0,0.0)
_EffParams ("X:波密度 Y:波速度 Z:混乱度 W:消散强度",vector)=(0.03,3.0,0.3,2.5)
}
SubShader
{
Tags { "Queue"="Transparent"
"RenderType"="Transparent" }
Pass
{
Tags {"LightMode"="ForwardBase"}
Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma multi_compile_fwdbase_fullshadows
#pragma target 3.0
#include "UnityCG.cginc"
#include "Lighting.cginc"
#include "AutoLight.cginc"
uniform sampler2D _MainTex;
uniform sampler2D _NormalTex;
uniform sampler2D _SpecTex;
uniform sampler2D _EmitTex;
uniform samplerCUBE _Cubemap;
uniform float3 _BaseColor;
uniform float3 _EnvUpColor;
uniform float3 _EnvMidColor;
uniform float3 _EnvDowColor;
uniform float3 _EnvDiffuse;
uniform float _SpecularPow;
uniform float _EnvSpecInt;
uniform float _FresenlPow;
uniform float _CubemapMip;
uniform float _Emitint;
uniform sampler2D _Effmap01;
uniform sampler2D _Effmap02;
uniform float3 _Effcol;
uniform float4 _EffParams;
struct appdata
{
float4 vertex : POSITION;
float4 normal : NORMAL;
float4 tangent:TANGENT;
float2 uv : TEXCOORD0;
float2 uv1: TEXCOORD1;
float4 color : COLOR;
};
struct v2f
{
float2 uv : TEXCOORD0;
float2 uv1 : TEXCOORD1;
float4 color : COLOR;
float4 pos : SV_POSITION;
float3 posWS : TEXCOORD2;
float3 nDirWS : TEXCOORD3;
float3 bDirWS : TEXCOORD4;
float3 tDirWS : TEXCOORD5;
float4 effectMask : TEXCOORD6;
LIGHTING_COORDS(7,8)
};
float4 CyberpunkAnim(float noise,float mask, float3 normal,inout float3 vertex){
float baseMask = abs(frac(vertex.y*_EffParams.x-_Time.x*_EffParams.y)-0.5)*2.0;//锯齿波mask
baseMask = min(1.0,baseMask*2.0);
baseMask += (noise-0.5)*_EffParams.z;//Noise偏移锯齿波
float4 effectMask= float4(0.0,0.0,0.0,0.0);
effectMask.x = smoothstep(-0.2,0.9,baseMask);//smoothstep重映射波形平滑
effectMask.y = smoothstep(0.2,0.7,baseMask);
effectMask.z = smoothstep(0.4,0.5,baseMask);
effectMask.w = mask;//顶点色存入EffectMask
vertex.xz += normal.xz*(1.0-effectMask.y)*_EffParams.w*mask;
return float4(effectMask);
}
v2f vert (appdata v)
{
v2f o;
float noise =tex2Dlod(_Effmap02,float4(v.uv1,0.0,0.0));//tex2Dlod顶点着色器中采样纹理,也可采样Mipmap
o.effectMask=CyberpunkAnim(noise,v.color.r,v.normal.xyz,v.vertex.xyz);
o.uv = v.uv;
o.uv1 = v.uv1;
o.pos = UnityObjectToClipPos(v.vertex);
o.posWS = mul(unity_ObjectToWorld,v.vertex);
o.nDirWS = UnityObjectToWorldNormal(v.normal);
o.tDirWS = normalize(mul(unity_ObjectToWorld,float4(v.tangent.xyz,1.0)));
o.bDirWS = normalize(cross(o.nDirWS,o.tDirWS));
TRANSFER_VERTEX_TO_FRAGMENT(o)
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float3 nDirTS = UnpackNormal(tex2D(_NormalTex,i.uv));
float3x3 TBN = float3x3(i.tDirWS,i.bDirWS,i.nDirWS);
float3 nDirWS = normalize(mul(nDirTS,TBN));
float3 lDir = _WorldSpaceLightPos0;
float3 vDir = normalize(_WorldSpaceCameraPos-i.posWS.xyz);
float3 vrDir = reflect(-vDir,nDirWS);
float3 lrDir = reflect(-lDir,nDirWS);
float3 ndotl = dot(nDirWS,lDir); //兰伯特
float3 ndotv = dot(nDirWS,vDir); //菲涅尔
float3 vdotlr = dot(vDir,lrDir); //Phong
float4 var_MainTex = tex2D(_MainTex,i.uv);
float4 var_SpecTex = tex2D(_SpecTex,i.uv);
float3 var_EmitTex = tex2D(_EmitTex,i.uv);
float3 var_Cubemap = texCUBElod(_Cubemap,float4(vrDir,lerp(_CubemapMip,1.0,var_SpecTex.a)));//lerp用来表现越光滑反射越清晰
float Lambert = max(ndotl,0);
float spect = lerp(1,_SpecularPow,var_SpecTex.a);//用lerp做插值
float Phong = pow(max(0,vdotlr),spect);
float shadow = LIGHT_ATTENUATION(i);
float3 dirtLight = (Lambert*_BaseColor*var_MainTex.rgb + Phong*var_SpecTex.rgb)*shadow*_LightColor0;
float topmask = max(nDirWS.g,0.0);
float dowmask = max(-nDirWS.g,0.0);
float midmask = 1.0-topmask-dowmask;
float3 col3 = topmask*_EnvUpColor+midmask*_EnvMidColor+dowmask*_EnvDowColor;
float fresnel = pow(max(1-ndotv,0.0),_FresenlPow);
float occluision = var_MainTex.a;
float Envlighting = (_BaseColor*var_MainTex.rgb*col3*_EnvDiffuse+var_Cubemap*fresnel*_EnvSpecInt)*occluision;
float3 emission = var_EmitTex*_Emitint;
float3 _Effmap01_var = tex2D(_Effmap01,i.uv1).xyz;
float meshMask = _Effmap01_var.x;
float faceRandomMask= _Effmap01_var.y;
float facesSlopeMask= _Effmap01_var.z;
float smallMask = i.effectMask.x;
float midMask = i.effectMask.y;
float bigMask = i.effectMask.z;
float baseMask = i.effectMask.w;
float midOpacity =saturate(floor(min(faceRandomMask,0.99999)+midMask));
float bigOpacity =saturate(floor(min(facesSlopeMask,0.99999)+bigMask));
float Opacity =lerp(1.0,min(bigOpacity,midOpacity),baseMask);
float meshEmitInt =(bigMask-smallMask)*meshMask;
meshEmitInt *=meshEmitInt;
emission +=_Effcol*meshEmitInt*baseMask;
float3 final = dirtLight+Envlighting+emission;
return float4(final*Opacity,Opacity);
}
ENDCG
}
}
}
效果展示:
4.补充
1.关于锯齿问题:
扰动造成的,可以给扰动的负值做下限制
2.“最后的输出结果模型上应该不透明的地方会有些半透不透的感觉”
因为是在顶点阶段做的 到像素shader会做差值 所以黑白交界的面是有过渡的