Bump图改进

您所在的位置:网站首页 切线和法线的关系公式 Bump图改进

Bump图改进

2023-03-21 12:15| 来源: 网络整理| 查看: 265

从尺度上来描述物体的细节,我们可以把它分为三种,宏观尺度,中观尺度和微观尺度。从宏观尺度上来看,它的特征可能覆盖多个像素。中观尺度覆盖几个像素,而微观尺度可能小于一个像素。宏观尺度是由顶点或者是三角形或者是其他几何图元来表示的,当我们创建三维角色的时候,四肢或者头部,这种通常就是在宏观尺度上建模的,微观尺度工作在着色模型中,着色模型通常在像素着色器里实现并且使用纹理贴图作为参数,着色模型模拟了物体表面微观几何形体下的相互作用。比如,有光泽的物体物体在微观尺度下是光滑的,而漫反射的物体在微观尺度下是粗糙的,角色的皮肤或者衣服看起来也有不同的材质,因为它们使用了不同的着色模型。而中观尺度就描述了宏观尺度和微观尺度之间的特征,它包含的细节比较复杂,没办法使用单个三角形进行渲染,但这些细节又足够大,能让观察者看出几个像素以上的表面曲率变化,比如人脸上的皱纹,肌肉组织的细节,衣服的褶皱,砖头之间的缝隙。凹凸映射就是模拟中观尺度的常用方法之一,它能够让观察者感知到比几何模型尺度更小的细节。它的基本思想是在纹理中把尺度细节相关的信息给编码进去,在着色过程中用稍微收到干扰的表面来代替真实的表面,就让表面看起来具有小尺度的细节。

Bump Mapping分类

Bump Mapping的种类:法线映射、视差映射、浮雕映射。这几种方法或者贴图。都是广泛的被使用于增加模型的细节效果,或者用来做特殊的画面表现效果。最常见的是法线映射,一般的增加法线贴图后,会对局部的物体表面进行法线扰动,进而改变明暗关系,从而达到增加表面细节的效果,其中三种映射都用到的法线贴图也是本次介绍的重点内容。

Normal Mapping

法线映射是一张存有物体局部表面信息的一张贴图 ,在计算程序的时候,程序会去读取法线图并且读到当前像素点的法线信息,结合光照进行计算。使用法线贴图计算光照,就能让物体表现出更丰富的细节,并且随着光照方向的变换实时变换,这是普通的纹理贴图所不能表现出来的,法线贴图一般由高模映射到低模上来生成,但像金属、木头这些细节丰富的物体就可以借助一些程序化生成的软件比如PS。

法线映射的实现切线空间法线的存储,一般会放到模型的切线空间中切线空间:以物体表面的切线,副切线和法线组成的几何空间每个顶点都有属于自己的切线空间,这个空间的原点是顶点本身,z轴是顶点的法线方向(n),x轴是顶点的切线方向(t),y轴有前边两个轴叉乘而来,被称为副切线(b)或者副法线。//可以参考入门精要第七章部分

在计算光照时,需要把相关的向量放在统一的坐标系下进行运算。此时就需要不同空间坐标的转换矩阵(世界空间转切线空间/切线空间转世界空间) 世界空间和切线空间的转换将世界坐标系下顶点的法线(Normal)、切线(Tangent)、副切线(Bitangent)作为切线空间坐标系的正交基。用这三个向量的标准正交基构建转换矩阵。对应关系为:法线方向作为z轴,切线方向作为x轴,副切线方向作为y轴转换矩阵:切线空间到世界空间的转换矩阵为一个3×3的旋转矩阵,一般称为TBN矩阵世界空间到切线空间的转换矩阵为上述TBN矩阵的逆矩阵,因为是正交矩阵,所以逆矩阵就是它的转置矩阵

////TBN矩阵参考资料:Tutorial 13 : Normal MappingGLSL-TBN矩阵_沉默的舞台剧的博客-CSDN博客_tbn矩阵//旋转矩阵的逆=转置可以参考《games101第四课》开头部分转换矩阵完成之后,接下来就是光照计算将光照计算中需要的数据,例如光照方向、观察方向、法线方向等参数,带入到光照模型中计算切线空间的优点法线存在各个空间里都可以,但关键不只是存在哪里,还有后续的光照计算切线空间的好处

自由度高。

模型空间下是绝对法线信息(仅可以用在创建它时的那个模型)

而切线空间下的是相对法线信息,是对当前物体法线的扰动。(可以复用)

可进行uv动画。

比如:移动uv坐标来实现凹凸移动效果

可以重用法线纹理。

比如:一个立方体,6个面可以用一张法线贴图

可压缩。

由于切线空间下贴图中法线的Z方向总是正方向(模型空间下可以是负的),那么我们只存XY(切线和副切线)就能推出Z(法线)了,可以少存一个。

在Unity中,非移动平台上,Unity会把法线贴图转换成DXRT5nm格式,这个格式只有两个有效GA通道,这样可以节省空间,而移动平台Unity使用传统的RGB通道。在DXRT5nm格式中,GA储存UI应法线x、y分量,z分量需要通过一个简单运算求得。

Parallax Mapping

法线映射虽然能展示较为通真的模型表面细节,但毕竟法线映射只能改变法线进而改变光照,并不能让模型表面产生让人信服的遮挡效果。所以我们引入视差映射。Parallax Mapping中文为视差映射,是—种类似于法线映射的技术,但是原理不同,类似法线贴图,它是用以提高模型表面细节并赋予其遮挡关系的技术。并可以和法线贴图—起使用提供令人信服的通真的效果。视差映射同样引进—张新的贴图,高度图,高度图—般是作为顶点位移来使用的,但模型要包含大量的三角形才能获得比较不错的效果,否则看起来会成块状。所以如何在有限的三角面上表示通真的令人信服的效果?这就是视差映射技术。视差映射的核心是改变纹理坐标,但如何改变?怎么改变?这时需要—张存储模型信息的高度图,利用模型表面高度信息来对纹理进行偏移。

视差映射主要是让平面看起来立体,和法线贴图—样是欺骗眼睛的做法。我们制作的模型在—个三角面即切线空间下,所有点都位于切线和副切线组成的平面内(右图水平0.0点),但实际物体要有更多的丰富细节。如右图当计算我们当前视角的片元A时,真正应该计算的点是视线与物体表面的实际交点,即B点。如何计算B点,计算B点,我们就需要知道A、B两点在平面上uv偏差。这个其实是不太好计算的。不过可以近似计算,根据高度图以及切线空间下的视角方向,近似的求解偏移量。视角方向(v) ,A点的高度值来近似的求解,并可以通过—个缩放值(scale)来控制。

d = v.xy * ha * scale l v.z

Steep Parallax Mapping

视差映射往往是近似值,所以计算结果并不是准确的。在此基础上想获得更加准确的结果就需要陡峭视差映射,陡峭视差也是一个近似的解,但相比于普通视差映射要精确的多,效果表现上也更好。并且会对纹理坐标偏移进行合理性检查。陡峭视差映射的基本思想是将深度分为等距的若干层,然后从最顶端开始采样,并且每次沿着视角方向偏移一定的值,若当前层的深度大于采样出的深度,则停止检查并返回最后的结果。

Relief Mapping

浮雕映射,对比与视差映射.想要有更好更准确的表现效果,视差映射是不够的,使用更大的uv偏移,视差映射就会导致失真。于是引入浮雕映射,浮雕映射更容易提供更多的深度,还可以做自阴影以及闭塞效果。

浮雕映射—般采用射线步进,和二分查找来决定uv偏移量。第—种使用射线步进来查找可能的交点,为什么不直接用二分查找。因为直接用二分查找可能会漏掉较薄的区域导致结果不准确。所以第—步,使用射线步进来确定交点位于那个步进内。之后在该步进内使用二分查找,快速确定交点位置。最后返回结果,偏移贴图。

Shader "Unlit/ReliefMapping" { Properties { _MainTex ("Texture", 2D) = "white" {} _NormalMap("法线贴图",2D) = "bump"{} _NormalScale("法线强度",Float) = 1 [Toggle]_HEIGHTMAP("高度映射",Float) = 0.0 _HeightMap("高度图",2D) = "white"{} _HeightScale("高度图强度",Range(0,0.5)) = 0.005 _MainColor("主颜色",Color) = (1,1,1,1) _CubeMap("环境贴图",CUBE) = "gray"{} _Metal("金属度",range(0,1)) = 0.5 } SubShader { Tags { "RenderPipeline"="UniversalRenderPipeline""RenderType"="Opaque" } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl" CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; float4 _NormalMap_ST; float4 _HeightMap_ST; float4 _MainColor; float _NormalScale; float _HeightScale; float _Metal; bool _HEIGHTMAP; CBUFFER_END TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); TEXTURE2D(_HeightMap); SAMPLER(sampler_HeightMap); TEXTURE2D(_CubeMap); SAMPLER(sampler_CubeMap); ENDHLSL Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma shader_feature _HEIGHTMAP_ON struct appdata { float3 normal : NORMAL; float4 vertex : POSITION; float2 uv : TEXCOORD0; float4 tangent:TANGENT; }; struct v2f { float4 uv : TEXCOORD0; float4 vertex : SV_POSITION; float3 nDirWS : TEXCOORD1; float3 lDirWS : TEXCOORD2; float3 posWS : TEXCOORD3; float3 TDirWS : TEXCOORD4; float4 uv2 : TEXCOORD5; float3 BDirWS : TEXCOORD6; }; v2f vert (appdata v) { v2f o; o.vertex = TransformObjectToHClip(v.vertex); o.uv.xy = TRANSFORM_TEX(v.uv, _MainTex); o.nDirWS = TransformObjectToWorldNormal(v.normal.xyz,true); o.posWS = TransformObjectToWorld(v.vertex); o.TDirWS = normalize(TransformObjectToWorld(v.tangent.xyz)); o.BDirWS = normalize(cross(o.nDirWS,o.TDirWS)*v.tangent.w); o.uv.zw = TRANSFORM_TEX(v.uv,_NormalMap); #ifdef _HEIGHTMAP_ON o.uv2.xy = TRANSFORM_TEX(v.uv,_HeightMap); #endif return o; } //视差映射 float2 ParallaxMapping(float2 Height_HV,float3 V) { float height = SAMPLE_TEXTURE2D(_HeightMap,sampler_HeightMap,Height_HV); float2 offsetuv = V.xy/V.z*height*_HeightScale; return offsetuv; } //陡峭视差映射 float2 SteepParallaxMapping(float2 uv,float3 V) { float layerNum = 40;//迭代层数 float layerHeight = 1/layerNum;//每层步进距离 float currentLayerHeight = 0;//当前高度 float2 offsetLayerUV = V.xy/V.z*_HeightScale;//最大偏移距离 float2 stepOffset = offsetLayerUV/layerNum;//每步偏移量 float2 offsetUV = float2(0,0); float2 currentUV = uv;//当前采样高度UV float currentHeight = SAMPLE_TEXTURE2D(_HeightMap,sampler_HeightMap,currentUV + offsetUV).r;//当前高度 for(int i=0;icurrentHeight) { return offsetUV;//当前采样的层数高度,大于当前高度 } offsetUV+=stepOffset; currentHeight = SAMPLE_TEXTURE2D(_HeightMap,sampler_HeightMap,currentUV + offsetUV).r;//采样偏移 currentLayerHeight+=layerHeight; } return offsetUV; } //浮雕映射 float2 ReliefMapping(float2 uv, real3 V) { float2 offlayerUV = V.xy / V.z * _HeightScale;//依然是最大偏移量 float RayNumber = 40;//步进算法 float layerHeight = 1 / RayNumber;//每层高度 float2 SteppingUV = offlayerUV / RayNumber;//每步偏移量 float currentLayerHeight = 0;//当前高度 float offlayerUVL = length(offlayerUV);//长度 float2 offUV = float2(0,0); for(int i = 0;i < RayNumber; i++) { offUV += SteppingUV; float currentHeight = SAMPLE_TEXTURE2D(_HeightMap,sampler_HeightMap,uv + offUV).r; currentLayerHeight += layerHeight;//层数增加 if (currentHeight < currentLayerHeight) { break; } } float2 T0 = uv + offUV;//当前UV float2 T1 = uv + offUV - SteppingUV;//上一个UV //二分查找 for (int j = 0; j < 40; j++) { float2 P0 = (T1 + T0) * 0.5; float P0Height = SAMPLE_TEXTURE2D(_HeightMap,sampler_HeightMap,P0).r;//当前采样高度 float P0LayerHeight = length(P0) / offlayerUVL;//当前高度(公式中还应乘上总高度1) if (P0Height < P0LayerHeight) { T0 = P0; } else { T1= P0; } } return (T0 + T1) / 2 - uv; } half4 frag (v2f i) : SV_Target { // sample the texture //-------HalfLambert-------- float2 MainTex_UV = i.uv.xy; float2 Normal_UV = i.uv.zw; half3x3 TBN = transpose(half3x3(i.TDirWS,i.BDirWS,i.nDirWS));//TBN矩阵 float3 VDirWS = normalize(GetWorldSpaceViewDir(i.posWS)); #ifdef _HEIGHTMAP_ON half3 VDirTS = normalize(mul(-VDirWS,TBN)); float2 offuv = float2(0,0); offuv = ReliefMapping(i.uv2.xy,VDirTS); MainTex_UV +=offuv; Normal_UV+=offuv; #endif float3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap,sampler_NormalMap,Normal_UV)).xyz; normalTS.xy*=_NormalScale; normalTS.z = sqrt(1-saturate(dot(normalTS.xy,normalTS.xy))); Light light = GetMainLight(); float3 NDirWS = normalize(mul(TBN,normalTS)); float3 lDirWS = normalize(light.direction); float3 RDirWS = normalize(reflect(-VDirWS,NDirWS)); float3 HDirWS = normalize(VDirWS+lDirWS); float NdotL = max(0,dot(NDirWS,lDirWS)); float NDotH = max(0,dot(NDirWS,HDirWS)); float4 TexCol = SAMPLE_TEXTURE2D(_MainTex,sampler_MainTex, MainTex_UV); float Glossiness = lerp(0,100,_Metal); float MipMapLevel = lerp(0.00001,8,1-_Metal); float3 Diffuse = light.color.rgb*TexCol*_MainColor*NdotL; float3 Specular = _Metal*pow(NDotH,Glossiness); float3 ambient = SAMPLE_TEXTURECUBE_LOD(_CubeMap,sampler_CubeMap,RDirWS,MipMapLevel); float3 result = Diffuse+Specular; return float4(result,1); } ENDHLSL } } }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3