Guida alla Programmazione di Giochi con le DirectX di David Joffe
Capitolo 4: Un semplice esempio Direct3D
in modalità Retained
Qui mostrerò alcune basi, come i sistemi di coordinate, i sistemi di
coordinate globali e dell'oggetto, etc. Per ora presupporrò che abbiate
almeno un po' familiarità con la programmazione 3D. Blah blah blah, differenze
tra modalità immediate e retained, etc etc.
4.1.1 Devices Direct3D si interfaccia con la superficie che sta renderizzando (es. screen
memory, system memory) utilizzando un oggetto IDirect3DRMDevice. Può
esistere più di un tipo di device di renderizzazione e un device di renderizzazione
specifico deve essere scelto per una scena. Per esempio, c'è normalmente
un device per il rendering RGB e un device per il rendering Mono (questi nomi
si riferiscono al modello di illuminazione utilizzato per il rendering. Mono
significa che nella scena possono esistere solo le luci bianche, mentre RGB
supporta le luci colorate, perciò è più lento). Possono
essere installati devices aggiuntivi che permettono l'uso dell'accelerazione
hardware 3D. E' possibile reiterare tutti i devices D3D installati contandoli
dal primo all'ultimo (EnumDevices). E' possibile avere due devices differenti
che renderizzano la stessa superficie.
4.1.2 Viewports L'oggetto IDirect3DRMViewport è usato per tenere traccia di come
viene renderizzata nel device la nostra scena 3D. E' possibile avere viewports
multipli per device, ed è anche possibile avere un viewport del rendering
di più di un device. L'oggetto viewport object tiene traccia della telecamera,
campi di clipping frontali e posteriori, campi visivi, etc.
4.1.3 Frames Un frame in Direct3D è fondamentalmente usato per immagazzinare
la posizione di un oggetto e le informazioni sul suo orientamento, relativa
ad un dato frame di riferimento, che è da dove deriva il termine
frame. I frames vengono posizionati in relazione ad altri frames, oppure
alle coordinate globali. I frames vengono usati per immagazzinare le posizioni
degli oggetti nella scena, così come altre cose come le luci. OK, così
mi sto spiegando in maniera scorretta. E' tardi, sono stanco, lo correggerò
presto. Per aggiungere un oggetto alla scena, dobbiamo collegare l'oggetto ad
un frame. L'oggetto è chiamato visual in Direct3D, dal momento
che rappresenta quello che l'utente vede. Quindi, un visual non ha di
per sé informazioni significative sulla posizione o sull'orientamento,
ma quando viene collegato ad un frame, viene trasformato quando renderizzato
in accordo con le informazioni sulla trasformazione nel frame. Frames multipli
possono essere usati nello stesso visual. Questo può far risparmiare
un sacco di tempo e memoria in una situazione come, per esempio, una foresta
o una piccola flotta di veicoli spaziali, dove abbiamo un gruppo di oggetti
che hanno un aspetto uguale, ma si trovano tutti in posizioni e orientamenti
differenti. Qui c'è uno scadente diagramma ASCII di un singolo visual collegato
a due frames che sono in posizioni differenti: Se tutti e due i frames sono collegati al frame della scena, allora la nostra
scena avrà 2 cubi; uno in (21, 3, 4) e l'altro in (-12, 10, -6).
4.1.4 Materiali Prima o poi ci sarà.
Per prima cosa, ecco uno screenshot del piccolo semplice esempio
dell'applicazione che troverete insieme a questo tutorial.
4.3 Settaggio delle variabili globali Prima di iniziare abbiamo bisogno di qualche variabile globale.
Notare che, per creare una applicazione Direct3D, ci serve sia un oggetto DirectDraw
che un oggetto Direct3D. Questo succede perché Direct3D lavora in congiunzione
con DirectDraw. Come prima, ci serve una superficie primaria e una superficie
back per il nostro double-buffering, e un clipper per l'handle al window-clipping
in modalità windowed. L'oggetto palette non viene (ancora) trattato in
questo tutorial. Abbiamo oggetti per il device e il viewport, e abbiamo oggetti
frame per tenere traccia della scena e della telecamera della scena.
Inoltre, abbiamo un frame che viene usato per l'oggetto che avremo in questa
scena.
Ecco una routine solo per appiattire inizialmente queste globali:
4.4 Da 'Inizializzazione del sistema DirectDraw'
a 'Creazione del clipper' Questo ripercorre tutto il procedimento esatamente come nell'esempio DirectDraw,
con l'eccezione della funzione CreateSurface, dove la superficie back viene
creata con DDSCAPS_3DDEVICE, poiché verrà usata per il rendering
3d:
4.5 Creazione dell'oggetto Direct3D in modalità
Retained Ora abbiamo bisogno di creare un oggetto IDirect3DRM. Questo viene fatto,
molto semplicemente, chiamando la funzione Direct3DRMCreate.
4.6 Creazione del device per il rendering Creiamo l'oggetto devicedalla superficie back, poiché questa superficie
è quella che andremo a renderizzare.
Qui facciamo un po' di più che creare solo un viewport. Creiamo l'oggetto
scena e l'oggetto telecamera, così come settiamo la luce ambientale per
la scena e creiamo una luce direzionale.
4.8 Creazione della vostra scena Ci serve qualche oggetto per la scena. Creiamo un cubo! Wheee! Qui trovate
il file cube.x, zippato. Unzipppatelo nella directory
dalla quale lanciate la vostra applicazione.
SetRotation assegna valori in radianti ad un frame che deve rotare attorno
al proprio asse ogni volta che il frame viene renderizzato usando Tick.
Direct3D esegue questa rotazione automaticamente, ogni volta che viene chiamato
Tick.
Qui c'è una parte finale della funzione InitInstancedell'applicazione:
4.10 Ripristino delle superfici perse Qualcosa di simile all'esempio DirectDraw:
Qualcosa di simile all'esempio DirectDraw:
Qualcosa di simile all'esempio DirectDraw.
4.14 Controllo degli errori Direct3D A breve(?).
A brevissimo(?).
_____
/ /| <- Cube (visual)
/ / |<==========================>[Frame1: (21, 3, 4)]
+----+ |
| | /<===========================>[Frame2: (-12, 10, -6)]
| |/
+----+
LPDIRECTDRAW pDD; // A DirectDraw object
LPDIRECT3DRM pD3DRM; // A Direct3D RM object
LPDIRECTDRAWSURFACE pDDSPrimary; // DirectDraw primary surface
LPDIRECTDRAWSURFACE pDDSBack; // DirectDraw back surface
LPDIRECTDRAWPALETTE pDDPal; // Palette for primary surface
LPDIRECTDRAWCLIPPER pClipper; // Clipper for windowed mode
LPDIRECT3DRMDEVICE pD3DRMDevice; // A device
LPDIRECT3DRMVIEWPORT pViewport; // A viewport
LPDIRECT3DRMFRAME pCamera; // A camera
LPDIRECT3DRMFRAME pScene; // The scene
LPDIRECT3DRMFRAME pCube; // The one and only object in
// our scene
BOOL bFullScreen; // Are we in full-screen mode?
BOOL bAnimating; // Has our animating begun?
HWND ddWnd; // HWND of the DDraw window
void InitDirectXGlobals()
{
pDD = NULL;
pD3DRM = NULL;
pDDSPrimary = NULL;
pDDSBack = NULL;
pDDPal = NULL;
pClipper = NULL;
pD3DRMDevice = NULL;
pViewport = NULL;
pCamera = NULL;
pScene = NULL;
pCube = NULL;
bFullScreen = FALSE;
bAnimating = FALSE;
}
UINT CreatePrimarySurface()
{
.
.
.
// Create an offscreen surface, specifying 3d device
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
.
.
.
}
UINT CreateDirect3DRM()
{
HRESULT hr;
// Create the IDirect3DRM object.
hr = Direct3DRMCreate(&pD3DRM);
if (FAILED(hr)) {
TRACE("Error creating Direct3d RM object\n");
return 1;
}
return 0;
}
UINT CreateDevice()
{
HRESULT hr;
hr = pD3DRM->CreateDeviceFromSurface(
NULL, pDD, pDDSBack, &pD3DRMDevice);
if (FAILED(hr)) {
TRACE("Error %d creating d3drm device\n", int(LOWORD(hr)));
return 1;
}
// success
return 0;
}
UINT CreateViewport()
{
HRESULT hr;
// First create the scene frame
hr = pD3DRM->CreateFrame(NULL, &pScene);
if (FAILED(hr)) {
TRACE("Error creating the scene frame\n");
return 1;
}
// Next, create the camera as a child of the scene
hr = pD3DRM->CreateFrame(pScene, &pCamera);
if (FAILED(hr)) {
TRACE("Error creating the scene frame\n");
return 2;
}
// Set the camera to lie somewhere on the negative z-axis, and
// point towards the origin
pCamera->SetPosition(
pScene, D3DVAL(0.0), D3DVAL(0.0), D3DVAL(-300.0));
pCamera->SetOrientation(
pScene,
D3DVAL(0.0), D3DVAL(0.0), D3DVAL(1.0),
D3DVAL(0.0), D3DVAL(1.0), D3DVAL(0.0));
// create lights
LPDIRECT3DRMLIGHT pLightAmbient = NULL;
LPDIRECT3DRMLIGHT pLightDirectional = NULL;
LPDIRECT3DRMFRAME pLights = NULL;
// Create two lights and a frame to attach them to
// I haven't quite figured out the CreateLight's second
// parameter yet.
pD3DRM->CreateFrame(pScene, &pLights);
pD3DRM->CreateLight(D3DRMLIGHT_AMBIENT, pD3DRMCreateColorRGB(
D3DVALUE(0.3), D3DVALUE(0.3), D3DVALUE(0.3)),
&pLightAmbient);
pD3DRM->CreateLight(D3DRMLIGHT_DIRECTIONAL, D3DRMCreateColorRGB(
D3DVALUE(0.8), D3DVALUE(0.8), D3DVALUE(0.8)),
&pLightDirectional);
// Orient the directional light
pLights->SetOrientation(pScene,
D3DVALUE(30.0), D3DVALUE(-20.0), D3DVALUE(50.0),
D3DVALUE(0.0), D3DVALUE(1.0), D3DVALUE(0.0));
// Add ambient light to the scene, and the directional light
// to the pLights frame
pScene->AddLight(pLightAmbient);
pLights->AddLight(pLightDirectional);
// Create the viewport on the device
hr = pD3DRM->CreateViewport(pD3DRMDevice,
pCamera, 10, 10, 300, 220, &pViewport);
if (FAILED(hr)) {
TRACE("Error creating viewport\n");
return 3;
}
// set the back clipping field
hr = pViewport->SetBack(D3DVAL(5000.0));
// Release the temporary lights created. It seems
// they will have been copied for the scene during AddLight
pLightAmbient->Release();
pLightDirectional->Release();
// success
return 0;
}
// Put stuff into the scene
UINT CreateDefaultScene()
{
HRESULT hr;
// Create the frame for the cube
hr = pD3DRM->CreateFrame(pScene, &pCube);
if (FAILED(hr)) {
TRACE("Error creating frame pCube\n");
return 1;
}
// Load the cube
hr = pCube->Load("CUBE.X", NULL, D3DRMLOAD_FROMFILE, NULL, NULL);
if (FAILED(hr)) {
TRACE("Error [%d] loading cube.x\n", int(LOWORD(hr)));
return 2;
}
// Set cube's position/orientation relative to scene
pCube->SetPosition(pScene,
D3DVALUE(0.0), D3DVALUE(0.0), D3DVALUE(0.0));
pCube->SetRotation(pScene,
D3DVALUE(1.0), D3DVALUE(1.0), D3DVALUE(0.0), D3DVALUE(0.1));
// success
return 0;
}
InitDirectXGlobals();
TRACE("Calling InitDDraw\n");
InitDDraw();
SetMode();
// TRACE("Calling LoadJascPalette\n");
// LoadJascPalette("inspect.pal", 10, 240);
TRACE("Calling CreatePrimarySurface\n");
CreatePrimarySurface();
TRACE("Calling CreateClipper\n");
CreateClipper();
// TRACE("Calling AttachPalette\n");
// AttachPalette(pDDPal);
TRACE("Calling CreateDirect3DRM\n");
CreateDirect3DRM();
TRACE("Calling CreateDevice\n");
CreateDevice();
TRACE("Calling CreateViewport\n");
CreateViewport();
TRACE("Calling CreateDefaultScene\n");
CreateDefaultScene();
bAnimating = TRUE;
return TRUE;
}
BOOL CheckSurfaces()
{
// Check the primary surface
if (pDDSPrimary) {
if (pDDSPrimary->IsLost() == DDERR_SURFACELOST) {
pDDSPrimary->Restore();
return FALSE;
}
}
return TRUE;
}
BOOL CD3dRmAppApp::OnIdle(LONG lCount)
{
CWinApp::OnIdle(lCount);
if (bAnimating) {
HeartBeat();
Sleep(50);
}
return TRUE;
}
BOOL CD3dRmAppApp::HeartBeat()
{
HRESULT hr;
// if (!CheckSurfaces) bForceUpdate = TRUE;
// if (bForceUpdate) pViewport->ForceUpdate(10,10,300,220);
hr = pD3DRM->Tick(D3DVALUE(1.0));
if (FAILED(hr)) {
TRACE("Tick error!\n");
return FALSE;
}
// Call our routine for flipping the surfaces
FlipSurfaces();
// No major errors
return TRUE;
}
Articolo aggiornato il: 19 Giugno 1998
Articolo di David Joffe
http://www.geocities.com/SoHo/Lofts/2018/
---
Traduzione: Papero - IPG 1999
Eng?Ita! Team
http://www.ItaProGaming.com