像素着色器实现多重纹理,首先需要用HLSL语法写出相关代码,保存为一个文件,然后调用D3DXCompileShaderFromFile接口进行编译。还有一种方式是:通过fxc.exe工具编译那个文件。代码里读取文件,然后直接创建着色器。
着色器文件内容如下:
// 静态采样器
sampler sStatic : register(s0);
// 文字采样器
sampler sText : register(s1);
// 像素着色器
vector PSMain(float4 pos : SV_POSITION, float4 diffuse : COLOR0, float2 tStatic : TEXCOORD0, float2 tText : TEXCOORD1) : SV_TARGET
{
vector v = {0.0,255.0,0.0,0.0};
return (tex2D(sStatic, tStatic) + tex2D(sText,tText)*v);
}
如果函数就是PSMain,当然名字可以随便取。这个函数的功能是:tStatic纹理与tText纹理像素相加,tText纹理改变其颜色为绿色。然后这里输入参数是与代码里定义的顶点格式是一一对应的。
再就是:用了着色器,固定管道就变为了可编程管道。
下面是实现的代码:
#include <Windows.h>
#include <D3D9.h>
#include <D3dx9tex.h>
#pragma comment(lib, "D3D9.lib")
#pragma comment(lib, "D3dx9.lib")
const TCHAR *kClassName = L"Rectangle_D3D";
const int kWndWidth = 640;
const int kWndHeight = 480;
const int kTextureWidth = 256;
const int kTextureHeight = 256;
#define D3D_FVF_VECTOR (D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX2)
IDirect3D9 *d3d9 = nullptr;
IDirect3DDevice9 *device9 = nullptr;
IDirect3DVertexBuffer9 *vectex_buffer9 = nullptr;
IDirect3DPixelShader9* multi_tex_ps = 0;
ID3DXConstantTable* multi_tex_table = nullptr;
D3DPRESENT_PARAMETERS params;
BOOL window_mode = TRUE;
HINSTANCE kInstance = nullptr;
struct Vector {
Vector(float v_x, float v_y, float v_z, DWORD c, float v_u, float v_v, float v_u2, float v_v2)
: x(v_x),
y(v_y),
z(v_z),
color(c),
u(v_u),
v(v_v),
text_u(v_u2),
text_v(v_v2) {
rhw = 1.0f;
}
float x, y, z, rhw;
DWORD color;
float u, v;
float text_u, text_v;//文字纹理
};
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
bool InitD3D(HWND hwnd);//初始化
bool Done();//完成
bool ReDrawRectangle();
void DrawTextTexture(HWND hwnd);
void DrawPicTexture(HWND hwnd);
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
) {
kInstance = hInstance;
//init app
WNDCLASSEX wndclassex;
wndclassex.cbSize = sizeof(WNDCLASSEX);
wndclassex.style = CS_HREDRAW | CS_VREDRAW;
wndclassex.lpfnWndProc = WindowProc;
wndclassex.cbClsExtra = 0;
wndclassex.cbWndExtra = 0;
wndclassex.hInstance = hInstance;
wndclassex.hIcon = nullptr;
wndclassex.hCursor = LoadCursor(hInstance, IDC_ARROW);
wndclassex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wndclassex.lpszMenuName = nullptr;
wndclassex.lpszClassName = kClassName;
wndclassex.hIconSm = nullptr;
RegisterClassEx(&wndclassex);
HWND hwnd = CreateWindowEx(0, kClassName, L"斧王报道,中路英雄失踪", WS_OVERLAPPEDWINDOW, 100, 100, 640, 480, nullptr, nullptr, hInstance, nullptr);
ShowWindow(hwnd, nCmdShow);
InitD3D(hwnd);
UpdateWindow(hwnd);
MSG msg;
while (true) {
if (PeekMessage(&msg,nullptr, 0, 0, PM_REMOVE)) {
if (msg.message == WM_QUIT) {
break;
}
::TranslateMessage(&msg);
::DispatchMessage(&msg);
}
}
Done();
return 0;
}
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
) {
PAINTSTRUCT ps;
HDC hdc;
if (uMsg == WM_PAINT) {
hdc = BeginPaint(hwnd, &ps);
ReDrawRectangle();
EndPaint(hwnd, &ps);
}else if (uMsg == WM_DESTROY) {
PostMessage(hwnd, WM_QUIT, 0, 0);
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
bool InitD3D(HWND hwnd) {
d3d9 = Direct3DCreate9(D3D_SDK_VERSION);
if (nullptr == d3d9) {
return false;
}
params.BackBufferWidth = kWndWidth;
params.BackBufferHeight = kWndHeight;
params.BackBufferFormat = D3DFMT_X8R8G8B8;
params.BackBufferCount = 1;
params.MultiSampleType = D3DMULTISAMPLE_NONE;
params.MultiSampleQuality = 0;
params.SwapEffect = D3DSWAPEFFECT_COPY;
params.hDeviceWindow = hwnd;
params.Windowed = window_mode;
params.EnableAutoDepthStencil = FALSE;
params.AutoDepthStencilFormat = D3DFMT_UNKNOWN;
params.Flags = 0;
params.FullScreen_RefreshRateInHz = 0;
params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
HRESULT hr = d3d9->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, ¶ms, &device9);
if (FAILED(hr)) {
return false;
}
device9->SetRenderState(D3DRS_LIGHTING, false);
hr = device9->CreateVertexBuffer(12 * sizeof(Vector), 0, D3D_FVF_VECTOR, D3DPOOL_SYSTEMMEM, &vectex_buffer9, nullptr);
if (FAILED(hr)) {
return false;
}
// DrawText2(hwnd);
Vector *vectors;
vectex_buffer9->Lock(0, 0, (void**)&vectors, 0);
//创建Rectangle
vectors[0] = Vector(220, 340, 0, 0xffFFFFFF, 0, 1, 0, 1);
vectors[1] = Vector(220, 140, 0, 0xffFFFFFF, 0, 0, 0, 0);
vectors[2] = Vector(420, 140, 0, 0xffFFFFFF, 1, 0, 1, 0);
vectors[3] = Vector(220, 340, 0, 0xffFFFFFF, 0, 1, 0, 1);
vectors[4] = Vector(420, 140, 0, 0xffFFFFFF, 1, 0, 1, 0);
vectors[5] = Vector(420, 340, 0, 0xffFFFFFF, 1, 1, 1, 1);
vectex_buffer9->Unlock();
DrawPicTexture(hwnd);
DrawTextTexture(hwnd);
// device9->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_ADD);
//编译像素着色器
ID3DXBuffer* shader = 0;
ID3DXBuffer* errorBuffer = 0;
hr = D3DXCompileShaderFromFile(
L"effect_dx9_2048.fx",
0,
0,
"PSMain", // entry point function name
"ps_2_0",
D3DXSHADER_DEBUG,
&shader,
&errorBuffer,
&multi_tex_table);
hr = device9->CreatePixelShader(
(DWORD*)shader->GetBufferPointer(),
&multi_tex_ps);
multi_tex_table->SetDefaults(device9);
multi_tex_table->Release();
return true;
}
void DrawPicTexture(HWND hwnd) {
//加载图片
HDC mem_dc = CreateCompatibleDC(NULL);
HBITMAP hbitmap = static_cast<HBITMAP>(::LoadImage(kInstance, L"texture.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE));
HBITMAP old_bitmap = static_cast<HBITMAP>(SelectObject(mem_dc, hbitmap));
BITMAP bmp;
GetObject(hbitmap, sizeof(BITMAP), (LPBYTE)&bmp);
IDirect3DSurface9 *surface9 = nullptr;
HRESULT hr = device9->CreateOffscreenPlainSurface(bmp.bmWidth, bmp.bmHeight, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &surface9, nullptr);
if (FAILED(hr)) {
return;
}
DWORD pixel_pos;
D3DLOCKED_RECT lock_rect;
surface9->LockRect(&lock_rect, nullptr, 0);
BYTE* surface_buffer = static_cast<BYTE*>(lock_rect.pBits);
for (int h = 0; h < bmp.bmHeight; ++h) {
for (int w = 0; w < bmp.bmWidth; ++w) {
COLORREF color = GetPixel(mem_dc, w, h);
DWORD red = GetRValue(color);
DWORD green = GetGValue(color);
DWORD blue = GetBValue(color);
red <<= 16;
green <<= 8;
DWORD dwColor = red | green | blue;
pixel_pos = h * lock_rect.Pitch + w * 4;
memcpy(&surface_buffer[pixel_pos], &dwColor, 4);
}
}
surface9->UnlockRect();
SelectObject(mem_dc, old_bitmap);
ReleaseDC(hwnd, mem_dc);
device9->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
device9->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
// 创建纹理
IDirect3DTexture9 *texture9 = nullptr;
hr = device9->CreateTexture(kTextureWidth, kTextureHeight, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &texture9, 0);
if (FAILED(hr)) {
surface9->Release();
return;
}
IDirect3DSurface9 *texture_surface9 = nullptr;
texture9->GetSurfaceLevel(0, &texture_surface9);
RECT src;
::SetRect(&src, 0, 0, kTextureWidth, kTextureHeight);
POINT dest;
dest.x = 0;
dest.y = 0;
hr = device9->UpdateSurface(surface9, &src, texture_surface9, &dest);
texture_surface9->Release();
if (FAILED(hr)) {
surface9->Release();
return;
}
device9->SetTexture(0, texture9);
surface9->Release();
}
void DrawTextTexture(HWND hwnd) {
HDC hDc = ::CreateCompatibleDC(NULL); // 通过当前桌面创建设备内容HDC
SetTextColor(hDc, RGB(255, 255, 255)); // 设置背景颜色和文字的颜色
SetBkColor(hDc, 0xFFFF0000);
LOGFONT lf;
ZeroMemory(&lf, sizeof(LOGFONT));
lf.lfHeight = 25;
lf.lfWidth = 0;
HFONT hFont = CreateFontIndirect(&lf); // 创建大小为72的字体
SelectObject(hDc, hFont);
SIZE sz;
GetTextExtentPoint32(hDc, L"斧王报道,中路英雄失踪", lstrlen(L"斧王报道,中路英雄失踪"), &sz);
DWORD* pBitmapBits; // 创建一个位图
BITMAPINFO bitmapInfo;
ZeroMemory(&bitmapInfo.bmiHeader, sizeof(BITMAPINFOHEADER));
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = kTextureWidth;
bitmapInfo.bmiHeader.biHeight = kTextureHeight;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
bitmapInfo.bmiHeader.biBitCount = 32;
HBITMAP hBitmap = CreateDIBSection(hDc, &bitmapInfo, DIB_RGB_COLORS, (VOID**)&pBitmapBits, NULL, 0);
SelectObject(hDc, hBitmap); // 将位图与HDC关联,这样文字时间上就保存在hBitmap里面了
TextOut(hDc, 6, 100, L"斧王报道,中路英雄失踪", lstrlen(L"斧王报道,中路英雄失踪"));
BITMAP bmp;
GetObject(hBitmap, sizeof(BITMAP), &bmp);
IDirect3DSurface9 *surface9 = nullptr;
HRESULT hr = device9->CreateOffscreenPlainSurface(kTextureWidth, kTextureHeight, D3DFMT_X8R8G8B8, D3DPOOL_SYSTEMMEM, &surface9, nullptr);
if (FAILED(hr)) {
return;
}
DWORD pixel_pos;
D3DLOCKED_RECT lock_rect;
surface9->LockRect(&lock_rect, nullptr, 0);
BYTE* surface_buffer = static_cast<BYTE*>(lock_rect.pBits);
for (int h = 0; h < kTextureHeight; ++h) {
for (int w = 0; w < kTextureWidth; ++w) {
COLORREF color = GetPixel(hDc, w, h);
DWORD red = GetRValue(color);
DWORD green = GetGValue(color);
DWORD blue = GetBValue(color);
red <<= 16;
green <<= 8;
DWORD dwColor = red | green | blue;
pixel_pos = h * lock_rect.Pitch + w * 4;
memcpy(&surface_buffer[pixel_pos], &dwColor, 4);
}
}
surface9->UnlockRect();
//创建纹理
IDirect3DTexture9 *texture9x = nullptr;
hr = device9->CreateTexture(kTextureWidth, kTextureHeight, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &texture9x, 0);
if (FAILED(hr)) {
surface9->Release();
return;
}
IDirect3DSurface9 *texture_surface9 = nullptr;
texture9x->GetSurfaceLevel(0, &texture_surface9);
RECT src;
::SetRect(&src, 0, 0, kTextureWidth, kTextureHeight);
POINT dest;
dest.x = 0;
dest.y = 0;
hr = device9->UpdateSurface(surface9, &src, texture_surface9, &dest);
texture_surface9->Release();
if (FAILED(hr)) {
surface9->Release();
return;
}
hr = device9->SetTexture(1, texture9x);
surface9->Release();
DeleteObject(hFont);
DeleteObject(hBitmap);
DeleteDC(hDc);
// surface9->Release();
}
bool ReDrawRectangle() {
if (nullptr == device9) {
return false;
}
device9->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 255, 255, 255), 0.0f, 0);
device9->SetStreamSource(0, vectex_buffer9, 0, sizeof(Vector));
device9->SetPixelShader(multi_tex_ps);
device9->SetFVF(D3D_FVF_VECTOR);
device9->BeginScene();
device9->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 4);
device9->EndScene();
device9->Present(0, 0, 0, 0);
return true;
}
bool Done() {
if (nullptr != multi_tex_ps) {
multi_tex_ps->Release();
}
if (nullptr != vectex_buffer9) {
vectex_buffer9->Release();
}
if (nullptr != device9) {
device9->Release();
}
if (nullptr != d3d9) {
d3d9->Release();
}
return true;
}
效果图: