[SharpDX] [Direct3D9] Texture auf einer bestimmten Größe skalieren

  • C#
  • .NET (FX) 4.5–4.8

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von ClonkAndre.

    [SharpDX] [Direct3D9] Texture auf einer bestimmten Größe skalieren

    Hallo liebe Community!

    Wie ist es möglich, mittels SharpDX.Direct3D9 eine Textur zu zeichnen, diese auf die angegebene Größe skaliert wurde?
    Beispiel: Ich habe ein 128x128 großes Bild welches ich aber nur in 64x64 Größe auf den Bildschirm zeichen möchte. Oder umgekehrt, wenn ich ein 128x128 großes Bild in der Größe 256x256 auf den Bildschirm zeichnen möchte.

    Hier ist der momentane Code welcher auch funktioniert, nur die skalierung auf die angegebene Größe funktioniert nicht.

    C#-Quellcode

    1. public static bool DrawTexture(IntPtr device, IntPtr txt, RectangleF rect, float rotation, Color tint)
    2. {
    3. try {
    4. Texture texture = (Texture)txt;
    5. Matrix m = Matrix.Identity * Matrix.Translation(-0.5f, -0.5f, 0.0f) * Matrix.Scaling(rect.Width, rect.Height, 1.0f) * Matrix.RotationZ(rotation) * Matrix.Translation(rect.X, rect.Y, 0.0f);
    6. using (Sprite s = new Sprite((Device)device)) {
    7. s.Begin();
    8. s.Transform = m;
    9. s.Draw(texture, tint.ToRawColorBGRA());
    10. s.End();
    11. }
    12. return true;
    13. }
    14. catch (Exception ex) {
    15. Main.managerInstance.console.PrintError(string.Format("[Direct3D9] An error occured while trying to draw texture. Details: {0}", ex.ToString()));
    16. }
    17. return false;
    18. }


    Und so lade ich Texturen

    C#-Quellcode

    1. // D3DX.DefaultNonPowerOf2 = -2
    2. Texture t = Texture.FromFile(device, filePath, D3DX.DefaultNonPowerOf2, D3DX.DefaultNonPowerOf2, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.None, Filter.None, 0);


    Falls ihr weitere Informationen benötigt bitte nicht zögern mir dies mitzuteilen
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Hi benutze doch einfach
    github.com/sharpdx/SharpDX/blo…Direct3D9/Texture.cs#L373

    Also im Sinne:

    C#-Quellcode

    1. Bitmap src = new Bitmap(filename);
    2. Bitmap dst = new Bitmap(64, 64);
    3. Graphics g = Graphics.FromImage(dst);
    4. g.DrawImage(src, 0, 0, 64, 64);
    5. MemoryStream ms = new MemoryStream();
    6. dst.Save(ms, ImageFormat.Png);
    7. var d3d9Tex = Texture.FromMemory(device, ms.ToArray());
    Und Gott alleine weiß alles am allerbesten und besser.
    Das wäre eine Möglichkeit aber ich muss sagen die kommt mir ziemlich ineffizient rüber.
    Mir wäre es lieber das Bild mittels der Matrix zu skalieren wenn es irgendwie möglich ist.
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    ClonkAndre schrieb:

    nur die skalierung auf die angegebene Größe funktioniert nicht

    Was genau funktioniert nicht? Skaliert er nicht? Oder zu viel? Ist Matrix.Scaling nicht ein Faktor, also Matrix.Scaling(2f, 2f, 1f) mach es doppelt so groß? Du skalierst vermutlich viel zu viel.
    Fast-Vollzitat des direkten Vorposts an dieser Stelle entfernt ~VaporiZed

    Jop Du hast recht. Matrix.Scaling(2f, 2f, 1f) macht es doppelt so groß, und ich skaliere viel zu viel. Wie könnte ich das denn hinbekommen, das wenn ich die Textur auf Bildschirmgröße skalieren möchte, einfach bei der Matrix.Scaling Funktion meine Auflösung eingeben kann und das Bild ist dann dementsprechend groß? Also keine Skalierung von 0 bis 1 sondern von 0 bis meine Auflösung?
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „VaporiZed“ ()

    Warum renderst du nur eine Textur? Du kannst das viel einfacher haben. Erstelle im 3D-Editor ein Mesh, füge die Materialien hinzu, backe die Textur, exportiere das Model als Wavefront(.obj + .mtl). Das macht dir dann auch Kollisionserkennung sehr einfach.

    In DirectX9 ist glaub ich noch alles drin was man zum laden dafür braucht.(Aber auch für danach gibt es das DXTK)

    Hast du etwa vor ein 2D Overlay zu machen? Dann bau auch Direct2D ein, also D2D und D3D kombinieren, mit D2D kannst du passgenau die Texture auf den Bildschirm bekommen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    ClonkAndre schrieb:

    Das wäre eine Möglichkeit aber ich muss sagen die kommt mir ziemlich ineffizient rüber.


    Eine Textur von der Disk zu laden ist an sich ineffizient. Das machst du ja hoffentlich nicht jeden Frame. Und ein Graphics-Objekt aus einem Bitmap zu generieren und dann ein anderes Bild drauf zu zeichnen funktioniert recht schnell. Das als Png in ein MemoryStream zu speichern geht auch schnell, der Bottleneck ist eher Texture.FromMemory... aber wie gesagt, Bottleneck ist ja gerade sowieso das Lesen aus der Disk. Du hast also vielleicht 20 Millisekunden eingespart wenn du das anders machen willst... und das nur für das Initialisieren.
    Und Gott alleine weiß alles am allerbesten und besser.

    DTF schrieb:

    Hast du etwa vor ein 2D Overlay zu machen? Dann bau auch Direct2D ein, also D2D und D3D kombinieren, mit D2D kannst du passgenau die Texture auf den Bildschirm bekommen.

    Ich bin leider gezwungen DirectX 9 zu benutzen und Direct2D ist laut Recherche nur für DirectX 11 verfügbar :woozy_face:
    Ein 2D Overlay kann man das nicht nennen (denke ich), aber es kommt dem nahe. Ich möchte dem User anbieten sein eigenes Zeug auf dem Bildschirm zeichnen. Das ganze ist übrigens für meine GTA IV Mod und wird mit einem EndScene Hook verwirklicht.


    φConst schrieb:

    Eine Textur von der Disk zu laden ist an sich ineffizient. Das machst du ja hoffentlich nicht jeden Frame.

    Das mache ich zum Glück nicht jeden Frame^^ Aber ich würde halt gerne im Rendercode schon die Größe des Bildes bestimmen können.
    Mein Vorhaben war folgendes: Ich wollte ein Bild zeichnen, welches originell auf der Größe des Bildschirmes skaliert wurde, und dann langsam rauszoomt also kleiner skaliert wird. Und ich bin mir da nicht so sicher ob das so performant wäre jeden Frame die Bitmap neu zu skalieren. Aber ja, Du hast volkommen recht, das generieren eines Graphics-Objekt aus einer Bitmap um darauf ein anderes Bild zeichnen zu können geht wirklich schnell! Ich habe das mal getestet. (Fände ich halt nur wieder schöner wenn es direkt über der Matrix.Scaling Funktion möglich wäre :) )
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Ahso, das soll ein Effekt sein. Tja, wenn du schon rauszoomen willst, wäre es eventuell einfach am klügsten ein Quad zu generieren (ist im Endeffekt dasselbe wie ein Sprite) und das als dreidimensionales Objekt zu benutzen. Das Zoomen könntest du dann über die Z-Koordinate erledigen'.
    Und Gott alleine weiß alles am allerbesten und besser.
    Ich schätze ich habe etwas Fortschritt gemacht:


    Ich teile die angegeben Breite und Höhe des Bildes (in dem Fall 128x128) durch die Breite und Höhe der momentanen Bildschirmauflösung (1920x1080).

    C#-Quellcode

    1. Size res = CGame.Resolution;
    2. float cW = rect.Width / res.Width;
    3. float cH = rect.Height / res.Height;
    4. Matrix m = Matrix.Identity * Matrix.Translation(-0.5f, -0.5f, 0.0f) * Matrix.Scaling(cW, cH, 1.0f) * Matrix.RotationZ(rotation) * Matrix.Translation(rect.X, rect.Y, 0.0f);


    Es funktioniert solala... Wie man im obigen Bild vielleicht erkennen kann, befindet sich dort ein rotes Viereck welches 128x128 groß ist. Und wie man auch erkennen kann, ist das Bild nicht gerade gleich groß wie das rote Viereck...
    Was könnte ich jetzt noch ändern damit das Bild exakt 128x128 pixel groß ist damit es mit dem roten Viereck übereinstimmt?
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!
    Solved.

    Um die Pixel in screen units zu convertieren für die Matrix.Scaling Funktion, muss man die gewollte Größe durch die Breite und Höhe des Bildes teilen. Und nicht durch die Breite und Höhe der aktuellen Bildschirmauflösung.
    Das mache ich wie folgt:

    C#-Quellcode

    1. SurfaceDescription sd = texture.GetLevelDescription(0);
    2. float cW = rect.Width / sd.Width;
    3. float cH = rect.Height / sd.Height;


    Und wie man sehen kann, sieht man dass das Bild im roten Viereck ist, welches 128 in der Breite ist, und 128 in der Höhe.


    Ich kann endlich meine Mod fertigstellen :thumbsup:
    Wenn ich dir auf irgendeiner Art und Weise helfen konnte, drück doch bitte den "Hilfreich" Button :thumbup:

    Für VB.NET Entwickler: Option Strict On nicht vergessen!

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ClonkAndre“ ()