Zobrazit předchozí téma :: Zobrazit následující téma |
Autor |
Zpráva |
Al
Založen: 23. 10. 2007 Příspěvky: 196
|
Zaslal: 9. březen 2012, 19:27:04 Předmět: Jak správně zobrazit 2D bitmapu pomocí 3D rozhraní? |
|
|
Před lety jsem dělal emulátor Sam Coupé/ZX Spectrum. Je to už asi 15 let stará záležitost a dodnes jsem nevydal žádnou verzi pro Windows, protože když jsem ěnkdy před 10 lety dělal konverzi do Visual Studia, celé se to nějak rozsypalo a nechtělo to chodit korektně. Teď jsem "slavnostně" po 9 letech hledání opravil jednu klíčovou chybu v jádru emulátoru a jede mi to už stabilně. A řeším teď kreslení. Jak to kreslit?
Emulátor "vyrábí" bitmapovou obrazovku v rozlišení 640x240, kterou potřebuju roztáhnout do AR 4:3 na obrazovku. (Umím to vygenerovat v 8, 16 i 32bitové hloubce.) Vytvořil jsem k tomu dva "drivery" - jeden používá DirectDraw 6 a pěkně kreslí, jenže na Windows Vista/7 to blokuje Aero, čili při zpanutí mého progrmau Windows přestane kreslit průhledná okna. To považuju za nevyhovující.
Druhý "driver" mám v Direct3D 9. Udělám tam dva trojúhelníky a jednu texturu a obraz z prgoramu dávám do té textury a kreslím. Má to zásadní mouchu, která se mi nedaří opravit: Nepasuje mi to úplně přesně pixel na pixel. Moje otázka je tedy jasná: Kde je ta zatracená chyba a jak ho přimět, aby mi přenášel 2D bitmapu pomocí Direct3D nebo OpenGL úplně přesně pixel na pixel. (Ano, jsem z toho na prášky a klidně bych tam dal OpenGL, kdyby fungovalo.) Předpokládám, že pro lidi, co dělají dnes a denně v Direct3D, to bude věc na minutku, takže přikládám i zdroják. (Já jsem naposledy něco reálně dělal v Direct3D před 7 lety, kdy jsem sestavil tento kód, který nefunguje, a pak před tím v roce 2001, kdy jsem ještě dělal v Illusion Softworks, ale to už jsem dávno zapomněl.)
1. krok - vytvořím device:
kód: |
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.BackBufferWidth=640; //0=vezmi velikost client area okna
d3dpp.BackBufferHeight=240; //0=vezmi velikost client area okna
d3dpp.BackBufferFormat=D3DFMT_UNKNOWN; //unknown=kompatibilni s desktopem
d3dpp.Windowed=TRUE;
d3dpp.SwapEffect=D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow=hwnd;
d3dpp.PresentationInterval=D3DPRESENT_INTERVAL_IMMEDIATE;
if(FAILED(g_pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev))) return E_FAIL; |
2. krok - vytvořím vertex buffer:
kód: |
const int w = 640;
const int h = 240;
vertices[0].pos = D3DXVECTOR3(0,0,0); // top left
vertices[1].pos = D3DXVECTOR3(0,h,0); // bottom left
vertices[2].pos = D3DXVECTOR3(w,0,0); // top right
vertices[3].pos = D3DXVECTOR3(w,h,0); // bottom right
const float maxx = 639.0f/640;
const float maxy = 239.0f/240;
vertices[0].tu = 0.0f; vertices[0].tv = 0.0f; // low left
vertices[1].tu = 0.0f; vertices[1].tv = maxy; // high left
vertices[2].tu = maxx; vertices[2].tv = 0.0f; // low right
vertices[3].tu = maxx; vertices[3].tv = maxy; // high right
for(int i=0;i<4;i++) vertices[i].rhw=1;
if(FAILED(d3ddev->CreateVertexBuffer(sizeof(vertices), D3DUSAGE_WRITEONLY, D3DFVF_CUSTOMVERTEX, D3DPOOL_DEFAULT, &g_pVB, 0))) return E_FAIL;
void *pVertices;
if(FAILED(g_pVB->Lock(0,0,&pVertices,0))) return E_FAIL;
memcpy(pVertices,vertices,sizeof(vertices));
g_pVB->Unlock(); |
3. krok - nastavím ještě nějaké flagy a vytvořím texturu:
kód: |
tryx(d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE));
tryx(d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE));
tryx(d3ddev->CreateTexture(640, 240, 1, D3DUSAGE_DYNAMIC, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &tex, 0));
tex->GetSurfaceLevel(0,&texsurf); |
No a pak se to kreslí 50x za sekundu takhle:
kód: |
if(SUCCEEDED(tex->LockRect(0,&locked,0,D3DLOCK_DISCARD|D3DLOCK_NOSYSLOCK))) {
BYTE *wpos = (BYTE*)locked.pBits;
for(int y=0; y<240; y++,wpos+=locked.Pitch) memcpy(wpos, osvideo.linebuf[y], 640*4);
try(tex->UnlockRect(0));
}
if(SUCCEEDED(d3ddev->BeginScene())) {
try(d3ddev->SetTexture(0,tex));
d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
d3ddev->SetStreamSource(0, g_pVB, 0, sizeof(CUSTOMVERTEX));
d3ddev->SetFVF(D3DFVF_CUSTOMVERTEX);
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2); //nakresli obdelnik
d3ddev->EndScene();
}
d3ddev->Present(0,0,0,0); |
|
|
Návrat nahoru |
|
 |
igor

Založen: 28. 07. 2007 Příspěvky: 196
|
|
Návrat nahoru |
|
 |
Al
Založen: 23. 10. 2007 Příspěvky: 196
|
Zaslal: 9. březen 2012, 21:47:35 Předmět: |
|
|
Jo, pomohlo mi to. Tady to odečtení 0.5f od každé souřadnice, jak píšou na tom webu Microsoftu, mi tam chybělo. A ještě dvě další drobnosti. Souřadnice textury musejí být přesně [0-1]. A až jsem to opravil, ukázalo se, že byla taky nepřesně nastavená velikost okna.
Mám to v DX 9, souvislost s DX10 a 11 jsem nepochopil. V DX 8 jsem to nezkoušel dělat, mám dojem, že tam nějak vůbec není ta podpora custom vertexů. |
|
Návrat nahoru |
|
 |
igor

Založen: 28. 07. 2007 Příspěvky: 196
|
|
Návrat nahoru |
|
 |
VladR
Založen: 30. 07. 2007 Příspěvky: 1322 Bydliště: Greater New York City Area
|
Zaslal: 9. březen 2012, 22:29:12 Předmět: |
|
|
Al napsal: |
Mám to v DX 9, souvislost s DX10 a 11 jsem nepochopil. V DX 8 jsem to nezkoušel dělat, mám dojem, že tam nějak vůbec není ta podpora custom vertexů. |
To mas velmi zly dojem.
Pod DX8.1 som sa Custom Vertexov nadeklaroval stovky, takze rozhodne tam podpora je - dokonca je na vyssej urovni ako v XNA, kde v zaujme zjednodusenia API uz nie su mozne kombinacie, ktore predtym hardwaru hodne pomohli (vykonovo).
Half-Texel Offset pod OpenGL , aspon v dobe, ked som pod OpenGL robil, nebol. Velmi jasne si spominam, ako som pred 10+ rokmi konvertoval aplikaciu do DX a cumel na to prvy raz jak puk. Ked som kodil lightmapper z Radiosity, tak mi ten half-texel narobil hodne vela problemov, lebo ta hrana, aj ked mala len pol texelu totalne rozbila scenu...
Ci to nezaviedli pod poslednymi verziami OGL, vskutku netusim - to nech sa zveri niekto znaly posledneho OGL. |
|
Návrat nahoru |
|
 |
nou

Založen: 28. 07. 2007 Příspěvky: 1050
|
Zaslal: 9. březen 2012, 23:03:17 Předmět: |
|
|
stred pixelu textury je na surdaniciach 0.5/L+N/L L-rozmer textury N-cele cisla
a taktiez stred pixela obrazovky je taktiez na tych istych suradniciach ak pouzijeme ortho projekciu. teda vykreslenie obdlznika od [0,0] po [1,1] nam namapuje 1:1 texturu na obrazovku ak ma ta textura rovnake rozlisenia ako framebuffer. v konecnom dosledku sa tieto polkove offsety vyrusia. _________________ Najjednoduchšie chyby sa najtažšie hľadajú. |
|
Návrat nahoru |
|
 |
Al
Založen: 23. 10. 2007 Příspěvky: 196
|
Zaslal: 10. březen 2012, 18:07:36 Předmět: |
|
|
To, co psal nou, jsem nepochopil. (Je to takovej typickej příklad textu, kterýmu porozumí jen ten, co tomu už rozumí, ale ne ten, co se na to tady ptá. )
Teď mi to teda už kreslí přesně pixel-to-pixel 1:1. Krása. Akorát bych chtěl ještě bilineární mapování, když cílové okno je větší než zdrojová bitmapa. A to mi nefunguje, při zvětšení na FULL HD monitor se pixely opakují, nikde nevidím žádné zprůměrované body. Co musím kde ještě nastavit, aby mi to při zvětšování dělalo bilineárně? (O případu zmenšování ani nemluvě, tam by se taky nějaké průměrování hodilo, ale to asi nebude tak snadné.)
Mám tam tohle a myslel jsem, že to k bilineárnímu mapování textury bude stačit:
kód: |
d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
d3ddev->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR); |
Mám kartu 7600GT, tak by to snad měla umět. Původně mi to právě rozmazávalo úplně, proto jsem tady pokládal ten původní dotaz. A teď to zas nerozmazává vůbec, takže nechápu. |
|
Návrat nahoru |
|
 |
Crypton

Založen: 14. 05. 2009 Příspěvky: 306 Bydliště: The Void
|
|
Návrat nahoru |
|
 |
Al
Založen: 23. 10. 2007 Příspěvky: 196
|
Zaslal: 10. březen 2012, 22:30:07 Předmět: |
|
|
Podle té dokumentace se D3DSAMP_ADDRESSU a D3DSAMP_ADDRESSV vůbec netýká bilineárního mapování, ale opakování textury. Já samozřejmě opakování nepotřebuju. Potřebuju aby mi mezi bílým a černým pixelem byl dopočítán šedý. Zatím se mi dopočítává mezilehlý bod mezi černým a bílým ta, že je buď černý, nebo bílý, co je zrovna blíž, ale nikdy není šedý. |
|
Návrat nahoru |
|
 |
|