Graphiken für Rot-Grün-Brille

16/10/2007 - 22:56 von Lorenz | Report spam
Ich programmierte einfache 3D-Graphiken (z.B. ein Strichmodell eines
Würfels, wobei wahlweise auch ein dichtes Muster von zusàtzlichen ràumlichen
Linien hinzukommt), so dass sie mit einer Rot-Grün-Brille ràumlich gesehen
werden kann. Da stellt sich nun ein interessantes Farbenproblem. Durch die
Rot-Grün-Brille sieht das linke Auge nur alles Rote und das rechte nur alles
Grüne. Das Programm zeichnet nun eine rote Figur für das linke Auge und eine
grüne für das rechte. Nun können sich auf dem Bildschirm rote und grüne
Linien überschneiden. Im Schnittpunkt ist dann immer nur die zuletzt
gezeichnete Farbe sichtbar. Also wenn dort zuerst z.B. rot gezeichnet wurde,
dann ist die Farbe (ausgedrückt durch die Bestandteile RGB) = (255, 0, 0).
Wenn dann anschliessend Grün darüber kommt, ist die Farbe (0, 255, 0). Was
ich aber haben sollte, ist, dass das vorherige Byte erhalten bleibt, d.h.
zum Rot sollte das Grün hinzukommen, mit der resultierende Farbe (255, 255,
0), sonst geht ja die Information für das eine Auge wegen dem Zeichnen der
Information für das andere Auge verloren. Gibt es nicht einen Modus für die
Zeichenoperation (Graphics.DrawLine), der die Farben additiv im obigen Sinne
behandelt?
 

Lesen sie die antworten

#1 Karsten Sosna
17/10/2007 - 09:16 | Warnen spam
"Lorenz" schrieb im Newsbeitrag
news:
^^^^^^^^^^
Hier sollte der volle Name(Vor- und Zuname) stehen.^

Ich programmierte einfache 3D-Graphiken (z.B. ein Strichmodell eines
Würfels, wobei wahlweise auch ein dichtes Muster von zusàtzlichen
ràumlichen Linien hinzukommt), so dass sie mit einer Rot-Grün-Brille
ràumlich gesehen werden kann. Da stellt sich nun ein interessantes
Farbenproblem. Durch die Rot-Grün-Brille sieht das linke Auge nur alles
Rote und das rechte nur alles Grüne. Das Programm zeichnet nun eine rote
Figur für das linke Auge und eine grüne für das rechte. Nun können sich
auf dem Bildschirm rote und grüne Linien überschneiden. Im Schnittpunkt
ist dann immer nur die zuletzt gezeichnete Farbe sichtbar. Also wenn dort
zuerst z.B. rot gezeichnet wurde, dann ist die Farbe (ausgedrückt durch
die Bestandteile RGB) = (255, 0, 0). Wenn dann anschliessend Grün darüber
kommt, ist die Farbe (0, 255, 0). Was ich aber haben sollte, ist, dass das
vorherige Byte erhalten bleibt, d.h. zum Rot sollte das Grün hinzukommen,
mit der resultierende Farbe (255, 255, 0), sonst geht ja die Information
für das eine Auge wegen dem Zeichnen der Information für das andere Auge
verloren. Gibt es nicht einen Modus für die Zeichenoperation
(Graphics.DrawLine), der die Farben additiv im obigen Sinne behandelt?



Mit GDI+ direkt nicht. Mit GDI32 API's schon. Siehe SetROP2-Methode:
\\\
Private Sub Form1_Paint(ByVal sender As Object, ByVal e As
System.Windows.Forms.PaintEventArgs) Handles Me.Paint
e.Graphics.Clear(Color.Black)

Dim diameter As Int32 = 100
Dim l, t, r, b As Int32
Dim cr As PInvoke.COLORREF
Dim hdc As IntPtr
Dim hPen, hOldPen As IntPtr
Dim hBrush, hOldBrush As IntPtr

hdc = e.Graphics.GetHdc
PInvoke.SetROP2(hdc, PInvoke.R2_FLAGS.MERGEPEN)

cr = New PInvoke.COLORREF(255, 0, 0)
hPen = PInvoke.CreatePen(PInvoke.PenStyles.PS_SOLID, 1, cr)
hOldPen = PInvoke.SelectObject(hdc, hPen)
hBrush = PInvoke.CreateSolidBrush(cr)
hOldBrush = PInvoke.SelectObject(hdc, hBrush)

l = 50
t = 25
r = l + diameter
b = t + diameter
PInvoke.Ellipse(hdc, l, t, r, b)

PInvoke.SelectObject(hdc, hOldPen)
PInvoke.DeleteObject(hPen)
PInvoke.SelectObject(hdc, hOldBrush)
PInvoke.DeleteObject(hBrush)

cr = New PInvoke.COLORREF(0, 255, 0)
hPen = PInvoke.CreatePen(PInvoke.PenStyles.PS_SOLID, 1, cr)
hOldPen = PInvoke.SelectObject(hdc, hPen)
hBrush = PInvoke.CreateSolidBrush(cr)
hOldBrush = PInvoke.SelectObject(hdc, hBrush)

l = 30
t = 75
r = l + diameter
b = t + diameter
PInvoke.Ellipse(hdc, l, t, r, b)

PInvoke.SelectObject(hdc, hOldPen)
PInvoke.DeleteObject(hPen)
PInvoke.SelectObject(hdc, hOldBrush)
PInvoke.DeleteObject(hBrush)

cr = New PInvoke.COLORREF(0, 0, 255)
hPen = PInvoke.CreatePen(PInvoke.PenStyles.PS_SOLID, 1, cr)
hOldPen = PInvoke.SelectObject(hdc, hPen)
hBrush = PInvoke.CreateSolidBrush(cr)
hOldBrush = PInvoke.SelectObject(hdc, hBrush)

l = 70
t = 75
r = l + diameter
b = t + diameter
PInvoke.Ellipse(hdc, l, t, r, b)

PInvoke.SelectObject(hdc, hOldPen)
PInvoke.DeleteObject(hPen)
PInvoke.SelectObject(hdc, hOldBrush)
PInvoke.DeleteObject(hBrush)

e.Graphics.ReleaseHdc(hdc)
End Sub

Public Class PInvoke
Public Declare Function SetROP2 Lib "GDI32" (ByVal hdc As IntPtr, ByVal
fnDrawMode As R2_FLAGS) As R2_FLAGS
Public Declare Function CreatePen Lib "GDI32" (ByVal fnPenStyle As
PenStyles, ByVal nWidth As Int32, ByVal crColor As COLORREF) As IntPtr
Public Declare Function CreateSolidBrush Lib "GDI32" (ByVal crColor As
COLORREF) As IntPtr
Public Declare Function DeleteObject Lib "GDI32" (ByVal hdc As IntPtr)
As Boolean
Public Declare Function SelectObject Lib "GDI32" (ByVal hdc As IntPtr,
ByVal hgdiobj As IntPtr) As IntPtr
Public Declare Function Ellipse Lib "GDI32" (ByVal hdc As IntPtr, ByVal
nLeftRect As Int32, ByVal nTopRect As Int32, ByVal nRightRect As Int32,
ByVal nBottomRect As Int32) As Boolean

Public Enum R2_FLAGS As Int32 'Binary raster operations
BLACK = 1
NOTMERGEPEN = 2
MASKNOTPEN = 3
NOTCOPYPEN = 4
MASKPENNOT = 5
[NOT] = 6
XORPEN = 7
NOTMASKPEN = 8
MASKPEN = 9
NOTXORPEN = 10
NOP = 11
MERGENOTPEN = 12
COPYPEN = 13
MERGEPENNOT = 14
MERGEPEN = 15
WHITE = 16
LAST = 16
End Enum

<StructLayout(LayoutKind.Sequential)> _
Public Structure COLORREF
Public Sub New(ByVal red As Byte, ByVal green As Byte, ByVal blue As
Byte)
Me.R = red
Me.G = green
Me.B = blue
End Sub
Public R As Byte
Public G As Byte
Public B As Byte
Public A As Byte 'Unused
Public Overrides Function ToString() As String
Return String.Format("COLORREF (R={0}; G={1}; B={2})", Me.R,
Me.G, Me.B)
End Function
End Structure
End Class
///
Weitere Funktionen siehe in der MSDN unter Windows GDI.

Mit GDI+ besteht die Möglichkeit über zwei Bitmaps zu gehen. Eine beinhaltet
das bereits gezeichnete und die Zweite das Neue. Dann "verodert" man beide
Bitmaps mit Hilfe von BitmapData-Objekten. Man kann auch die GDI-Funktion
BitBlt nutzen, um die zweite Bitmap auf die Erste "zu blitten". BitBlt
braucht dazu einen Ternary-Raster-Operation-Code, wàre hierwohl MERGEPAINT.
Alles in Allem rein GDI+ wird das eine "langsame" Sache. Ich würde deswegen
auf das obige Beispiel ausweichen, zumal die GDI32-Funktionen meiner
Beobachtung auch noch schneller sind als die GDI+-Methoden.

Noch zur Anmerkung: Ein bspw. roter Kreis auf weißen Hintergrund kann nicht
"verodert" werden. Für Weiß ist nàmlich R%5, G%5, B%5 und wenn man das
mit Rot(R%5, G=0, B=0) verodert ergibt das wieder Weiß. Deswegen auch das
Löschen mit Schwarz(R=0, G=0, B=0) des Hintergrundes in meinem Beispiel.

Ach so eines vergaß ich noch. Im Beispiel werden immer wieder die Pens und
Brushes gelöscht(DeleteObject). Das muss man machen, weil sonst die
Resourcen nicht wieder freigegeben. Das entspricht dann der bspw.
Pen.Dispose-Methode. Solltest Du also nicht vergessen!
Gruß Scotty

Ähnliche fragen