前期准备
模型准备
为了得到网格效果,专门渲染一张纯黑白的网格图,然后右边的图则是在Alpha通道里用于UV分块
在SD中准备UV1:3D位置信息图
在SD中中制作UV2
R:网格线;
G按模型灰度随机Bias透明度;
B:坡度值(从边缘到中间坡度);
A纯色(无信息)
编写Shading
顶点动画的方法
前面都是基础操作遵循PPT即可,下面着重讲一下顶点动画的方法
追加小人顶点动画方法
//动画方法 noise:偏移噪声;mask:基座遮罩;normal:模型法线;vertex:模型顶点位置(inout) 返回effct相关遮罩
float4 CyberpunkAnim(float noise,float mask, float3 normal,inout float3 vertex)
锯齿波mask
float baseMask = abs(frac(vertex.y*_EffParams.x-_Time.x*_EffParams.y)-0.5)*2.0;
baseMask = min(1.0,baseMask*2.0);
- 因为所需效果是从下到上所以取Y轴(vertex.y)
- 再用函数frac取小数部分,此时范围是(-1,1)
- -0.5,此时范围是(-0.5,0.5)
- 加绝对值(0,0.5)
- *2 (0,1)
- 把Y轴(vertex.y)*_Time.x(时间)*_EffParams.y(波速度)*_EffParams.x(波密度)
- 把刚刚得到的结果*2(0,2)再把结果和1比较取较小的(使黑色时间比白色时间少,不透明时间更多,透明时间更少)
Noise偏移锯齿波
baseMask += (noise-0.5)*_EffParams.z;
因为noise从纹理里采样所以值域是(0,1),做相加偏移只会加不会减,把值域-0.5(-0.5,0.5)有加有减这时候偏移才会合理错开,再*_EffParams.z(混乱度)
smoothstep重映射波形平滑
float4 effectMask = float4(0,0,0,0)
effectMask.x = smoothstep(0,0.9,baseMask);
effectMask.y = smoothstep(0.2,0.7,baseMask);
effectMask.z = smoothstep(0.4,0.5,baseMask);
把RGB通道存在范围不同的三个通道里
将顶点色遮罩存入EffectMask
effectMask.w = mask;
把基座遮罩存到w分量
计算顶点动画
vertex.xz += normal.xz*(1.0-effectMask.y)*_EffParams.w*mask;
只在xz轴偏移也就是平着散出去,如果是三维太乱了;
给每个顶点一个增量;我们需要的效果是让透明的地方膨胀带动着不透明的地方(黑色透明,白色不透明),也就是让半透的地方膨胀,也就是刚刚计算的EffectMask的反向,经测试y也就是棕色区域效果最好;
乘以_EffParams.w(消散强度)和基座的mask(顶点色)
顶点动画部分完整代码,老师PPT
像素Shader
采样EffMap02
float3 _Effmap01_var = tex2D(_Effmap01,i.uv1).xyz;
float meshMask = _Effmap01_var.x;
float faceRandomMask= _Effmap01_var.y;
float facesSlopeMask= _Effmap01_var.z;
把图的各个通道信息给缓存起来
获取EffectMask
float smallMask = i.effectMask.x;
float midMask = i.effectMask.y;
float bigMask = i.effectMask.z;
float baseMask = i.effectMask.w;
把顶点effect数据缓存
计算Opacity
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);
midOpacity
方格随机灰度图(G通道),用min把值域从(0,1)限制到(0,0.99999);
加上Noise偏移锯齿波(midMask)把两个相加值域是(0,1.99999);
再使用函数floor二分处理,如果大于1就白色不透明,小于1就纯透明,没有半透明。
给一个值保护(0,1)之间
随机性+随机性结果,如左图
bigOpacity
面坡度值(B通道),在单独一个面上有坡度变化,从面边缘慢慢消散到面中心。
方法和上面一样不再赘述
Opacity(把两种混合)
把midOpacity ,bigOpacity 混合取最小;
lerp基座mask,使基座永远是实的
叠加自发光
float meshEmitInt =(bigMask-smallMask)*meshMask;
meshEmitInt *=meshEmitInt;
emit +=_Effcol*meshEmitInt*baseMask;
希望在半透明的地方产生自发光,用大范围减小范围,乘以网格线(meshMask);但是范围有点大,自然而然就想了Power但是太费了,我们就自己乘自己相当于Power 2得到了我们想要的效果;再把自发光强度*自发光颜色再*基座
返回结果
float3 final = finalRGb+envLighting+emit;
最终效果以及代码
Shader "Unlit/cyber" {
Properties {
[Header(Texture)]
_MainTex("基础贴图",2d)="white"{}
_NormalTex("法线贴图",2d)="bump"{}
_OcclusionTex("AO贴图",2d)="white"{}
_EmitTex("自发光贴图",2d)="black"{}
_CubeMap("环境贴图",cube)="skybox"{}
_SpecTex("高光贴图",2d)="gery"{}
[Header(Diffuse)]
_MainCol ("基础颜色",color) =(0,0,0,0)
_EnvUpCol ("环境天顶颜色",color) =(1,1,1,1)
_EnvDownCol ("环境地表颜色",color) =(0.5,0.5,0.5,1.0)
_EnvSideCol ("环境水平颜色",color) =(0,0,0,0)
_EnvColInt ("环境漫反射强度",Range(0,1))=0.5
[Header(Specular)]
_SpecPow ("高光次幂",Range(1,90)) =30
_FransnalPow("菲涅尔次幂",Range(1,10))=3
_EnvSpecInt("环境镜面反射强度",Range(0,10))=2
_CubemapMip("环境球Mip",range(0,7))=1
_EmitInt("自发光强度",Range(1,10))=1
_threshold("抖动值",Range(0,1.01))=0.5
[Header(Effect)]
_Effmap01("特效纹理1",2D)="gray"{}
_Effmap02("特效纹理2",2D)="gray"{}
[HDR]_Effcol("光效颜色",color)=(0,0,0,0)
_EffParams("X:波密度 Y:波速度 Z:混乱度 W:消散强度",vector)=(0.03,3.0,0.3,2.5)
}
SubShader {
Tags {
"RenderType"="transparent" "Queue"="transparent"
}
LOD 100
Pass {
Name "FORWARD"
Tags {
"LightMode"="ForwardBase"
}
Blend One OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
//包含文件
#include "Lighting.cginc"
#include "AutoLight.cginc"
#include "../CG include/My cginc.cginc"
#pragma multi_compile_fwdbase_fullshadows
#pragma multi_compile_fog
#pragma target 3.0
//Texture
uniform sampler2D _MainTex;
uniform sampler2D _NormalTex;
uniform sampler2D _OcclusionTex;
uniform sampler2D _EmitTex;
uniform samplerCUBE _CubeMap;
uniform samplerCUBE _SpecTex;
//Diffuse
uniform float3 _EnvDownCol;
uniform float3 _EnvUpCol;
uniform float3 _EnvSideCol;
uniform float3 _MainCol;
uniform float _EnvColInt;
//Specular
uniform float _SpecPow;
uniform float _FransnalPow;
uniform float _EnvSpecInt;
uniform float _CubemapMip;
uniform float _EmitInt;
float _threshold;
//Effect
uniform sampler2D _Effmap01;
uniform sampler2D _Effmap02;
float3 _Effcol;
float4 _EffParams;
//输入结构
struct VertexInput {
float4 vertex : POSITION;
float2 uv0 :TEXCOORD0;
float2 uv1 :TEXCOORD1;
float4 normal :NORMAL;
float4 tangent:TANGENT;
float4 color :COLOR;
};
//输出结构
struct VertexOutput {
float4 pos:SV_POSITION;
float2 uv0 :TEXCOORD0;
float4 posWS:TEXCOORD1;
float3 tDirWS:TEXCOORD2;
float3 bDirWS:TEXCOORD3;
float3 ndirWS:TEXCOORD4;
float2 uv1:TEXCOORD5;
float4 effectMask :TEXCOORD6;
LIGHTING_COORDS(7,8)
};
//动画方法 noise:偏移噪声;mask:基座遮罩;normal:模型法线;vertex:模型顶点位置(inout) 返回effct相关遮罩
float4 CyberpunkAnim(float noise,float mask, float3 normal,inout float3 vertex){
//锯齿波mask
float baseMask = abs(frac(vertex.y*_EffParams.x-_Time.x*_EffParams.y)-0.5)*2.0;
baseMask = min(1.0,baseMask*2.0);
//Noise偏移锯齿波
baseMask += (noise-0.5)*_EffParams.z;
//smoothstep重映射波形平滑
float4 effectMask = float4(0,0,0,0);
effectMask.x = smoothstep(0,0.9,baseMask);
effectMask.y = smoothstep(0.2,0.7,baseMask);
effectMask.z = smoothstep(0.4,0.5,baseMask);
//将顶点色遮罩存入EffectMask
effectMask.w = mask;
//计算顶点动画
vertex.xz += normal.xz*(1.0-effectMask.y)*_EffParams.w*mask;
return effectMask;
}
//输入结构>>>顶点Shader>>>输出结构
VertexOutput vert (VertexInput v) {
//采样纹理。tex2Dlod顶点着色器中采样纹理,也可采样Mipmap
float noise =tex2Dlod(_Effmap02,float4(v.uv1,0.0,0.0)).r;
//输出结构
VertexOutput o = (VertexOutput)0;
//计算顶点动画 同时获取EffectMask
o.effectMask=CyberpunkAnim(noise,v.color.r,v.normal.xyz,v.vertex.xyz);
o.pos=UnityObjectToClipPos(v.vertex);
o.uv0=v.uv0;
o.uv1=v.uv1;
o.posWS=mul(unity_ObjectToWorld,v.vertex);
o.ndirWS = UnityObjectToWorldNormal(v.normal);
o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz, 1.0)).xyz);
o.bDirWS = normalize(cross(o.ndirWS, o.tDirWS));
TRANSFER_VERTEX_TO_FRAGMENT(o)//投影
return o;
}
//输出结构>>>像素
float4 frag(VertexOutput i) : COLOR {
//向量准备
float3 nDirTS =UnpackNormal(tex2D(_NormalTex,i.uv0)).rgb;
float3x3 TBN =float3x3(i.tDirWS,i.bDirWS,i.ndirWS);
float3 ndirWS = normalize(mul(nDirTS, TBN));
float3 lDirWS =_WorldSpaceLightPos0.xyz;
float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWS.xyz);
float3 vrDirWS = reflect(vDirWS,ndirWS);
//中间量准备
float vrdir=dot(vrDirWS,-lDirWS);
float ndotv = dot(ndirWS,vDirWS);
//纹理采样
float4 var_MainTex=tex2D(_MainTex,i.uv0);
//float4 var_SpecTex=tex2D(_SpecTex,i.uv0);
float3 var_CubeMap= texCUBElod(_CubeMap,float4(vrDirWS,_CubemapMip));
float3 var_OcclusionTex=tex2D(_OcclusionTex,i.uv0);
float3 var_EmitTex=tex2D(_EmitTex,i.uv0);
//光照模型
//光源漫反射
float3 basecol =var_MainTex*_MainCol;
float lambert=max(0.0,dot(ndirWS,lDirWS));
//光源镜面反射
//float var_specPow=lerp(1,_SpecPow,var_SpecTex);
float phone =pow(max(0,vrdir),_SpecPow);
//光源混合
float shadow = LIGHT_ATTENUATION(i);
float3 dirLighting =(basecol*lambert)*_LightColor0*shadow;
//环境漫反射
float3 envCol = TriColAmbient(ndirWS,_EnvUpCol,_EnvDownCol,_EnvSideCol);
float3 EnvDiff =_EnvColInt*envCol*basecol;
//环境镜面反射
float fresnel =pow(max(0,1-ndotv),_FransnalPow);
float3 EnvSpec=var_CubeMap*fresnel*_EnvSpecInt;
//环境反射混合
float3 envLighting=(EnvSpec+EnvDiff)*var_OcclusionTex;
//自发光
float3 emit=_EmitInt*var_EmitTex;
//输出
float3 finalRGb=envLighting+dirLighting+emit;
//特效部分
//采样EffMap02
float3 _Effmap01_var = tex2D(_Effmap01,i.uv1).xyz;
float meshMask = _Effmap01_var.x;
float faceRandomMask= _Effmap01_var.y;
float facesSlopeMask= _Effmap01_var.z;
//获取EffectMask
float smallMask = i.effectMask.x;
float midMask = i.effectMask.y;
float bigMask = i.effectMask.z;
float baseMask = i.effectMask.w;
//计算Opacity
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 =saturate(bigMask-smallMask)*meshMask;
meshEmitInt =meshEmitInt*meshEmitInt;
emit =emit+_Effcol*meshEmitInt*baseMask;
//返回结果
float3 final = finalRGb+envLighting+emit;
return float4(final*Opacity,Opacity);
}
ENDCG
}
}
FallBack "Diffuse"
}