前言
手游做效果,最担心的就是性能问题。只有在性能保证的情况下,做出效果才是最好的。
本文主要是介绍一种性能不错的效果,可以用来在某些情况下实现pdr的效果,而且性能很好。
本文适用于一些有shader基础的同学。
有想交流的同学请加入群302257246 。
作者个人csdn博客:哎柠檬茶
http://my.csdn.net/weixin_39235393?locationNum=0&fps=1
欢迎关注、交流!
效果展示
什么是matcap?
Matcap全称MaterialCapture(材质捕获)
是一种把光照信息存储在纹理,从而省略大量光照计算(只需要采样一张图),就可以实现有光的感觉。
优点确实是能出效果、非常省。
缺点是光照图是死的,难以使效果与环境产生交互。
适用的情况:比如现在很多手游的展示用场景,基本上场景不会出现太大的光照变化,更多的是人物特效、人物本身的展示,这就可以用到matcap。
法线贴图大家都应该有所了解,法线贴图是通过一张纹理,把法线信息给gpu采样。
matcap也是这样,使用一张matcap图,通过法线读取纹理。
关键代码:
v2f vert (appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
float3 worldNorm = normalize(unity_WorldToObject[0].xyz * v.normal.x + unity_WorldToObject[1].xyz * v.normal.y + unity_WorldToObject[2].xyz * v.normal.z);
worldNorm = mul((float3x3)UNITY_MATRIX_V, worldNorm);
o.cap.xy = worldNorm.xy * 0.5 + 0.5;
return o;
}
这里是常规的worldNormal计算,而为了进行matcap操作,将法线从[-1,1]映射到[0,1]
float4 frag (v2f i) : COLOR
{
float4 mc = tex2D(_MatCap, i.cap);
return _Color * mc * 2.0;
}
然后在片段着色器中,将法线映射的结果,直接作为UV,去采样matcap图
一些扩展效果:
比如车漆、玉,甚至是用于卡通渲染的效果
完整代码
Shader "MatCap/Vertex/Plain"
{
Properties
{
_Color ("Main Color", Color) = (0.5,0.5,0.5,1)
_MatCap ("MatCap (RGB)", 2D) = "white" {}
}
Subshader
{
Tags { "RenderType"="Opaque" }
Pass
{
Tags { "LightMode" = "Always" }
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma fragmentoption ARB_precision_hint_fastest
#include "UnityCG.cginc"
struct v2f
{
float4 pos : SV_POSITION;
float2 cap : TEXCOORD0;
};
v2f vert (appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos (v.vertex);
float3 worldNorm = normalize(unity_WorldToObject[0].xyz * v.normal.x + unity_WorldToObject[1].xyz * v.normal.y + unity_WorldToObject[2].xyz * v.normal.z);
worldNorm = mul((float3x3)UNITY_MATRIX_V, worldNorm);
o.cap.xy = worldNorm.xy * 0.5 + 0.5;
return o;
}
uniform float4 _Color;
uniform sampler2D _MatCap;
float4 frag (v2f i) : COLOR
{
float4 mc = tex2D(_MatCap, i.cap);
return _Color * mc * 2.0;
}
ENDCG
}
}
Fallback "VertexLit"
}
MatCap图的制作方式:
目前常见的思路就是直接google Matcap。也可以从zbrush上获得很多相关图片
从unity material那里截图(感谢A$HES_L提供思路,不久大家也会见到他的文章)
原理
为什么matcap的图是圆的?为什么直接就可以使用法线的xy就可以做uv呢?
想象一下,物体的法线归一化之后可能朝向各个方向(忽略背面),以顶点为原点,朝向各个方向,就会形成一个半圆。
换句话说,半球的每一个点就代表了一个法线的方向
而将3D半圆存储到2D就变成了
是不是和matcap有点像?
我们都知道,很多pbr的效果都是在物体法线和光线,以及相机的三重影响下产生的效果。那么假定在相机位置不变的情况下,光线信息已经知道了,我只需要根据物体法线去找到对应的光照信息,是不是就可以节省很多计算呢。
其实matcap就是记录了光照信息,而法线就是寻找光线信息的key。
关于matcap就介绍到这里。
关于MatCap你还有什么想说的吗?
欢迎在来留言区和qq群进行讨论交流~