Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Mit DirectX->DrawPrimitive umrandete Flächen zeichnen (https://www.delphipraxis.net/143358-mit-directx-drawprimitive-umrandete-flaechen-zeichnen.html)

TOC 14. Nov 2009 05:37


Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Hi!

Also, vorab: Ich Verwende immer noch Delphi 3.0 Pro :oops:, mangels eine besseren Version, zusammen mit DelphiX von Hiroyuki Hori :oops:.
Ich habe zwar auch ein Delphi7 Pe, auch mit DelphiX, aber ich verwende es nur sehr ungern zum programmieren. Aber dass nur zur Info, meine Frage bezieht sich mehr auf Microsoft DirectX.

Ich habe folgendes Problem: Ich möchte mit der Function "DrawPrimitive" eine Fläche (bestehend aus mehreren Dreiecken) rendern und mit einer Farbe ausfüllen (also OHNE Texture). Ok, das klappt. Aber ich möchte dass das Dreieck sagen wir mal Innen mit Rot ausgefüllt und außen herum ein blauer Rand gezeichnet wird. Und das ist das Problem, ich weiß echt nit wie. Ich habe schon die halbe MSN-Bib nach einer Lösung abgesucht. Es gibt nämlich ein Problem mit dem Z-Puffer bei dieser Sache. Also, im Moment zeichne ich das Dreieck (bzw. eine komplexere Form aus Dreiecken) mit DrawPrimitive->TriangleList oder ->TriangleStrip, und anschließend zeichne nochmal den Rahmen herum mit DrawPrimitive->LineList oder ->LineStrip. Das ist erstens nicht sehr Effektiv und zweitens führt dies dazu das der Rand um das Objekt herum optisch zerrissen wird, also keine durchgezogene Linie. Und das liegt daran das der (blaue) Pixel vom Rand in Z-Richtung mal vor, mal hinter dem (roten) Pixel der Dreieck-Fläche berechnet wird :gruebel:. Je nachdem wie ich die Form sich dann im 3D-Raum bewegen und rotieren lasse ist der Rahmen mal durchgezogen, mal gestrichelt und mal leider völlig unsichtbar. :?

Meine Frage: Kennt einer von Euch eine Lösung für diese Problem? Vielleicht einen RenderState denn man setzen kann? Oder irgendeinen FillMode, oder was auch immer.

Ich bin für jeden Hinweis zur Lösung dieses Problems echt dankbar.

MfG, TOC!

Medium 14. Nov 2009 15:12

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Zwei Dinge fallen mir ein:

1) Über eine Textur, die eben einen blauen Rand und rotes Inneres hat. Nachteile: Die Texcoords könnten evtl. gräßlich werden, und der Rand wächst mit der Fläche eines Dreiecks - ist also u.U. verschieden Dick in ein und dem selben Patch.
2) Mache den Wireframe-Pass mit einem gaaanz leicht "gewachsenem" Patch. Die Normalenvektoren für jeden Vertex hast du ja wahrscheinlich schon, also dann einfach die Vertices um einen Bruchteil ihres Norm. verrücken. Da es ja wirklich nur um ein "Titsch" geht und es ein Wireframe wird ist, ist das sonst dabei teilweise auftretende Problem der Selbstschneidung kaum vorhanden bzw. von Bedeutung. (Nämlich hochstens dort, wo sich das Objekt selbst berührt.)

TOC 14. Nov 2009 16:46

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Hi!

Vielen Dank für Deine Antwort und Deine Vorschläge.

Zitat:

Zitat von Medium
Zwei Dinge fallen mir ein:
1) Über eine Textur, die eben einen blauen Rand und rotes Inneres hat. Nachteile: Die Texcoords könnten evtl. gräßlich werden, und der Rand wächst mit der Fläche eines Dreiecks - ist also u.U. verschieden Dick in ein und dem selben Patch.

Also, die Idee hatte ich im Prinzip auch schon. Aber, mit ner Texture geht es leider nicht. Die Texture-Koords zu berechnen ist nicht das große Problem. Ich habe eine Funktion die ein Rechteck zeichnet, und in dem Rechteck ist ein kleineres Rechteck mit drehbarem Winkel ausgespart, also durchsichtig. Dazu setze ich das große Rechteck aus 4 Rechtecken und, wennn der innere Drehwinkel ungleich 0 ist, zusätzlich 4 Dreiecken zusammen.In dem aktuellen Programm verwende ich diese Funktion und zeichne 6 Quadrate so räumlich versetzt dass ein Würfel entsteht, ja, und die kleineren durchsichtigen Quadrate drehen sich um ihre Mittelachse, und der ganze Würfel dreht sich noch dazu im Raum. Also ich könnte ja eine Texture erzeugen mit einem beispielsweise blauem Rand und einer roten Füllung, nur, ich muss ja auch das kleine ausgesparte Quadrat im inneren Umranden, und das dreht sich um sich selbt- also geht es nicht mit einer Texture...

Zitat:

Zitat von Medium
2) Mache den Wireframe-Pass mit einem gaaanz leicht "gewachsenem" Patch. Die Normalenvektoren für jeden Vertex hast du ja wahrscheinlich schon, also dann einfach die Vertices um einen Bruchteil ihres Norm. verrücken. Da es ja wirklich nur um ein "Titsch" geht und es ein Wireframe wird ist, ist das sonst dabei teilweise auftretende Problem der Selbstschneidung kaum vorhanden bzw. von Bedeutung. (Nämlich hochstens dort, wo sich das Objekt selbst berührt.)

Ja, habe ich auch schon versucht. Klappt leider ebenfalls nit. Ich habe alle Z-Koordinaten von der Umrandung einfach mal eiskalt um einen Betrag nach vorne geschoben, weil ich hoffte dass sie dann in Z-Richtung über der Grafik zu liegen kommen. Klappt aber nicht, weil: Wenn ich den Z-Unterschied so groß mache, dass die Linien nicht mehr unterbrochen werden, dann sind die Linien dafür aber in der X- und Y-Position versetzt und auch in der Länge vergrößert und decken sich nicht mehr mit der darunterliegenden Grafik... :cry:

Echt blöd. Fällt Dir, oder sonst irgend jemandem da draußen, vielleicht noch etwas anderes zur Lösung dieses Problems ein?
Ich freue mich über jeden weiteren Vorschlag und jede weitere Idee!

Grüße von TOC!

Medium 14. Nov 2009 17:46

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Versetzen auf der Z-Achse ist nicht was ich vorgeschlagen hab ;) Dass das oft nicht ganz zum Ziel führt ist klar. Deswegen ja um die Normalenvektoren verschieben!

Edit: Noch was. Viele machen auch den Fehler, das Near- und Far-Clipping vieeel zu nah bzw. weit zu setzen, wodurch sich der Z-Buffer arg auseinanderzieht. Vor allem ist da wohl das Near-Clipping kritisch, da sich der Z-Buffer logarithmisch von vorn nach hinten verteilt, so dass du je näher ein Objekt ist eine größere Auflösung in Z hast. Das hilft zwar auch nichts wenn du garnicht oder nur um Z verschiebst, aber damit kann man sich mit meiner Methode mit recht kleinem Wachstum begnügen ohne dass einem der Z-Buffer zu schnell einen Strich durch die Rechnung macht.
Im Zweifel kannst du auch einfach mal den Z-Buffer in 32Bit versuchen (können nur nicht alle GraKas, und der Stencil-Buffer ist flöten - wenn du den brauchst).

TOC 14. Nov 2009 18:08

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Hi!

Zitat:

Zitat von Medium
Versetzen auf der Z-Achse ist nicht was ich vorgeschlagen hab ;) Dass das oft nicht ganz zum Ziel führt ist klar. Deswegen ja um die Normalenvektoren verschieben!

Sorry, ich habe Deine Idee wohl noch nicht verstanden. Was meinst Du denn mit "um die Normalenvektoren verschieben". Klar, ok, ich habe in den Vertices den Vector selbst als XYZ und ein dazugehöriges Normal, dass vom Mittelpunkt aus weg in die Richtung der Gesamtfläche zeigt, so dass DX Lichteffekte berechnen kann etc. . Aber wie soll ich den Vector um das Normal verschieben? Irgendwie raffe ich das nicht. Könntest Du es mir vielleicht bitte genauer erklären wie Du das meinst? Vielleicht den Vector aus dem Vertice einfach skalieren, mit einer Scale-Matrix also multiplizieren, also etwas vergrößern, und im inneren Rechteck für die ausgesparrte Umrandung skalieren und etwas verkleinern?

Auf jeden Fall Danke für Deine Antwort, ich raufe mir hier schon die Haare aus :? Wenn ich keine Lösung finde hab ich bald ne Glatze :(, und das obwohl ich Glatzen hasse :mrgreen: !

Grüße von TOC.

TOC 14. Nov 2009 18:26

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Zitat:

Zitat von Medium

Edit: Noch was. Viele machen auch den Fehler, das Near- und Far-Clipping vieeel zu nah bzw. weit zu setzen, wodurch sich der Z-Buffer arg auseinanderzieht.

Also, ich nehme :

Delphi-Quellcode:
...
  D3DUtil_SetProjectionMatrix(Matrix, Pi/4, Aspect, 50, 20000000);
...
Also NearClipping 50 und FarClipping 20000000. Meinst Du das es daran liegen könnte?

Ich könnte das Programm auch Posten dann könntest Du es Dir genauer ansehen was mein Problem ist- obwohl ich dies nit gerade so gerne tun würde, weil es ist nur ein DxTest-Programm und auch noch nit fertig...
Aber wenn es helfen würde dann würde ich es Posten (die .exe).

Grüße von TOC!

TOC 15. Nov 2009 08:53

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Hi Medium!

Vielen Dank für Deine Vorschläge und Hilfe, es hat mich auf einige neue Ideen gebracht.

Zitat:

Zitat von Medium
Edit: Noch was. Viele machen auch den Fehler, das Near- und Far-Clipping vieeel zu nah bzw. weit zu setzen, wodurch sich der Z-Buffer arg auseinanderzieht.

Ok, das wusste ich auch noch nicht. Ich habe in meinem Programm das FarClipping jetzt mal runter gesetzt auf 2000. Irgendwie sieht die Grafik dadurch wesentlich kristalliner aus, irgendwie einfach besser, vielleicht weil es jetzt weniger Z-Rundungsfehler gibt. Super Tip :thumb: !

Wie Du das mit dem verschieben um die Normalen meinst habe ich immer noch nit kapiert, aber, egal, mir ist ein neuer Trick eingefallen. Also, ich berechne mir zuerst die 4 Vektoren von dem Rechteck, dann ziehe ich davon zweidimensional gesehen einen einstellbaren kleinen Betrag ab und berechne nochmal 4 Vektoren für ein etwas kleineres Rechteck bzw. Quadrat. Zum Zeichnen der ausgefüllten Fläche nehme ich dann das kleinere Quadrat, und zeichne nun ZWEI mal den WireFrame herum, einmal mit dem etwas verkleinerten Vektoren und einmal mit den Vektoren in Normalgröße- funzt super! Mit dem ausgesparten Rechteck/Quadrat im Inneren Umrande ich das ganze ebenso. Ok, es ist etwas mehr Rechen- und Zeichenaufwand, weil ich ja den inneren und äußeren Rand nun 2 mal Zeichne, also 4 Ränder, und das pro Quadrat, also mal 6 für meinen Würfel. Trotzdem: Der Aufwand lohnt sich, da die Umrandungen jetzt nahezu aus durchgezogenen Linien bestehen und die Optik 10 mal besser ist.
Und als Nebeneffekt sehen die Umrandungen jetzt auch noch etwas dicker aus als vorher, das erleichtert das erkennen der Grafik enorm!

Grüße von TOC!

Medium 15. Nov 2009 16:55

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Mit um die Normalenvektoren verschieben meine ich quasi einfach "V+k*N", V ist ein Vertex, N sein Normalenvektor, und k ein kleiner konstanter Wert um den das Mesh wachsen soll. Da die Normalen ja immer "von der Oberfläche weg" zeigen, bewirkt ein Verschieben um diese eben ein Wachstum des Volumens. Im Fall eines zentrierten Würfels ist das gleich einer Skalierungsmartix, bei komplexeren Objekten ist das Ergebnis allerdings unterschiedlich, und eine reine Skalierung ist dann nicht mehr wirklich zielführend (da man sich dann auch Teile "in" das vorige Objekt hinein schiebt).
Ein weiterer Vorteil dessen ist, dass die Normalenvektoren nachher auch noch stimmen ohne sie neu zu berechnen. Auch das ist bei einer einfachen Skalierung nicht unbedingt mehr gegeben.

TOC 15. Nov 2009 17:47

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Hi Medium!

Zitat:

Zitat von Medium
Mit um die Normalenvektoren verschieben meine ich quasi einfach "V+k*N", V ist ein Vertex, N sein Normalenvektor, und k ein kleiner konstanter Wert um den das Mesh wachsen soll. Da die Normalen ja immer "von der Oberfläche weg" zeigen, bewirkt ein Verschieben um diese eben ein Wachstum des Volumens.

Oh, super, diesmal habe ich Dich verstanden, vielen Dank :thumb: !

Zitat:

Zitat von Medium
Ein weiterer Vorteil dessen ist, dass die Normalenvektoren nachher auch noch stimmen ohne sie neu zu berechnen. Auch das ist bei einer einfachen Skalierung nicht unbedingt mehr gegeben.

Den Trick werde ich mir auf jeden Fall merken. In meinem konkreten Testprogramm hier wäre dies aber etwas Problematisch- weil bei mir die Normals nicht normalisiert sind. Ich habe kurzerhand DirectX per Renderstate-->NormalizeNormals dazu überedet sie automatisch zu normalisieren... Nicht aus Faulheit, sondern das hat einen praktischen Grund: die Normals haben bei mir, je nach Grafik, unterschiedliche Längen und Farben. Und ich kann in meinem Programm einen Debug-Modus einschalten, der die Normals dann von dem Vector aus wegzeigend einzeichnet. So kann ich also optisch kontrollieren ob ich diese Normals richtig berechnet habe.

Gerade schreibe ich meine Rechteck-Funktion, aus der ich ja meinen Würfel zusammen setzte, nochmal um. Dank Dir bin ich auf diesen Gedanken gekommen: Ich zeichne jetzt nicht mehr einen einfachen WireFrame 2 mal, sondern ziehe einen einstellbaren Betrag von der Länge und Höhe ab, und diese dadurch außen neu entstehenden Rechtecke fülle ich dann wieder mit DrawPrimitive->TriangleList in einer anderen Farbe aus. Mit anderen Worten: Ich mache die Rahmenbreite nun mit einstellbarer Breite. Vielen Dank das Du mich auf diesen Idee gebracht hast :thumb: !

Grüße von TOC!

Medium 15. Nov 2009 18:37

Re: Mit DirectX->DrawPrimitive umrandete Flächen zeichnen
 
Immer gern. 3D Gefummel macht halt auch immer wieder Spaß :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:11 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz