- 小光!小光!小光!小光!小光!
- 本文所总结视频为或许是小光从油管搬运到B站的视频:传送门
- 本篇主要汇总HLSL着色器的知识原理部分,并涉及少量必要的代码知识点,主要为知识点总结,实践部分建议参照其他Shader教程视频。
- 我创建了一个游戏制作交流群:637959304 进群密码:(CSGO的拆包密码)欢迎各位大佬一起学习交流,不限于任何平台(U3D、UE、COCO2dx、GamesMaker等),以及欢迎编程,美术,音乐等游戏相关的任何人员一起进群学习交流。
- 个人博客网址:https://www.sugarcanesama.com/archives/1298,如文章转载中出现例如传送门失效等纰漏,建议直接访问原博客网址。
- 如有不对之处,欢迎指正。
目录
视差贴图
- 增加法线信息细节,增添深度信息细节,通过营造高度差来模拟深度细节。
- 缺点:数值设置过大会造成图片拉伸效果,摄像机视角如果与贴图法线角度接近90度则看不出效果。
offset hight = 0
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,所以无论如何提高模糊度该表面区域都是光滑的。
reflectionBlur = 6的效果
导入了黑白格子的模糊贴图后效果
进行反射混合之后的效果
折射效果(Reflection)
//水晶、透明等类似材质的折射效果 //自定义函数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用来提高贴图亮度 }
折射效果贴图
材质折射率=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); }
dot(V,N)
1 - dot(V,N)
pow(1 - dot(V,N),4)
反射折射混合后效果
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章节。
- 用处举例:有两张漫反射贴图,通过顶点色决定哪些地方显示第一张,哪些地方显示第二张。
顶点动画
- 改变渲染位置
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) ; }
波动效果
- 跷跷板效果(沿着中轴线旋转移动)
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!