HLSL着色器原理:(三)高级着色器

  • 小光!小光!小光!小光!小光!
  • 本文所总结视频为或许是小光从油管搬运到B站的视频:传送门
  • 本篇主要汇总HLSL着色器的知识原理部分,并涉及少量必要的代码知识点,主要为知识点总结,实践部分建议参照其他Shader教程视频。
  • 我创建了一个游戏制作交流群:637959304 进群密码:(CSGO的拆包密码)欢迎各位大佬一起学习交流,不限于任何平台(U3D、UE、COCO2dx、GamesMaker等),以及欢迎编程,美术,音乐等游戏相关的任何人员一起进群学习交流。
  • 个人博客网址:https://www.sugarcanesama.com/archives/1298,如文章转载中出现例如传送门失效等纰漏,建议直接访问原博客网址。
  • 如有不对之处,欢迎指正。

目录

视差贴图

反射贴图(镜面反射)

制作金属材质

折射效果(Reflection)

菲涅尔效应

细节法线贴图

顶点颜色

顶点动画

溶解特效


视差贴图

  • 增加法线信息细节,增添深度信息细节,通过营造高度差来模拟深度细节。
  • 缺点:数值设置过大会造成图片拉伸效果,摄像机视角如果与贴图法线角度接近90度则看不出效果。

HLSL着色器原理:(三)高级着色器_第1张图片

offset hight = 0

HLSL着色器原理:(三)高级着色器_第2张图片

offset hight = 0.06

  • 前置条件:高度贴图(Height Map),可以存入到法线贴图的alpha通道中

//自定义Offset Height变量
v2f v(a2v In,uniform float4 lightPosition)
{
//在v2f中定义t_eyeVec,代表切线空间下的观察向量
        float3x3 objTangentXf = //ObjectToTangentSpaceTransform,类似于mvp矩阵
        objTangentXf[0] = In.binoraml.xyz;
        objTangentXf[0] = -In.tangent.xyz;
        objTangentXf[0] = In.normal.xyz;

        float4 objSpaceEyePos = mul(Viewinverse[3] , worldI);//摄像机坐标物体空间,worldI为定义的Inverse矩阵
        float3 objEyeVec = objSpaceEyePos.xyz - In.position.xyz;//观察向量

        Out.t_eyeVec = mul(objEyeVec,objTangentXf);.//切线空间下观察向量
}

float4 f(v2f In,uniform float4 lightColor) : COLOR
{
//计算出能够跟随观察向量和高度贴图移动的UV坐标
        float2 t_eyeVec = normalize(In.t_eyeVec).xy;
        t_eyeVec.y = -t_eyeVec.y;//这里是视频里适配3DS MAX的UV坐标才这么写的
        float heightAlpha = tex2D(normalMapSampler,In.texCoord).a * 2 - 1;
        float2  nevTextCoords = (heightAlpha * t_eyeVec * OffsetHeight) + In.texCoord.xy;
//之后把新的nevTextCoords在ColorTexture、SpecularTexture、noraml中替换原来的In.texCoord.xy
}


反射贴图(镜面反射)

  • 反射贴图(Reflection Mapping),依靠反射贴图实现实时反(Realtime)射计算,实现环境光的效果
  • (现在可以直接使用光追,NVIDIA yes!)
  • 前置条件:立方贴图
  • 数据结构

//自定义反射贴图材质(texture reflectMap)以及反射贴图采样器(samplerCUBE reflectMapSampler)
float4 f(v2f In,uniform float4 lightColor) : COLOR
{
//计算反射向量,解决贴图旋转问题
        float3 refvector = reflect(V,N);
        refvector.yz = -refvector.zy;//同3DS的问题
        float4 ref = texCUBE(reflectMapSampler, refvector);
        return ref * 5;//该系数根据贴图亮度进行调整即可
}


制作金属材质

  • 设置反射模糊度(模拟不光滑、锈蚀等的金属表面)

//自定义采样层数reflectionBlur
float4 f(v2f In,uniform float4 lightColor) : COLOR
{
//texCUB->texCUBElod从更模糊的贴图中进行采样 LOD->level of detail
//此处ColorTexture.a为模糊贴图的设置,导入模糊贴图后可以让指定区域展示不同的模糊效果
        float4 ref = texCUBElod(reflectMapSampler, float4(refvector,reflectionBlur * ColorTexture.a));

//将反射混合进原有光装模型当中
         Diffuse = lerp(Diffuse,ref,colorTexture.a);//lerp允许按照权重混合两个颜色
}

  • Tip:因为导入图片是黑白贴图,所以在作乘法运算时,黑色区域的值为0,0乘以任何值都为0,所以无论如何提高模糊度该表面区域都是光滑的。

HLSL着色器原理:(三)高级着色器_第3张图片

reflectionBlur = 6的效果

HLSL着色器原理:(三)高级着色器_第4张图片

导入了黑白格子的模糊贴图后效果

HLSL着色器原理:(三)高级着色器_第5张图片

进行反射混合之后的效果


折射效果(Reflection)

HLSL着色器原理:(三)高级着色器_第6张图片

//水晶、透明等类似材质的折射效果
//自定义函数refractionIndex代表曝光率

float4 f(v2f In,uniform float4 lightColor) : COLOR
{
//计算折射向量
//refract用于计算折射的函数,第一介质折射率除以第二介质折射率,此时第一介质为空气,第二介质为水。绝对折射率分别为函数内填入数据
//把1.330替换为refractionIndex,可让用户自定义材质折射率
        float3 refractvector = refract(V,-N,1.000293/1.330).xyz;
        refractvector = -refractvector.xzy;
        refractvector.z = -refractvector.z;

        refractedColor = texCUBE(reflectMapSampler,refractvector ) * 5;//系数5用来提高贴图亮度

}

HLSL着色器原理:(三)高级着色器_第7张图片

折射效果贴图

HLSL着色器原理:(三)高级着色器_第8张图片

材质折射率=1.0时情况


菲涅尔效应

  • 利用菲涅尔效应(Fresnel)来结合反射和折射的效果。也可以用该思路制作边缘光效果,制作厨房表面,
  • 菲涅尔效应(第二集里有详细链接):物体边缘或光线入射角较大的部位,比入射角小的部分体现出了更强烈的反射性质。

float4 f(v2f In,uniform float4 lightColor) : COLOR
{
        float fresnelTerm = pow(1 - dot(V,N),fresnelPower)* fresnelBrightness;//边缘白色中间黑色,直接是dot为边缘黑色中间白色,fresnelPower,fresnelBrightness为自定义变量
        float4 reflectionAndRefraction = lerp(refractedColor,ref,fresnelTerm);
}

HLSL着色器原理:(三)高级着色器_第9张图片

dot(V,N)

HLSL着色器原理:(三)高级着色器_第10张图片

1 - dot(V,N)

HLSL着色器原理:(三)高级着色器_第11张图片

pow(1 - dot(V,N),4)

HLSL着色器原理:(三)高级着色器_第12张图片

反射折射混合后效果

HLSL着色器原理:(三)高级着色器_第13张图片

pow(1 - dot(V,N),4)* 3


细节法线贴图

  • 细节法线贴图(Detail Normal Mapping):允许放大观察后的图片拥有更多的细节。

//自定义参数:detailnormalmap 自定义采样器:detailNoramlMapSampler
float4 f(v2f In,uniform float4 lightColor) : COLOR
{
//自定义参数detailSize,detialHeight
        float3 detailNormal = tex2D(detailNoramlMapSampler,In.textCoord * detailSize).xyz * 2.0 -1.0 t;
        
        normal = float3((normal.x + detailNormal.x* detialHeigh),(normal.y + detailNormal.y* detialHeigh),normal.z);
}


顶点颜色

  • 利用顶点颜色和不同明度编写着色器。具体教程请看视频3.7章节。
  • 用处举例:有两张漫反射贴图,通过顶点色决定哪些地方显示第一张,哪些地方显示第二张。


顶点动画

  • 改变渲染位置

HLSL着色器原理:(三)高级着色器_第14张图片

v2f v(a2v In,uniform float4 lightPosition)
{
        float4 ObjectSpacePosition = In.position;
        ObjectSpacePosition.z += 50;//这里的单位为cm,在3dsmax中
}

  • 通过引入时间变量来制作各种动画
  • 波动效果(动画)

float time : TIME;

float wave(float value,float frequency,float speed,float amplitude)
{
        return sin(value * frequency + speed) * amplitude;
}

v2f v(a2v In,uniform float4 lightPosition)
{
        float4 ObjectSpacePosition = In.position;
        ObjectSpacePosition.z += wave(ObjectSpacePosition.x,0.1,time,8) ;
}

HLSL着色器原理:(三)高级着色器_第15张图片

波动效果

  • 跷跷板效果(沿着中轴线旋转移动)

float2 teetertotter(float2 Textcoords,float2 center,float maxAngle,float time)
{
        float theta = maxAngle * sin(time);
        float2 sc;
        sincos(theta,sc.x,sc.y);
        float2 uv = Texcoords - center;
        float2 rotateduv;
        rotateduv.x = dot(uv,float2(sc.y-sc.x));
        rotateduv.y = dot(uv,sc.xy);
        rotateduv += center;
        return rotateduv;
}

v2f v(a2v In,uniform float4 lightPosition)
{
        float4 ObjectSpacePosition = In.position;
        ObjectSpacePosition.yz += teetertotter(ObjectSpacePosition.yz,float2(0,0),1,time) ;
}

  • 旋转效果(和跷跷板差不多具体可以看视频)


溶解特效

technique regular
{
        pass one
        {
                AlphaTTestEnable = true;//开启透明度测试,根据透明度选择是否剔除片元
                AlphaRef = 128;//用于定义透明度分界线。透明度低于128分为一组视为完全透明,高于128视为完全不透明
        }
}

//自定义参数brightnessAmount,contrastAmount
float4 f(v2f In,uniform float4 lightColor) : COLOR
{
        float4 OutColor = (Ambient + Diffuse + Specular) * lightColor;
        Outcolor.a = ColorTexture.a + brightnessAmount;
        Outcolor.a = contrastAmount * (Outcolor.a - 0.5) + 0.5;//对比度调整公式
        if(Outcolor.a <= 0.55) OutColor.rgb = float3(1.0,0.5,0.0);//因为在AlphaRef中规定了小于128的颜色会完全透明,所以实际上是在0.5-0.55的区间段内进行颜色的渲染

        return OutColor;
}


  • WELL DONE!

你可能感兴趣的:(Unity3D,着色器)