Eigenartiges Problem mit Schrift und Pixelshader...
-
Hallo zusammen
Ich habe hier gerade ein ziemlich eigenartiges Phänomen, dass ich beim besten Willen nicht nachvollziehen kann. Ich habe folgenden Pixelshader auf das absolute Minimum reduziert, so dass das Phänomen gerade noch auftritt. Rufe ich eine der 4 im Beispiel auskommentierten Codezeilen auf, bekomme ich wunderschönen geglätteten TextRufe ich allerdings die letzte Zeile auf, so bekomme ich eine praktisch nicht mehr lesbare Schrift voller Artefakte...
Die 4 Farblayer sind aaabsoluut identisch, habe ich mit Photoshop überprüft. Kann das jemand von euch nachvollziehen?// ******************************************* function "main" ******************************************* float4 main(float2 Dif:TEXCOORD0,float4 Clr:COLOR0):COLOR0{ //return float4(1.0f,1.0f,1.0f,tex2D(smp,Dif).a); // sieht toll aus //return float4(1.0f,1.0f,1.0f,tex2D(smp,Dif).r); // sieht toll aus //return float4(1.0f,1.0f,1.0f,tex2D(smp,Dif).g); // sieht toll aus //return float4(1.0f,1.0f,1.0f,tex2D(smp,Dif).b); // sieht toll aus return tex2D(smp,Dif); // sieht aus wie Scheisse... :-( } // *******************************************************************************************************
Gruss Samuel
-
ein bild sagt mehr als...
-
Kann mir mal einer erklären, wieso eine der 4 auskommentierten Zeilen eine Schrift rendern sollte? Der Code sollte doch nur weiß ausgeben?!
-
Gute Schrift (Eine der 4 auskommentierte Zeilen): http://picfront.de/d/7A7h
Schlechte Schrift (unterste Zeile): http://picfront.de/d/7A7g
-
welchen blendmode hast du?
@this->that
er gibt ja noch als alpha den inhalt der textur an, somit blended er weiss anhand der schrifttextur.
-
Das passiert, wenn die Schrift in der Fonttextur sowohl in den Farbkanälen als auch im Alphakanal mit Antialiasing gerendert wurde. Die beiden werden beim Rendern miteinander multipliziert, dadurch dunkler als durch das Antialiasing vorgesehen. Dieses falsche, mehrfache Blending führt zu dünnen und ausgefransten Linien.
Lösung: alle Pixel (oder nur die, die im Alphakanal > 0 sind) in den Farbkanälen der Textur weiß färben. Dann passt das Antialiasing wieder. Das entspricht dann der auskommentierte Zeile, wo du nur das Alpha aus der Textur verwendet hast.
Edit: klarer formuliert.
-
@Nukularfüsiker
Du bist ein Genie, es funktioniert hervorragend. Weisst du vielleicht auch noch gerade, ob es möglich ist, mit der WinAPI direkt in den AlphaKanal eines Surfaces zu rendern. Im moment mache ich es folgendermassen, entsprechend deinem Tipp// try to create a texture and to obtain a device context of its primary surface hRst = pDev->CreateTexture(sWdt,sHgt,1,0,D3DFMT_A8R8G8B8,D3DPOOL_MANAGED,&this->txFnt,0x00); if(hRst != D3D_OK) throw LowLevelException(FNC,"IDirect3DDevice9::CreateTexture",hRst); hRst = this->txFnt->GetSurfaceLevel(0,&sfFnt); if(hRst != D3D_OK) throw LowLevelException(FNC,"IDirect3DTexture9::GetSurfaceLevel",hRst); hRst = sfFnt->GetDC(&hDc); if(hRst != D3D_OK) throw LowLevelException(FNC,"IDirect3DSurface9::GetDC",hRst); // setup the obtained device context SelectObject(hDc,hFnt); SelectObject(hDc,GetStockObject(NULL_BRUSH)); SetBkMode(hDc,TRANSPARENT); SetTextColor(hDc,RGB(255,255,255)); // declare and init two dimensional coordinates // and the width of a character uint32 x = 4, y = 4, w; // start a loop for iterating over each character for(uint32 i=0;i<224;++i){ // add the width of the current character to the current row w = this->aWdt[i]; // reset x and adjust y if there isn't enought space to place // the current character into the current row if(x+w+2 > sWdt) x = 4, y += this->uHgt+4; // finally render the current character and adjust the current row width TextOut(hDc,x,y,&aChr[i],1); // calculate the aspect ratio of the current character this->aAsr[i] = static_cast<float32>(w)/this->uHgt; // compute the texture coordinates for the current character this->vcRct[i].X = static_cast<float32>(x)/sWdt; this->vcRct[i].Y = static_cast<float32>(y)/sHgt; this->vcRct[i].Z = static_cast<float32>(x+w)/sWdt; this->vcRct[i].W = static_cast<float32>(y+this->uHgt)/sHgt; // finally increase x as required x += w+4; } // release the device context and delete the font sfFnt->ReleaseDC(hDc); DeleteObject(hFnt); // try to lock the surface in which we just rendered the alphabet. The WinAPI rendered the character // pixels into the three color channels, but we actually need it in the alpha channel LockedRect rcFnt; hRst = sfFnt->LockRect(&rcFnt,0x00,0); if(hRst != D3D_OK) throw LowLevelException(FNC,"IDirect3DSurface9::Lock",hRst); // start a loop for iterating over each row for(uint32 i=0;i<sHgt;++i){ // convert the generic pointer into a 8-bit pointer in order to gain access to each channel uint8 *pFnt = reinterpret_cast<uint8*>(rcFnt.pBits)+rcFnt.Pitch*i; // start a loop for iterating over each pixel within the current row for(uint32 k=0,c=4*sWdt;k<c;k+=4){ // setup the alpha channel with the red channel pFnt[k+3] = pFnt[k]; // overwrite each color channel with white // (the resulting image will be plain white) pFnt[k] = 0xff; pFnt[k+1] = 0xff; pFnt[k+2] = 0xff; } } // finally unlock the and release the texture surface and we're done sfFnt->UnlockRect(); sfFnt->Release();
Es wäre natürlich schöner, direkt in den Alphakanal rendern zu können...
-
...oder einfach mit dem color blenden und nicht alpha. deswegen fragte ich.
-
@rapso
In meiner Engine behandle ich eben Schriftzeichen genau gleich wie gewöhnliche Bilder, sprich ein Textcharacter ist einfach ein Sprite. Und diese Sprites muss ich IMHO mit dem Alpha blenden?
-
scheinbar eben nicht
//return float4(1.0f,1.0f,1.0f,tex2D(smp,Dif).a); // sieht toll aus
entsprechend kann man dabei mit dem color blenden.