新建網頁 1
在像素著色器中使用HLSL的內建函數tex*XXXX給紋理采樣。注意:采樣時引用紋理上圖素的坐標索引和采樣器狀態來生成像素。
通常這些函數需要我們做2件事:
使用紋理中的索引建立(u, v)紋理坐標。
給特定的紋理中編入索引。
將紋理坐標(u, v)輸入到像素著色器,在一個指定的HLSL對象中的像素著色器中,我們想編入索引的紋理是在像素著色器中被定義過的,在HLSL中叫作采樣器。(The particular texture that we want to index into is identified in the pixel shader by a special HLSL object called a sampler.),我們可以把采樣器對象想象成定義紋理和采樣器階段的對象。例如:假如我們使用3張紋理,這意味著我們需要在像素著色器里能夠引用3個階段中的每個一個。在像素著色器中我們這樣寫:
sampler FirstTex;
sampler SecondTex;
sampler ThirdTex;
|
Direct3D將給每個采樣器對象連接一個唯一的紋理級別(stage),在應用程序中我們找出與采樣器對象相關聯的階段,并設置相應的紋理和采樣器狀態給該階段。下列代碼將舉例說明如何在應用程序中設置紋理并把采樣器狀態設置為FirstTex:
// 創建
IDirect3DTexture9* Tex;
D3DXCreateTextureFromFile(Device, "tex.bmp", &Tex);
… …
// 取得常量FirstTex的句柄
FirstTexHandle = MultiTexCT->GetConstantByName(0, "FirstTex");
// 取得常量的描述
D3DXCONSTANT_DESC FirstTexDesc;
UINT count;
MultiTexCT->GetConstantDesc(FirstTexHandle, &FirstTexDesc, &count);
… …
// 為FirstTex設置紋理和采樣器狀態.
// We identify the stage FirstTex is associated with from the D3DXCONSTANT_DESC::RegisterIndex member:
Device->SetTexture(FirstTexDesc.RegisterIndex, Tex);
Device->SetSamplerState(FirstTexDesc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
Device->SetSamplerState(FirstTexDesc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
Device->SetSamplerState(FirstTexDesc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
|
注意:作為選擇,替換使用采樣器類型,你可以使用更多特殊的、強大的類型,如:sampler1D,sampler2D,sampler3D,和samplerCube類型,這些類型更安全并且它們只使用tex*函數。例如:一個sampler2D對象只使用tex2D*函數,同樣一個sampler3D對象只使用tex3D*函數。
18.5例子程序:Multitexturing in a Pixel Shader
這章中的例子演示了在像素著色器中使用多紋理,這個例子渲染的目標是一個木箱紋理,一個聚光燈紋理,和一個包含字符串的紋理。這就是例子程序:Pixel Shader。

這個例子可以不使用像素著色器來實現,但實現這個程序是簡單直接,它允許我們示范如何編寫,創建,而且使用像素著色器實現一些特效不必使用那些復雜的算法。
雖然在這個例子中一次只使用3張紋理,檢查采樣器對象的成員以確定每個像素著色器能夠使用的版本,這是值得的。換句話說,我們一次能使用多少紋理,這依賴于使用的像素著色器的版本:
像素著色器的版本ps_1_1到 ps_1_3支持4個紋理采樣器。
像素著色器的版本ps_1_4支持6個紋理采樣器。
像素著色器的版本ps_2_0到 ps_3_0支持16個紋理采樣器。
/******************************************************************************
Pixel shader that does multi texturing.
******************************************************************************/
sampler g_base_texture;
sampler g_spotlight_texture;
sampler g_string_texture;
struct sPixelInput
{
float2 base : TEXCOORD0;
float2 spotlight : TEXCOORD1;
float2 text : TEXCOORD2;
};
struct sPixelOutput
{
vector diffuse : COLOR0;
};
/////////////////////////////////////////////////////////////////////////////////
sPixelOutput main(sPixelInput input)
{
sPixelOutput output = (sPixelOutput) 0;
// sample appropriate textures
vector base_color = tex2D(g_base_texture, input.base);
vector spotlight_color = tex2D(g_spotlight_texture, input.spotlight);
vector text_color = tex2D(g_string_texture, input.text);
// combine texel colors
vector color = base_color * spotlight_color + text_color;
// increase the intensity of the pixel slightly
color += 0.1f;
// save the resulting pixel color
output.diffuse = color;
return output;
}
tex2D的函數使用說明如下:
There are two overloaded tex2D texture lookup functions:
- 2D texture lookup
- 2D texture lookup with partial derivatives
2D texture lookup
This function performs a 2D texture lookup.
Syntax
Where:
Name | In/Out | Template Type | Component Type | Size |
s |
in |
object |
sampler2D |
1 |
t |
in |
vector |
float |
2 |
ret |
out |
vector |
float |
4 |
2D texture lookup with partial derivatives
This function performs a 2D texture lookup also, but also uses the partial derivatives to help pick the LOD.
Syntax
ret tex2D(s, t, ddx, ddy) |
Where:
Name | In/Out | Template Type | Component Type | Size |
s |
in |
object |
sampler2D |
1 |
t |
in |
vector |
float |
2 |
ddx |
in |
vector |
float |
2 |
ddy |
in |
vector |
float |
2 |
ret |
out |
vector |
float |
4 |
首先像素著色器定義了3個sampler對象,要渲染的每個紋理,接下來定義是input和output結構。注意:我們沒有將任何的顏色值輸入到像素著色器中,這是因為我們使用紋理自己的顏色和光照;即BaseTex保存表面的顏色,SpotLightTex是光照圖。像素著色器輸出只一個簡顏色值,指定了我們計算過的這個特定像素的顏色。
Main函數使用tex2D函數采樣3個紋理,即它取得每個紋理的圖素,計算映射到的像素,這通常依賴于指定的紋理坐標和采樣器對象。然后我們混合圖素的顏色用公式:c = b * s + t。接下來我們讓全部的像素變亮一個bit,給每個部分增加0.1f。最后我們保存結果像素顏色并返回它。
執行程序:
/**************************************************************************************************
Deomstrates multi-texturing using a pixel shader. You will have to switch to the REF
device to run this sample if your hardware doesn't support pixel shaders.
**************************************************************************************************/
#include "d3dUtility.h"
#pragma warning(disable : 4100)
struct sMultiTextureVertex
{
sMultiTextureVertex(float x, float y, float z,
float u0, float v0,
float u1, float v1,
float u2, float v2)
{
_x = x; _y = y; _z = z;
_u0 = u0; _v0 = v0;
_u1 = u1; _v1 = v1;
_u2 = u2, _v2 = v2;
}
float _x, _y, _z;
float _u0, _v0;
float _u1, _v1;
float _u2, _v2;
};
const DWORD MULTI_TEXTURE_VERTEX_FVF = D3DFVF_XYZ | D3DFVF_TEX3;
/////////////////////////////////////////////////////////////////////////////////////////////
const int WIDTH = 640;
const int HEIGHT = 480;
IDirect3DDevice9* g_device;
IDirect3DPixelShader9* g_pixel_shader;
ID3DXConstantTable* g_constant_table;
IDirect3DVertexBuffer9* g_vertex_buffer;
IDirect3DTexture9* g_base_texture;
IDirect3DTexture9* g_spotlight_texture;
IDirect3DTexture9* g_string_texture;
D3DXHANDLE g_base_texture_handle;
D3DXHANDLE g_spotlight_texture_handle;
D3DXHANDLE g_string_texture_handle;
D3DXCONSTANT_DESC g_base_texture_desc;
D3DXCONSTANT_DESC g_spotlight_texture_desc;
D3DXCONSTANT_DESC g_string_texture_desc;
////////////////////////////////////////////////////////////////////////////////////////////////////
bool setup()
{
// create geometry
g_device->CreateVertexBuffer(6 * sizeof(sMultiTextureVertex), D3DUSAGE_WRITEONLY,
MULTI_TEXTURE_VERTEX_FVF, D3DPOOL_MANAGED, &g_vertex_buffer, NULL);
sMultiTextureVertex* v;
g_vertex_buffer->Lock(0, 0, (void**)&v, 0);
v[0] = sMultiTextureVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
v[1] = sMultiTextureVertex(-10.0f, 10.0f, 5.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
v[2] = sMultiTextureVertex( 10.0f, 10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
v[3] = sMultiTextureVertex(-10.0f, -10.0f, 5.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
v[4] = sMultiTextureVertex( 10.0f, 10.0f, 5.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f);
v[5] = sMultiTextureVertex( 10.0f, -10.0f, 5.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f);
g_vertex_buffer->Unlock();
// compile shader
ID3DXBuffer* shader_buffer;
ID3DXBuffer* error_buffer;
HRESULT hr = D3DXCompileShaderFromFile("MultiTextureShader.cxx", NULL, NULL, "main", "ps_2_0", D3DXSHADER_DEBUG,
&shader_buffer, &error_buffer, &g_constant_table);
// output any error messages
if(error_buffer)
{
MessageBox(NULL, (char*) error_buffer->GetBufferPointer(), "ERROR", MB_OK);
safe_release<ID3DXBuffer*>(error_buffer);
}
if(FAILED(hr))
{
MessageBox(NULL, "D3DXCompileShaderFromFile() - FAILED", "ERROR", MB_OK);
return false;
}
hr = g_device->CreatePixelShader((DWORD*) shader_buffer->GetBufferPointer(), &g_pixel_shader);
if(FAILED(hr))
{
MessageBox(NULL, "CreatePixelShader - FAILED", "ERROR", MB_OK);
return false;
}
safe_release<ID3DXBuffer*>(shader_buffer);
// load textures
D3DXCreateTextureFromFile(g_device, "crate.bmp", &g_base_texture);
D3DXCreateTextureFromFile(g_device, "spotlight.bmp", &g_spotlight_texture);
D3DXCreateTextureFromFile(g_device, "text.bmp", &g_string_texture);
// get handles
g_base_texture_handle = g_constant_table->GetConstantByName(NULL, "g_base_texture");
g_spotlight_texture_handle = g_constant_table->GetConstantByName(NULL, "g_spotlight_texture");
g_string_texture_handle = g_constant_table->GetConstantByName(NULL, "g_string_texture");
// set constant descriptions
UINT count;
g_constant_table->GetConstantDesc(g_base_texture_handle, &g_base_texture_desc, &count);
g_constant_table->GetConstantDesc(g_spotlight_texture_handle, &g_spotlight_texture_desc, &count);
g_constant_table->GetConstantDesc(g_string_texture_handle, &g_string_texture_desc, &count);
g_constant_table->SetDefaults(g_device);
// set the projection matrix
D3DXMATRIX proj;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI/4.0f, (float)WIDTH/HEIGHT, 1.0f, 1000.0f);
g_device->SetTransform(D3DTS_PROJECTION, &proj);
//g_device->SetRenderState(D3DRS_FILLMODE, D3DFILL_WIREFRAME);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
void cleanup()
{
safe_release<IDirect3DVertexBuffer9*>(g_vertex_buffer);
safe_release<IDirect3DTexture9*>(g_base_texture);
safe_release<IDirect3DTexture9*>(g_spotlight_texture);
safe_release<IDirect3DTexture9*>(g_string_texture);
safe_release<IDirect3DPixelShader9*>(g_pixel_shader);
safe_release<ID3DXConstantTable*>(g_constant_table);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
bool display(float time_delta)
{
// update the scene: allow user to rotate around scene.
static float angle = (3.0f * D3DX_PI) / 2.0f;
static float radius = 20.0f;
if(GetAsyncKeyState(VK_LEFT) & 0x8000f)
angle -= 0.5f * time_delta;
if(GetAsyncKeyState(VK_RIGHT) & 0x8000f)
angle += 0.5f * time_delta;
if(GetAsyncKeyState(VK_UP) & 0x8000f)
radius -= 2.0f * time_delta;
if(GetAsyncKeyState(VK_DOWN) & 0x8000f)
radius += 2.0f * time_delta;
D3DXVECTOR3 position(cosf(angle) * radius, 0.0f, sinf(angle) * radius);
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);
g_device->SetTransform(D3DTS_VIEW, &view_matrix);
// render now
g_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0xFFFFFFFF, 1.0f, 0);
g_device->BeginScene();
g_device->SetPixelShader(g_pixel_shader);
g_device->SetFVF(MULTI_TEXTURE_VERTEX_FVF);
g_device->SetStreamSource(0, g_vertex_buffer, 0, sizeof(sMultiTextureVertex));
// base texture
g_device->SetTexture(g_base_texture_desc.RegisterIndex, g_base_texture);
g_device->SetSamplerState(g_base_texture_desc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(g_base_texture_desc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(g_base_texture_desc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
// spotlight texture
g_device->SetTexture(g_spotlight_texture_desc.RegisterIndex, g_spotlight_texture);
g_device->SetSamplerState(g_spotlight_texture_desc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(g_spotlight_texture_desc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(g_spotlight_texture_desc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
// string texture
g_device->SetTexture(g_string_texture_desc.RegisterIndex, g_string_texture);
g_device->SetSamplerState(g_string_texture_desc.RegisterIndex, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(g_string_texture_desc.RegisterIndex, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_device->SetSamplerState(g_string_texture_desc.RegisterIndex, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
g_device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2);
g_device->EndScene();
g_device->Present(NULL, NULL, NULL, NULL);
return true;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK wnd_proc(HWND hwnd, UINT msg, WPARAM word_param, LPARAM long_param)
{
switch(msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
if(word_param == VK_ESCAPE)
DestroyWindow(hwnd);
break;
}
return DefWindowProc(hwnd, msg, word_param, long_param);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE inst, HINSTANCE, PSTR cmd_line, int cmd_show)
{
if(! init_d3d(inst, WIDTH, HEIGHT, true, D3DDEVTYPE_HAL, &g_device))
{
MessageBox(NULL, "init_d3d() - failed.", 0, MB_OK);
return 0;
}
if(! setup())
{
MessageBox(NULL, "Steup() - failed.", 0, MB_OK);
return 0;
}
enter_msg_loop(display);
cleanup();
g_device->Release();
return 0;
}
setup函數執行下列功能:
填充方形的頂點緩存
編譯著像素色器
創建像素色器
讀取紋理
設置投影矩陣,不使用光照
取得采樣器(sampler)對象的句柄
取得采樣器對象的描述
display函數設置像素著色器,使用2個紋理,并且在渲染方格前設置他們對應的采樣器狀態。
運行截圖:

下載源程序