頂點着色器替代了固定渲染管線中的 變幻 和 光照 階段.
實現步驟:
1.在文本文件裏編寫頂點着色器代碼(HLSL語言)
2.編譯着色器代碼(D3DXCompileShaderFromFile)
3.創建頂點着色器(CreateVertexShader)
4.獲取HLSL語言中變量句柄(GetConstantByName)
5.根據句柄給HLSL語言中的變量傳值(ID3DXConstTable->Setxxx)??
在文本文件裏寫頂點着色器代碼:
//----------------------------------begin VertexShader.txt--------------------------------------------
//世界-觀察 矩陣
matrix g_world_view;
//世界-觀察-投影 矩陣
matrix g_world_view_proj;
//顏色
vector g_color;
//光線方向
vector g_dir_to_light;
//輸入
struct VTIN
{
vector pos :POSITION; //輸入:位置
vector normal : NORMAL; //輸入:法線
};
//輸出
struct VTOUT
{
vector pos : POSITION; //輸出:位置
float2 uv : TEXCOORD; //輸出:紋理座標
vector diffuse : COLOR; //輸出:顏色
};
//函數入口
VTOUT main(VTIN input)
{
//初始化輸出結構
VTOUT output = (VTOUT)0;
//pos由建模空間-世界空間-觀察空間-投影空間 變幻
output.pos = mul(input.pos, g_world_view_proj);
//轉換光線和法線到觀察空間,設置w分量爲0
//確保沒有縮放變幻,因爲縮放會弄亂法線的方向
g_dir_to_light.w = 0.0f;
input.normal.w = 0.0f;
g_dir_to_light = mul(g_dir_to_light, g_world_view);
input.normal = mul(input.normal, g_world_view);
//計算出uv
//其實只要用到紋理的x(即u)就行了
float u = dot(g_dir_to_light, input.normal);
//如果u<0.0f,說明角度大於90°,接受不到光線,so
if(u < 0.0f)
{
u = 0.0f;
}
float v = 0.5f; //紋理圖片y軸像素(0.0f~1.0f)
output.uv.x = u;
output.uv.y = v;
output.diffuse = g_color;
return output;
}
//----------------------------------end VertexShader.txt--------------------------------------------
<pre class="cpp" name="code">//vs中程序代碼:
#define MESH_TEAPOT 0
#define MESH_SPHERE 1
#define MESH_TORUS 2
#define MESH_CYLINDER 3
//-----------頂點着色器相關的變量------------------
IDirect3DVertexShader9* m_VertexShader;
ID3DXConstantTable* m_ConstantTable;
IDirect3DTexture9* m_ShadeTexture;
ID3DXMesh* m_Meshes[4];
D3DXMATRIX m_WorldMatrices[4];
D3DXVECTOR4 m_MeshColors[4];
D3DXMATRIX m_ProjMatrix;
D3DXHANDLE m_WorldViewHandle;
D3DXHANDLE m_WorldViewProjHandle;
D3DXHANDLE m_ColorHandle;
D3DXHANDLE m_DirLightHandle;
//setup: main函數中調用一次
void Setup()
{
//創建模型們: 茶壺 圓球 圓環 圓桶
D3DXCreateTeapot(D3DDevice, &m_Meshes[MESH_TEAPOT], NULL);
D3DXCreateSphere(D3DDevice, 1.0f, 20, 20, &m_Meshes[MESH_SPHERE], NULL);
D3DXCreateTorus(D3DDevice, 0.5f, 1.0f, 20, 20, &m_Meshes[MESH_TORUS], NULL);
D3DXCreateCylinder(D3DDevice, 0.5f, 0.5f, 2.0f, 20, 20, &m_Meshes[MESH_CYLINDER], NULL);
//模型們的在世界中的矩陣:
D3DXMatrixTranslation(&m_WorldMatrices[MESH_TEAPOT], 0.0f, 2.0f, 0.0f);
D3DXMatrixTranslation(&m_WorldMatrices[MESH_SPHERE], 0.0f, -2.0f, 0.0f);
D3DXMatrixTranslation(&m_WorldMatrices[MESH_TORUS], -3.0f, 0.0f, 0.0f);
D3DXMatrixTranslation(&m_WorldMatrices[MESH_CYLINDER], 3.0f, 0.0f, 0.0f);
//模型們的顏色:
m_MeshColors[MESH_TEAPOT] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
m_MeshColors[MESH_SPHERE] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
m_MeshColors[MESH_TORUS] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
m_MeshColors[MESH_CYLINDER] = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
//編譯着色器:
ID3DXBuffer* shader_buffer;
ID3DXBuffer* error_buffer;
HRESULT hr = D3DXCompileShaderFromFile(L"D:\\VertexShader.txt", NULL, NULL, "main", "vs_1_1",
D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY,
&shader_buffer, &error_buffer, &m_ConstantTable);
// 輸出錯誤信息:
if (error_buffer)
{
string str = (char*)error_buffer->GetBufferPointer();
MessageBox(NULL, Common::StringToWString(str).c_str(), L"ERROR", MB_OK);
//safe_release<ID3DXBuffer*>(error_buffer);
}
if (FAILED(hr))
{
MessageBox(NULL, L"D3DXCreateEffectFromFile() - FAILED", L"ERROR", MB_OK);
}
//創建頂點着色器
hr = D3DDevice()CreateVertexShader((DWORD*)shader_buffer->GetBufferPointer(), &m_VertexShader);
if (FAILED(hr))
{
MessageBox(NULL, L"CreateVertexShader - FAILED", L"ERROR", MB_OK);
}
//釋放
//safe_release<ID3DXBuffer*>(shader_buffer);
//加載紋理:
D3DXCreateTextureFromFile(D3DDevice, L"D:\\pic1.png", &m_ShadeTexture);
//設置狀態屬性:
D3DDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT);
D3DDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE);//禁用過濾
//獲取常量句柄
m_WorldViewHandle = m_ConstantTable->GetConstantByName(NULL, "g_world_view");
m_WorldViewProjHandle = m_ConstantTable->GetConstantByName(NULL, "g_world_view_proj");
m_ColorHandle = m_ConstantTable->GetConstantByName(NULL, "g_color");
m_DirLightHandle = m_ConstantTable->GetConstantByName(NULL, "g_dir_to_light");
// set shader constants
D3DXVECTOR4 dir_to_light(-0.57f, 0.57f, -0.57f, 0.0f);
m_ConstantTable->SetVector(D3DDevice, m_DirLightHandle, &dir_to_light);
m_ConstantTable->SetDefaults(D3DDevice);
//設置投影矩陣
RECT rt;
GetClientRect(hwnd, &rt);
D3DXMatrixPerspectiveFovLH(&m_ProjMatrix, D3DX_PI / 4.0f, (float)rt.right / rt.bottom, 1.0f, 1000.0f);
}
//display: 在消息循環中調用,時時更新
void Display(float timeDelta)
{
static float angle = (3.0f * D3DX_PI) / 2.0f;
static float height = 5.0f;
if (GetAsyncKeyState(VK_LEFT) & 0x8000f)
angle -= 0.5f * timeDelta;
if (GetAsyncKeyState(VK_RIGHT) & 0x8000f)
angle += 0.5f * timeDelta;
if (GetAsyncKeyState(VK_UP) & 0x8000f)
height += 5.0f * timeDelta;
if (GetAsyncKeyState(VK_DOWN) & 0x8000f)
height -= 5.0f * timeDelta;
D3DXVECTOR3 position(cosf(angle) * 7.0f, height, sinf(angle) * 7.0f);
D3DXVECTOR3 target(0.0f, 0.0f, 0.0f);
D3DXVECTOR3 up(0.0f, 1.0f, 0.0f);
D3DXMATRIX view_matrix;
D3DXMatrixLookAtLH(&view_matrix, &position, &target, &up);
// render now
D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x00000000, 1.0f, 0);
D3DDevice->BeginScene();
D3DDevice->SetVertexShader(m_VertexShader);
D3DDevice->SetTexture(0, m_ShadeTexture);
D3DXMATRIX world_view, world_view_proj;
for (int i = 0; i < 4; i++)
{
world_view = m_WorldMatrices[i] * view_matrix;
world_view_proj = m_WorldMatrices[i] * view_matrix * m_ProjMatrix;
m_ConstantTable->SetMatrix(D3DDevice, m_WorldViewHandle, &world_view);
m_ConstantTable->SetMatrix(D3DDevice, m_WorldViewProjHandle, &world_view_proj);
m_ConstantTable->SetVector(D3DDevice, m_ColorHandle, &m_MeshColors[i]);
m_Meshes[i]->DrawSubset(0);
}
D3DDevice()->EndScene();
D3DDevice()->Present(NULL, NULL, NULL, NULL);
}