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 Text 😉 Rufe 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


  • Mod

    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


  • Mod

    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...


  • Mod

    ...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?


  • Mod

    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.


Anmelden zum Antworten