我正在学习 DirectX 效果,我知道所有固定的管道渲染状态都可以在 .fx 文件中设置,当我想在 .fx 文件中设置点光源时,如何计算最终的像素颜色?光[0] 是从哪里来的?下面是 .fx 文件的代码,我不知道如何编写像素着色器部分(BasicPS)来计算最终颜色。
// World, View and Projection Matrix
uniform extern float4x4 gWVP;
// Output Vertex structure
struct OutputVS
{
float4 posH : POSITION0;
};
OutputVS BasicVS(float4 posL : POSITION0)
{
// Zero out our output.
OutputVS outVS = (OutputVS)0;
// Transform to homogeneous clip space.
outVS.posH = mul(posL, gWVP);
// Done--return the output.
return outVS;
}
float4 BasicPS() : COLOR
{
//What to write here?
}
technique Tech1
{
pass p0
{
vertexShader = compile vs_2_0 BasicVS();
pixelShader = compile ps_2_0 BasicPS();
Lighting = True;
LightEnable[0] = True;
LightType[0] = POINT;
// Light color is white
LightAmbient[0] = {0.6f, 0.6f, 0.6f, 0.0f};
LightDiffuse[0] = {1.0f, 1.0f, 1.0f, 0.0f};
LightSpecular[0] = {0.6f, 0.6f, 0.6f, 0.0f};
// Light position
LightPosition[0] = {10.0f, 10.0f, -5.0f};
// Light range
LightRange[0] = 1000.0f;
// Light falloff
LightFalloff[0] = 1.0f;
// Attenuations
LightAttenuation0[0] = 1.0f;
LightAttenuation1[0] = 0.0f;
LightAttenuation2[0] = 0.0f;
}
}
the cpp file of this program as below
#include <d3dx9.h>
#include <MMSystem.h>
LPDIRECT3D9 g_pD3D = NULL ; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL ; // Our rendering device
ID3DXMesh* g_pTeapotMesh = NULL ; // Hold the teapot
ID3DXEffect* g_pEffect = NULL ; // Effect interface
bool g_bActive = true ; // Is window active?
// Handles for effects
D3DXHANDLE g_hWVP; // world, view and projection matrix handle.
D3DXHANDLE g_hTech; // Technique handle
#define SAFE_RELEASE(P) if(P){ P->Release(); P = NULL;}
HRESULT BuildEffect()
{
char* effectFile = "./PointLight.fx";
ID3DXBuffer* errors = 0;
// Create Effect from file
HRESULT hr = D3DXCreateEffectFromFile(
g_pd3dDevice,
effectFile,
NULL,
NULL,
D3DXSHADER_DEBUG,
NULL,
&g_pEffect,
&errors);
if( errors )
MessageBox(0, (char*)errors->GetBufferPointer(), 0, 0);
g_hWVP = g_pEffect->GetParameterByName(0, "gWVP");
g_hTech = g_pEffect->GetTechniqueByName("Tech1");
return D3D_OK;
}
HRESULT SetupPointLight()
{
D3DLIGHT9 pointLight;
ZeroMemory(&pointLight, sizeof(pointLight));
// Set light
g_pd3dDevice->SetLight(0, &pointLight);
return D3D_OK;
}
HRESULT SetupMaterial()
{
D3DMATERIAL9 material;
ZeroMemory(&material, sizeof(material));
D3DXCOLOR red = D3DCOLOR_XRGB(255, 0, 0);
material.Ambient = red;
material.Diffuse = red;
material.Specular = red;
material.Emissive = D3DXCOLOR(0, 0, 0, 0);
material.Power = 2.0f; // only affect specular color
g_pd3dDevice->SetMaterial(&material);
return D3D_OK;
}
HRESULT InitD3D( HWND hWnd )
{
// Create the D3D object, which is needed to create the D3DDevice.
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
{
MessageBoxA(NULL, "Create D3D9 object failed!", "Error", 0) ;
return E_FAIL;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = TRUE; // use window mode, not full screen
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
// Create device
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
MessageBoxA(NULL, "Create D3D9 device failed!", "Error", 0) ;
return E_FAIL;
}
// Create teapot
D3DXCreateTeapot(g_pd3dDevice, &g_pTeapotMesh, NULL) ;
// Build effect
BuildEffect();
return S_OK;
}
void DrawTeapot()
{
// translate model to origin
D3DXMATRIX world ;
D3DXMatrixTranslation(&world, 0.0f, 0.0f, 0.0f) ;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &world) ;
// set view
D3DXVECTOR3 eyePt(0.0f, 0.0f, -10.0f) ;
D3DXVECTOR3 upVec(0.0f, 1.0f, 0.0f) ;
D3DXVECTOR3 lookCenter(0.0f, 0.0f, 0.0f) ;
D3DXMATRIX view ;
D3DXMatrixLookAtLH(&view, &eyePt, &lookCenter, &upVec) ;
g_pd3dDevice->SetTransform(D3DTS_VIEW, &view) ;
// set projection
D3DXMATRIX proj ;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4, 1.0f, 1.0f, 1000.0f) ;
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;
D3DXMATRIX worldviewproj = world * view * proj;
// Set matrix
g_pEffect->SetMatrix(g_hWVP, &worldviewproj);
// Set technique
g_pEffect->SetTechnique(g_hTech);
// Render pass
UINT numPass = 0;
g_pEffect->Begin(&numPass, 0);
g_pEffect->BeginPass(0);
g_pTeapotMesh->DrawSubset(0);
g_pEffect->EndPass();
g_pEffect->End();
}
VOID Cleanup()
{
SAFE_RELEASE(g_pTeapotMesh) ;
SAFE_RELEASE(g_pd3dDevice) ;
SAFE_RELEASE(g_pD3D) ;
}
void Render(float timeDelta)
{
if (!g_bActive)
{
Sleep(50) ;
}
SetupMaterial();
SetupPointLight();
// Clear the back-buffer to a RED color
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
// Draw teapot
DrawTeapot();
// End the scene
g_pd3dDevice->EndScene();
}
// Present the back-buffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
SendMessage( hWnd, WM_CLOSE, 0, 0 );
break ;
default:
break ;
}
}
return 0 ;
case WM_SIZE:
if(wParam == SIZE_MAXHIDE || wParam == SIZE_MINIMIZED)
g_bActive = false;
else
g_bActive = true;
return 0;
case WM_ACTIVATEAPP:
if(wParam == TRUE)
g_bActive = true ;
else
g_bActive = false ;
return 0 ;
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR szCmdLine, int iCmdShow)
{
WNDCLASSEX winClass ;
winClass.lpszClassName = "Teapot";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = MsgProc;
winClass.hInstance = hInstance;
winClass.hIcon = NULL ;
winClass.hIconSm = NULL ;
winClass.hCursor = LoadCursor(NULL, IDC_ARROW) ;
winClass.hbrBackground = NULL ;
winClass.lpszMenuName = NULL ;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
RegisterClassEx (&winClass) ;
HWND hWnd = CreateWindowEx(NULL,
winClass.lpszClassName, // window class name
"Teapot", // window caption
WS_OVERLAPPEDWINDOW, // window style
32, // initial x position
32, // initial y position
600, // initial window width
600, // initial window height
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
// Create window failed
if(hWnd == NULL)
{
MessageBoxA(hWnd, "Create Window failed!", "Error", 0) ;
return -1 ;
}
// Initialize Direct3D
if( SUCCEEDED(InitD3D(hWnd)))
{
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
MSG msg ;
ZeroMemory( &msg, sizeof(msg) );
PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
// Get last time
static DWORD lastTime = timeGetTime();
while (msg.message != WM_QUIT)
{
if(PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) != 0)
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
else // Render the game if there is no message to process
{
// Get current time
DWORD currTime = timeGetTime();
// Calculate time elapsed
float timeDelta = (currTime - lastTime) * 0.001f;
// Render
Render(timeDelta) ;
// Update last time to current time for next loop
lastTime = currTime;
}
}
}
UnregisterClass(winClass.lpszClassName, hInstance) ;
return 0;
}