天天看點

Directx11教程(42) 紋理映射(12)-簡單的bump mapping

     有時候,我們隻有一個粗糙的模型,但是我們想渲染紋理細節,比如一個磚牆,我們如何在隻有一個平面的時候,渲染出磚牆凹凸的效果。

   比如隻有這樣的牆:

Directx11教程(42) 紋理映射(12)-簡單的bump mapping

但是我們想要這樣的效果:

Directx11教程(42) 紋理映射(12)-簡單的bump mapping

怎麼辦呢?這時候,我們可以考慮對第一張圖進行處理,生成它的法向圖,存儲在一張紋理中,生成法向圖的主要算法是:

Directx11教程(42) 紋理映射(12)-簡單的bump mapping

      對于一張圖檔,假設像素排列如上圖所示,Hg,Hr,Ha分别表示這些點的RGB(或灰階)值,我們得到第一個向量(1,0,Hr-Hg),第二個向量(0,1,Ha-Hg),則法向可以通過它們的差積得到:

Directx11教程(42) 紋理映射(12)-簡單的bump mapping

 對所有的像素進行處理,我們可以得到一個紋理的法向圖,比如第一張牆紋理貼圖,經過計算,它的法向圖為:

Directx11教程(42) 紋理映射(12)-簡單的bump mapping
Directx11教程(42) 紋理映射(12)-簡單的bump mapping

      在物體表面,每個點都都有一個(T,N,B)的局部坐标系,分别對應切向、法向,副法向,有了紋理圖後,我們可以通過公式

bumpNormal = normal + bumpMap.x * tangent + bumpMap.y * binormal; 得到最終的法向。其中bumpMap為前面計算得到的法向貼圖,或者說normal map。

1、首先我們改寫CubeModelClass類,設定頂點格式為:

struct VertexType

{

D3DXVECTOR3 position;

D3DXVECTOR3 normal; //法向

D3DXVECTOR3 tangent; //切向

D3DXVECTOR3 binormal; //副法向

D3DXVECTOR2 texture; //紋理坐标

D3DXVECTOR4 Kd; //材質漫反射系數

D3DXVECTOR4 Ks;  //材質的高光系數

};

增加了切向和副法向的計算,主要通過頂點的uv坐标以及頂點值求得

void CubeModelClass::CalculateTangentBinormal(TempVertexType vertex1, TempVertexType vertex2, TempVertexType vertex3,

    VectorType& tangent, VectorType& binormal)

    {

    float vector1[3], vector2[3];

    float tuVector[2], tvVector[2];

    float den;

    float length;

    // 計算2個向量.

    vector1[0] = vertex2.x - vertex1.x;

    vector1[1] = vertex2.y - vertex1.y;

    vector1[2] = vertex2.z - vertex1.z;

    vector2[0] = vertex3.x - vertex1.x;

    vector2[1] = vertex3.y - vertex1.y;

    vector2[2] = vertex3.z - vertex1.z;

    // 計算tu和tv向量.

    tuVector[0] = vertex2.tu - vertex1.tu;

    tvVector[0] = vertex2.tv - vertex1.tv;

    tuVector[1] = vertex3.tu - vertex1.tu;

    tvVector[1] = vertex3.tv - vertex1.tv;

    den = 1.0f / (tuVector[0] * tvVector[1] - tuVector[1] * tvVector[0]);

    tangent.x = (tvVector[1] * vector1[0] - tvVector[0] * vector2[0]) * den;

    tangent.y = (tvVector[1] * vector1[1] - tvVector[0] * vector2[1]) * den;

    tangent.z = (tvVector[1] * vector1[2] - tvVector[0] * vector2[2]) * den;

    binormal.x = (tuVector[0] * vector2[0] - tuVector[1] * vector1[0]) * den;

    binormal.y = (tuVector[0] * vector2[1] - tuVector[1] * vector1[1]) * den;

    binormal.z = (tuVector[0] * vector2[2] - tuVector[1] * vector1[2]) * den;

    length = sqrt((tangent.x * tangent.x) + (tangent.y * tangent.y) + (tangent.z * tangent.z));

    // 歸一化

    tangent.x = tangent.x / length;

    tangent.y = tangent.y / length;

    tangent.z = tangent.z / length;

    // 計算向量的長度.

    length = sqrt((binormal.x * binormal.x) + (binormal.y * binormal.y) + (binormal.z * binormal.z));

   // 歸一化向量

    binormal.x = binormal.x / length;

    binormal.y = binormal.y / length;

    binormal.z = binormal.z / length;

    return;

    }

得到面的法向、切向以及副法向後,把他們指派給頂點。

然後我們在LightTex2ShaderClass中,改變layout,然後修改lighttex2.vs和lighttex2.ps

特别是ps中,我們改變normal的計算方式:

float3 N;

float4 textureColor;

float4 textureColor1 = shaderTexture[0].Sample(SampleType, input.tex);

float4 textureColor2 = shaderTexture[1].Sample(SampleType, input.tex);

float4 bumpMap;

float3 bumpNormal;

//從範圍[0,1]轉換到[-1,1],因為預設法向圖我們用[0,1]的這種方式打開

bumpMap  = (textureColor2 * 2.0f) - 1.0f;

N = input.worldnormal + bumpMap.x*input.worldtangent + bumpMap.y*input.worldbinormal;

N = normalize(N);

程式執行後,我們按R鍵,可以得到下面的結果:

Directx11教程(42) 紋理映射(12)-簡單的bump mapping

因為使用的是面法向,我們再看側面,有着不同效果,:

Directx11教程(42) 紋理映射(12)-簡單的bump mapping

完整的代碼請參考:

工程檔案myTutorialD3D11_37

代碼下載下傳:

<a href="http://files.cnblogs.com/mikewolf2002/d3d1127-28.zip">http://files.cnblogs.com/mikewolf2002/d3d1127-28.zip</a>

<a href="http://files.cnblogs.com/mikewolf2002/pictures.zip">http://files.cnblogs.com/mikewolf2002/pictures.zip</a>

繼續閱讀