菜鸡shader:L5 fresnel、matcap和cubemap

Fresnel

在这里插入图片描述

在这里插入图片描述

shader forge实现

在这里插入图片描述

  • 个人理解是,使用观察方向和法向方向点乘,那就相当于我们的视线看到哪里,哪里就是亮的,相当于头顶探照灯了。
  • 但是菲尼尔效果则是观察方向和法线方向离得越近,折射或者反射效果越弱;而如果观察方向和法线方向越接近90°时,反射的效果就越强。所以我们采用onemiuns(用1减去观察方向和法线方向的点乘),就能取得我们想要的效果。
  • 最后再使用power函数来增强这个菲涅尔的强度。

UE4蓝图实现

然后是ue4中的fresnel效果的实现,跟shader forge的节点差不多:
在这里插入图片描述

  • ue4中对应于shader forge中使用的法线方向的节点是PixelNormalWS,而不是VertexNormalWS这点需要注意。
  • 和unity中不同的时我们的观察方向需要通过摄像机方向取反来得到,因为shader forge的观察方向是从着色点为起点发射到相机的位置。这与ue4中的相机方向刚好相反。

Matcap

具体请参考毛星云大佬的blog
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

不像一般的Shader,需要提供光照,需要在Shader代码中进行漫长的演算,基于MatCap思想的Shader相当于MatCap贴图就把光照结果应该是怎样的标准答案告知Shader,我们只用在试卷下写出答案,进行一些加工即可。

需要注意,MatCap Shader有一定的局限性。因为从某种意义上来说,基于MatCap的Shader,就是某种固定光照条件下,从某个特定方向,特定角度的光照表现结果。

正是因为是选择的固定的MatCap贴图,得到相对固定的整体光照表现,若单单仅使用MatCap,就仅适用于摄像机不调整角度的情形,并不适合摄像机会频繁旋转,调节角度的情形。但我们可以在某些Shader中,用MatCap配合与光照交互的其他属性,如将MatCap结合一个作为光照反射的颜色指导的Reflection
Cube Map,就有了与光照之间的交互表现。这样,就可以适当弥补MatCap太过单一整体光照表现的短板。

shader forge实现

在这里插入图片描述
unity中的效果:
在这里插入图片描述

UE4蓝图实现

在这里插入图片描述

ue4中的效果:
在这里插入图片描述

  • ue和unity的亮度不一样啊…只能手动调参了,这里学习为主,暂时就不折腾这个了。

CubeMap

这个东西其实很多地方都讲过,如果感兴趣可以看看:

在这里插入图片描述
在这里插入图片描述

SD和PS制作所需的贴图

下面说一下怎么用ps处理cubemap需要的贴图:
首先找到一张全景图,类似于这样的:
在这里插入图片描述
在这里插入图片描述

  • 具体可以上subtance designer里面找3D View里的全景图,打开其中一个的文件夹,然后直接拖到ps里面:
    在这里插入图片描述
  • 拖进ps里后选择作为alpha通道:
    在这里插入图片描述
  • 选择:
    在这里插入图片描述
  • 调整图像大小:
    在这里插入图片描述
  • 然后设置图像模式,默认参数确认就行,这一步是为了将图片的亮度高于1和暗度低于0的部分限制在0到1范围内:
    在这里插入图片描述
    然后导出为tga格式:
    在这里插入图片描述
    在这里插入图片描述
  • 导入到unity中,红色的需要调整,绿色的自己选择调不调整:
    在这里插入图片描述
  • 调整完应用之后就是下面这个样子,一个材质球:
    在这里插入图片描述

shader forge实现

  • 然后放下课程上的实现:
    在这里插入图片描述

  • unity中自己的实现:
    在这里插入图片描述

  • 因为我们要得到的是视线看过去与法线形成的反射方向,所以需要获取到观察方向的反方向。

  • 感兴趣的可以去了解下reflect函数的实现。

  • 和课程上的实现图相比多了AO,也就是环境光遮蔽贴图的部分。

unity的效果图:
在这里插入图片描述

unity代码实现

Shader "shader forge/L9_CubeMap2"
{
    
    
    Properties
    {
    
    
        _normalmap ("normal map", 2D) = "bump" {
    
    }
        _cubeMap ("cubeMap", Cube) = "_Skybox" {
    
    }
        _AOTex ("AO Texture",2D) = "White" {
    
    }
        _n1 ("n1", Float ) = -1
        _MipMap_Level ("MipMap_Level", Range(0, 7)) = 0
        _fresnel_exp ("fresnel_exp", Range(0, 10)) = 1
        _EnvSpecInt ("EnvSpecInt", Range(0, 5)) = 1
    }
    SubShader
    {
    
    
        Tags {
    
     "RenderType"="Opaque" }
        LOD 100

        Pass
        {
    
    
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            // make fog work
            #pragma multi_compile_fog

            #include "UnityCG.cginc"

            struct appdata
            {
    
    
                float4 vertex : POSITION;
                float2 uv0 : TEXCOORD0;
                float4 tangent : TANGENT;
                float3 normal : NORMAL;
            };

            struct v2f
            {
    
    
                float2 uv0 : TEXCOORD0;                
                float4 pos : SV_POSITION;
                float4 posWorld : TEXCOORD1;
                float3 nDirWS : TEXCOORD2;
                float3 tDirWS : TEXCOORD3;
                float3 biDirWS : TEXCOORD4;               
            };

            uniform sampler2D _normalmap;
            uniform samplerCUBE _cubeMap;
            uniform sampler2D _AOTex;
            uniform float _n1;
            uniform float _MipMap_Level;
            uniform float _fresnel_exp;
            uniform float _EnvSpecInt;

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                o.uv0 = v.uv0;
                o.nDirWS = UnityObjectToWorldNormal(v.normal);
                o.tDirWS = normalize(mul(unity_ObjectToWorld, float4(v.tangent.xyz,0.0)).xyz);
                o.biDirWS = normalize(cross(o.nDirWS,o.tDirWS) * v.tangent.w);
                o.posWorld = mul(unity_ObjectToWorld, v.vertex);                
                return o;
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    
                //贴图采样
                float3 nDirTS = UnpackNormal(tex2D(_normalmap,i.uv0)).rgb;
                float AO_R = tex2D(_AOTex,i.uv0);

                //向量准备
                float3x3 TBN_Matrix = float3x3(i.tDirWS,i.biDirWS,i.nDirWS);
                float3 nDirWS_FT = normalize(mul(nDirTS,TBN_Matrix));
                float3 nDirVS_FT = normalize(mul(UNITY_MATRIX_V,float4(nDirWS_FT,0.0)).xyz);
                float3 vDirWS = normalize(_WorldSpaceCameraPos.xyz - i.posWorld.xyz);
                float3 vrDirWS = normalize(reflect(-vDirWS,nDirWS_FT));

                //中间量准备
                fresnel
                float NoV = max(0.0,dot(nDirWS_FT,vDirWS));
                float OneMinusNoV = 1 - NoV;
                float fresnel = pow(OneMinusNoV,_fresnel_exp);

                cubemap
                float3 cubemap_uv = vrDirWS;
                float3 cubemap_color = texCUBElod(_cubeMap,float4(cubemap_uv,_MipMap_Level));

                //光照模型
                float3 finalColor = cubemap_color * fresnel;
                float3 EnvSpecLighting = finalColor * _EnvSpecInt * AO_R;

                //后处理

                //最后返回值
                return float4(EnvSpecLighting,1.0);
            }
            ENDCG
        }
    }
}

UE4蓝图实现(未实现)

额,虽然还想在ue4中实现一编,但是ue4的cubemap好像是直接用来制作天空盒的,跟本节课只是单纯作为贴图参与材质的编辑不一样,当然也有可能是我自己原因没有搜到相关教程,如果有大佬知道也可以在评论区告诉我一声。

如果对制作ue4的cubemap有兴趣的话也可移步至:

猜你喜欢

转载自blog.csdn.net/weixin_43789369/article/details/131411352