MatCap—又省又好看的Shader


前言

手游做效果,最担心的就是性能问题。只有在性能保证的情况下,做出效果才是最好的。

本文主要是介绍一种性能不错的效果,可以用来在某些情况下实现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图的制作方式

  1. 目前常见的思路就是直接google Matcap。也可以从zbrush上获得很多相关图片

  2. unity material那里截图(感谢A$HES_L提供思路,不久大家也会见到他的文章)

原理

为什么matcap的图是圆的?为什么直接就可以使用法线的xy就可以做uv呢

想象一下,物体的法线归一化之后可能朝向各个方向(忽略背面),以顶点为原点,朝向各个方向,就会形成一个半圆。

换句话说,半球的每一个点就代表了一个法线的方向

而将3D半圆存储到2D就变成了

是不是和matcap有点像?

我们都知道,很多pbr的效果都是在物体法线和光线,以及相机的三重影响下产生的效果。那么假定在相机位置不变的情况下,光线信息已经知道了,我只需要根据物体法线去找到对应的光照信息,是不是就可以节省很多计算呢。

其实matcap就是记录了光照信息,而法线就是寻找光线信息的key。

关于matcap就介绍到这里。

关于MatCap你还有什么想说的吗?

欢迎在来留言区和qq群进行讨论交流~




评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值