Probleme mit Transparenz bei DirectX und StretchRect



  • Folgende Situation: ich lade für meine Maps die benötigten Tilesets (mit Magenta als Colorkey, d.h. ich habe keine echt transparenten Pixel im Tileset!) und baue die einzelnen statischen Layer der Map direkt zusammen und cache das als große Surfaces anstatt jeden Frame etliche Tiles einzeln zu rendern. Dies funktioniert ganz grob so:

    // === TILESET LOOP === //
     IDirect3DSurface9 *pTilesetSurface = nullptr;
     // Create surface
     HRESULT hResult = Engine::GetInstance()->GraphicsDevice->CreateOffscreenPlainSurface(
          pTileset->GetImage()->GetWidth(),
          pTileset->GetImage()->GetHeight(),
          D3DFMT_A8R8G8B8,
          D3DPOOL_DEFAULT,
          &pTilesetSurface,
          nullptr);
     if(!SUCCEEDED(hResult))
          return FALSE;
    
     // Load tileset
     std::wstring strTilesetSource(
          pTileset->GetImage()->GetSource().begin(),
          pTileset->GetImage()->GetSource().end());
     strTilesetSource = strPathToMap + strTilesetSource;
     hResult = ::D3DXLoadSurfaceFromFile(
          pTilesetSurface,
          nullptr,
          nullptr,
          strTilesetSource.c_str(),
          nullptr,
          D3DX_FILTER_LINEAR,
          D3DCOLOR_ARGB(255, 255, 0, 255),
          nullptr);
     if(!SUCCEEDED(hResult))
          return FALSE;
    
     this->m_vTilesets.push_back(pTilesetSurface);
    
     /* ... */
    
     // === LAYER LOOP === //
     IDirect3DSurface9 *pLayerSurface = nullptr;
     HRESULT hResult = Engine::GetInstance()->GraphicsDevice->CreateOffscreenPlainSurface(
         pLayer->GetWidth() * 16,
         pLayer->GetHeight() * 16,
         D3DFMT_A8R8G8B8,
         D3DPOOL_DEFAULT,
         &pLayerSurface,
         nullptr);
     if(!SUCCEEDED(hResult))
         return FALSE;
     Engine::GetInstance()->GraphicsDevice->ColorFill(
         pLayerSurface,
         nullptr,
         D3DCOLOR_ARGB(0, 0, 0, 0));
     for(int x = 0; x < pLayer->GetWidth(); ++x) {
         for(int y = 0; y < pLayer->GetHeight(); ++y) {
             const Tmx::MapTile tile = pLayer->GetTile(x, y);
             if(tile.tilesetId != -1) {
                 int dwTilesetWidth =
                 this->m_pTmxFile->GetTileset(tile.tilesetId)->GetImage()->GetWidth() / 16;
                 std::div_t tileCoords = std::div(tile.id, dwTilesetWidth);
                 RECT srcRect = { tileCoords.rem * 16, tileCoords.quot * 16,
                     tileCoords.rem * 16 + 16, tileCoords.quot * 16 + 16 };
                 RECT destRect = { x * 16, y * 16, x * 16 + 16, y * 16 + 16 };
                 Engine::GetInstance()->GraphicsDevice->StretchRect(
                     this->m_vTilesets[tile.tilesetId],
                     &srcRect,
                     pLayerSurface,
                     &destRect,
                     D3DTEXF_NONE);
             }
         }
     }
    

    Versuche ich nun die Layer per D3DXSaveSurfaceToFile zum Debuggen zu speichern, dann besitzen sie Alpha-Informationen und lassen sich problemlos übereinanderlegen und liefern das gewünchte Ergebnis. Rendere ich diese nun, funktioniert das aber nicht in meinem Fenster.

    for(auto iter = this->m_vLayers.begin(); iter != this->m_vLayers.end(); ++iter) {
        Engine::GetInstance()->GraphicsDevice->StretchRect(
            *iter,
            nullptr,
            Engine::GetInstance()->Backbuffer,
            nullptr,
            D3DTEXF_NONE);
    }
    

    Es entsteht folgende Ausgabe. Überall wo der obere Layer transparent sein sollte ist dieser leider schwarz. Ich würde gerne wissen, ob jemand eine Idee hat, was das Problem ist. Weiterhin habe ich was von IDirect3DTexture9 und ID3DXSprite gelesen - leider konnte ich das bisher nicht benutzen, auch wenn ich mitbekommen habe, dass Alpha bei Sprites unterstützt wird, da ich nicht herausgefunden habe, wie ich einen Layer mit den Tiles wie oben mit StretchRect zusammensetzen kann, wenn ich Sprites und Textures nehme anstelle von Surfaces.


  • Mod

    das problem ist, dass du denkst dass stretchrect rendert, aber

    Copy the contents of the source rectangle to the destination rectangle

    http://msdn.microsoft.com/en-us/library/windows/desktop/bb174471(v=vs.85).aspx

    entsprechend musst du dir einen anderen weg suchen.

    btw. schoene pixel art.



  • Danke für den Hinweis - durch Trial and Error habe ich nun eine Möglichkeit gefunden mit dem Problem umzugehen. Meine Tilesets lade ich weiterhin als Surfaces und nutze auch StretchRect um die Layer zu generieren, da ja die Alpha-Werte übernommen werden. In meiner Schleife zum Erstellen der Layer generiere ich ein IDirect3DTexture9 Objekt pro Layer. Per GetSurfaceLevel habe ich Zugriff auf das Surface welche zu der Texture gehört und kann es gewohnt mit StretchRect befüllen. Beim Rendern nutze ich jedoch ID3DXSprite welches sich automatisch um die Alpha-Werte kümmert und nun funktioniert alles und ich erhalte ein richtiges Ergebnis!


  • Mod

    klingt nach einer loesung 🙂
    vielleicht gleich D3DXLoadTextureFromFile nutzen?

    ich haette bei der "Art" wohl einfach alles per cpu gemacht und das fertige bild rausgezeichnet, koennte mir vorstellen dass das sogar schneller ist 🙂


Anmelden zum Antworten