視差貼圖(Parallax Mapping)與陡峭視差貼圖(Steep Palallax Mapping)

視差貼圖(Parallax Mapping)

Demo下載


視差貼圖目前已經被廣泛運用了,只需要增加一種模型表面的深度紋理信息之後,就能近似的模擬模型的凹凸,在不需要燈光,不需要環境反射的情況下,可以比較真實的模擬真實世界.

先來看一下視差貼圖與其他貼圖的區別

可以看出 Parallax Mapped 和Steep Parallax Mapped 實現的效果要好很多.

下面的圖片更好的表現了視差貼圖的好處


原理:

根據用戶的觀察角度來將紋理座標偏移,就是把模型表面較高的位置來遮擋位置較低的位置.當用戶觀察角度改變的時候,讓一些像素的紋理座標偏移來遮擋一些像素,從而使觀察者感覺到凹凸起伏.紋理的偏移需要一個描述模型的凹凸紋理和觀察位置同時決定的.



這是一張原理的圖片,在這裏觀察者的眼睛在V處,實際觀察的物體的H(T1)點,也就是說物體的真實位置是在H(T1)處,但是眼睛觀測的視線會落在To處.
要想得到真實的場景,我們需要把To處的光線偏移到H(T1)處,這樣子就看起來就會比較真實.

如何來計算像素點To到H(T1)的偏移呢,需要觀察者位置和當前像素點的位置才能計算出來.下面我們來看一下是如何實現計算的.
就是OffsetUV 和ViewDir.x 和ViewDir.y 我們是已經知道的.

通常用簡化的公式

OffsetUV = OffsetUV + float2(-ViewDir.x,ViewDir,y)*v2Scale;

其中OffsetUV 表示最終得到的顏色紋理偏移,ViewDir 表示紋理觀察向量(經歸一處理過),v2Scale 表示與高度和模型有關的縮放因子,,這個縮放因子與表面起伏的大小和整個的大小的比相關.


在shader裏面分爲兩部分寫:
 一部分是將每個頂點上的觀察方向變化帶模型空間,整個部分在Vertex裏面計算實現;
另一部分是完成像素偏移的計算,此部分在PixelShader中完成.

PixelShader


//PixelShader
float4 RenderScenePS( VS_OUTPUT In ) :COLOR0
  { 
    // 計算視差貼圖的偏移
    float3 ViewDir = normalize( In.vLookAt );
    float2 OffsetUV = In.TextureUV ;
    float3 h = tex2D( MeshHeightSampler ,In.TextureUV ).y ;
    OffsetUV += float2( -ViewDir.x , ViewDir.y ) * ( h * 0.04 - 0.02 );
    float4 texColor = tex2D( MeshTextureSampler ,OffsetUV );
    // 
    return texColor  ;
    
  }


OffsetUV += float2( -ViewDir.x , ViewDir.y ) * ( h * 0.04 - 0.02 );

其中這行代碼就是表示視差貼圖的公式;

在VertexShader裏面要實現Tangent Space(我的另一篇博客有提到)座標,
VS_OUTPUT RenderSceneVS( VS_INPUT In )
  {
    
    VS_OUTPUT Out = ( VS_OUTPUT )0;
   //正常流程變化模型的頂點
    float4x4 matWorldView = mul( g_matWorld ,g_matView );
    float4x4 matWorldViewProject = mul( matWorldView ,g_matProject );
    Out.Position = mul( In.Position , matWorldViewProject );
    Out.TextureUV = In.TextureUV;
    //----------------- 在此計算一個變換矩陣 ---------------------
    // 將世界座標變換到切線空間系的變換矩陣
    float3x3 matWorldToModel = float3x3 (
      mul( In.Tanget ,                   g_matWorld ).xyz ,
      mul( cross( In.Tanget,In.Normal ), g_matWorld ).xyz ,
      mul( In.Normal ,                   g_matWorld ).xyz );

    // 
    float4 Position = mul( In.Position ,g_matWorld );
    // 每個頂點上的指向觀察者的方向
    Out.vLookAt = mul ( matWorldToModel ,normalize( Position - g_vEyePosition ));
    return Out;
  }


陡峭視差貼圖Steep Parallax Mapped

我們接着看一下Steep Parallax Mapping,這種視圖看起來會更加逼真,顯示效果會好點,當然計算的方法也不一樣.

下面是Steep Parallax Mapping的公式:

ti = s + (Ex , Ey) i / (n Ez)            0 ≤ i < n

陡峭視差映射,不像簡單的視差映射近似,並不只是簡單粗暴的對紋理座標進行偏移而不檢查合理性和關聯性,會檢查結果是否接近於正確值。這種方法的核心思想是把表面的深度切分成等距的若干層。然後從最頂端的一層開始採樣高度圖,每一次會沿着V的方向偏移紋理座標。如果點已經低於了表面(當前的層的深度大於採樣出的深度),停止檢查並且使用最後一次採樣的紋理座標作爲結果。

原理:

陡峭視差映射的工作方式在下面的圖片上舉例。深度被分割成8個層,每層的高度值是0.125。每層的紋理座標偏移是V.xy/V.z * scale/numLayers。從頂層黃色方塊的位置開始檢查,下面是手動計算步驟:

1.層的深度爲0,高度圖深度H(T0)大約爲0.75。採樣到的深度大於層的深度,所以開始下一次迭代。
2.沿着V方向偏移紋理座標,選定下一層。層深度爲0.125,高度圖深度H(T1)大約爲0.625。採樣到的深度大於層的深度,所以開始下一次迭代。
3.沿着V方向偏移紋理座標,選定下一層。層深度爲0.25,高度圖深度H(T2)大約爲0.4。採樣到的深度大於層的深度,所以開始下一次迭代。
4.沿着V方向偏移紋理座標,選定下一層。層深度爲0.375,高度圖深度H(T3)大約爲0.2。採樣到的深度小於層的深度,所以向量V上的當前點在表面之下。我們找到了紋理座標Tp=T3是實際交點的近似點。

下面是Steep Parallax Mapped的算法.
vec2 steepPallaxMapping(in vec3 v, in vec2 t)
{
	// determine number of layers from angle between V and N
	const float minLayers = 5;
	const float maxLayers = 15;
	float numLayers = mix(maxLayers, minLayers, abs(dot(vec3(0, 0, 1), v)));

	// height of each layer
	float layerHeight = 1.0 / numLayers;
	// depth of current layer
	float currentLayerHeight = 0;
	// shift of texture coordinates for each iteration
	vec2 dtex = gHeightScale * v.xy / v.z / numLayers;

 	// current texture coordinates
	vec2 currentTextureCoords = t;

	// get first depth from heightmap
 	float heightFromTexture = texture(NormTexSampler, currentTextureCoords).a;

	// while point is above surface
	while(heightFromTexture > currentLayerHeight) 
	{
		// to the next layer
		currentLayerHeight += layerHeight;
		// shift texture coordinates along vector V
		currentTextureCoords -= dtex;
		// get new depth from heightmap
		heightFromTexture = texture(NormTexSampler, currentTextureCoords).a;
   }

   return currentTextureCoords;
}

Demo 下載





發佈了57 篇原創文章 · 獲贊 86 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章