![]() |
OpenGL - Prüfen ob Textur angeklickt
Hi,
ich will genau das herausfinden, wie der Name schon sagt: Ob eine Textur angeklickt wurde, und zwar nur die Textur, die mit Alphatest rausgelesen wurde. Wie bewerkstelle ich das? Mfg, Destroxi |
AW: OpenGL - Prüfen ob Textur angeklickt
|
AW: OpenGL - Prüfen ob Textur angeklickt
Der OpenGL Selection Mode ist furchtbar langsam. Ich würde davon abraten, ihn zu verwenden, ausser für das Prototyping, aber niemals für eine echte Applikation.
Besser ist es, mit Z-Sortierung, eigener Objekthiarchie und Raycasting zu arbeiten, auch wenn man damit nicht "so schnell" zu Ergebnissen kommt wie mit dem Selection Mode. Einfach mal nach "OpenGL Picking Raycast" oder ähnlichem googlen, gibt sehr viele gute Ansätze dafür. Oder du schaust dir von GLScene mal die "RayCastIntersect"-Funktionen an, sie sind zwar nicht optimal, dennoch ein guter Ansatzpunkt und schon mal 100-1000x schneller als der OpenGL Selection Mode. P.S. Für OpenGL-Fragen bist du denke ich in einem direkten OpenGL-Forum oder beim GameDEV besser aufgehoben als hier. Generell würde ich dir aber immer noch empfehlen, lade dir mal ![]() |
AW: OpenGL - Prüfen ob Textur angeklickt
Danke für die Tipps, werde mich für zukünftige fragen in einem OpenGL Forum umsehn ;)
... aber erstma nach
Code:
googeln :D
OpenGL Picking Raycast
€dit: Ehrlich gesagt... ich versteh das total nicht :o Wie, was, muss ich tun? Ich will - einfach - nur prüfen ob meine Textur angeklickt wurde... Geht das nicht irgendwie einfacher? Bei TImage geht es so einfach xD Gibts nicht vielleicht einfach so eine "OnClick" Methode für GL Objekte? *hoff* Mfg... |
AW: OpenGL - Prüfen ob Textur angeklickt
Was blackfin gesagt hat, stimmt größtenteils aber in deinem Fall reicht es vollkommen aus und ist anfängerfreundlich. Kucks dir an.
Eine weitere Alternative, die mir gerade einfällt, ist "Color Picking" |
AW: OpenGL - Prüfen ob Textur angeklickt
Color Picking hab ich auch schon gesehn...
Und: was du mit "Anfängerfreundlich" meinst kommt bei jedem anders an :x Ich stell ma ganz konkret die Frage zu meinem Quelltext: Wie schaffe ich es das ich rauskriege ob das Flugzeug angeklickt ist (PlaneTex):
Delphi-Quellcode:
unit Unit1;
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, dglOpenGL, glText, Textures, StdCtrls, ExtCtrls; type TMainForm = class(TForm) Timer1: TTimer; Timer2: TTimer; procedure FormCreate(Sender: TObject); procedure FormResize(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Timer1Timer(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure Timer2Timer(Sender: TObject); procedure FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Timer3Timer(Sender: TObject); private { Private declarations } procedure Render(Sender: TObject; var Done: Boolean); function Selection : integer; public { Public declarations } DC: HDC; RC: HGLRC; myPalette: HPALETTE; end; TRecBorder = Record RLeft, RRight, RBot, RTop: Integer; end; procedure ErrorMsg (Msg: String; MsgTitle: String = 'Error!'); const RecBorder: TRecBorder = (RLeft: 10; RRight: 0; RBot : 10; RTop : 10); SizeX = 640; SizeY = 480; ObjWidth = 100; ObjHeight = 100; dir_LEFT = 0; dir_RIGHT = 1; dir_Max = 1; ManWidth = 100; ManHeight = 100; var MainForm: TMainForm; PlaneTex, ManTex: glUInt; SelPlane: Record pX, pY: Single; Direction: 0..1; end; Player: Record pX, pY: Single; end; Options: Record Speed: Integer; CanClick: Boolean; clicksHitted, clicksMissed, clicksTotal: Integer; end; xs, ys: Integer; implementation {$R *.dfm} procedure SetupPixelFormat; var hHeap: THandle; nColors, i: Integer; lpPalette : PLogPalette; byRedMask, byGreenMask, byBlueMask: Byte; nPixelFormat: Integer; pfd: TPixelFormatDescriptor; begin FillChar(pfd, SizeOf(pfd), 0); with pfd do begin nSize := sizeof(pfd); // Länge der pfd-Struktur nVersion := 1; // Version dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER; // Flags iPixelType:= PFD_TYPE_RGBA; // RGBA Pixel Type cColorBits:= 24; // 24-bit color cDepthBits:= 32; // 32-bit depth buffer iLayerType:= PFD_MAIN_PLANE; // Layer Type end; nPixelFormat:= ChoosePixelFormat(MainForm.DC, @pfd); SetPixelFormat(MainForm.DC, nPixelFormat, @pfd); // Farbpalettenoptimierung wenn erforderlich DescribePixelFormat(MainForm.DC, nPixelFormat, sizeof(TPixelFormatDescriptor),pfd); if ((pfd.dwFlags and PFD_NEED_PALETTE) <> 0) then begin nColors := 1 shl pfd.cColorBits; hHeap := GetProcessHeap; lpPalette:= HeapAlloc (hHeap,0,sizeof(TLogPalette)+(nColors*sizeof(TPaletteEntry))); lpPalette^.palVersion := $300; lpPalette^.palNumEntries := nColors; byRedMask := (1 shl pfd.cRedBits) - 1; byGreenMask:= (1 shl pfd.cGreenBits) - 1; byBlueMask := (1 shl pfd.cBlueBits) - 1; for i := 0 to nColors - 1 do begin lpPalette^.palPalEntry[i].peRed := (((i shr pfd.cRedShift) and byRedMask) *255)DIV byRedMask; lpPalette^.palPalEntry[i].peGreen:= (((i shr pfd.cGreenShift)and byGreenMask)*255)DIV byGreenMask; lpPalette^.palPalEntry[i].peBlue := (((i shr pfd.cBlueShift) and byBlueMask) *255)DIV byBlueMask; lpPalette^.palPalEntry[i].peFlags:= 0; end; MainForm.myPalette := CreatePalette(lpPalette^); HeapFree(hHeap, 0, lpPalette); if (MainForm.myPalette <> 0) then begin SelectPalette(MainForm.DC, MainForm.myPalette, False); RealizePalette(MainForm.DC); end; end; end; function TMainForm.Selection : integer; var Puffer : array[0..256] of GLUInt; Viewport : {array[0..3] of Integer}TVector4i; Treffer,i : Integer; Z_Wert : GLUInt; Getroffen : GLUInt; tmpBool: Boolean; begin glGetIntegerv(GL_VIEWPORT, @viewport); //Die Sicht speichern glSelectBuffer(256, @Puffer); //Den Puffer zuordnen glRenderMode(GL_SELECT); //In den Selectionsmodus schalten glmatrixmode(gl_projection); //In den Projektionsmodus glPushMatrix; //Um unsere Matrix zu sichern glLoadIdentity; //Und dieselbige wieder zurückzusetzen gluPickMatrix(xs, viewport[3]-ys, 1.0, 1.0, viewport); gluPerspective(45.0, ClientWidth/ClientHeight, 1, 100); render(Self, tmpBool); //Die Szene zeichnen glmatrixmode(gl_projection); //Wieder in den Projektionsmodus glPopMatrix; //um unsere alte Matrix wiederherzustellen treffer := glRenderMode(GL_RENDER); //Anzahl der Treffer auslesen Getroffen := High(GLUInt); //Höchsten möglichen Wert annehmen Z_Wert := High(GLUInt); //Höchsten Z - Wert for i := 0 to Treffer-1 do if Puffer[(i*4)+1] < Z_Wert then begin getroffen := Puffer[(i*4)+3]; Z_Wert := Puffer[(i*4)+1]; end; Result := getroffen; end; // Procedure to send an error message procedure ErrorMsg (Msg: String; MsgTitle: String = 'Error!'); begin Application.MessageBox(PChar(Msg), PChar(MsgTitle), MB_OK or MB_ICONERROR); end; // Procedure to create a texture quad procedure DrawQuad(pX, pY: Single; pWidth, pHeight: Integer); begin glBegin(GL_QUADS); glTexCoord2f(0, 0); glVertex2f(pX, pY); glTexCoord2f(1, 0); glVertex2f(pX+pWidth, pY); glTexCoord2f(1, 1); glVertex2f(pX+pWidth, pY+pHeight); glTexCoord2f(0, 1); glVertex2f(pX, pY+pHeight); glEnd; end; // Procedure to set the opengl sizes procedure SetSizes; begin glMatrixMode(GL_PROJECTION); glLoadIdentity; glViewPort(0, 0, MainForm.ClientWidth, MainForm.ClientHeight); glOrtho(0, SizeX, 0, SizeY, -128, 128); glMatrixMode(GL_MODELVIEW); glLoadIdentity; end; // Procedure to create a new plane procedure NewPlane; begin If (SelPlane.Direction <> 0) and (SelPlane.Direction <> 1) then SelPlane.Direction := Random(dir_MAX+1) else SelPlane.Direction := Integer(not Bool(SelPlane.Direction)); Case SelPlane.Direction of dir_LEFT: SelPlane.pX := SizeX; dir_RIGHT: SelPlane.pX := 0; end; SelPlane.pY := Random(SizeY-ObjHeight*2-ManHeight)+ObjHeight+ManHeight; end; // ========================================================== // TMainForm // ========================================================== procedure TMainForm.FormCreate(Sender: TObject); begin DC:= GetDC(Handle); //SetupPixelFormat; RC:= CreateRenderingContext(DC, [opDoubleBuffered], 32, 24, 0, 0, 0, 0); ActivateRenderingContext(DC, RC); glEnable(GL_DEPTH_TEST); glLoadIdentity; SetSizes; glClearColor(1, 1, 1, 0); glEnable(GL_CULL_FACE); glEnable(GL_TEXTURE_2D); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.1); Application.OnIdle := Render; LoadTexture('Raumschiff.tga', PlaneTex, False); LoadTexture('Schütze.tga', ManTex, False); NewPlane; Options.Speed := 20; Options.CanClick := True; Options.clicksHitted := 0; Options.clicksMissed := 0; Options.clicksTotal := 0; Player.pX := 0; Player.pY := 0; end; // Procedure to render all things procedure TMainForm.Render(Sender: TObject; var Done: Boolean); var CanClickText: String; begin glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); SetSizes; glPrint(10, SizeY-15, 'Speed : '+IntToStr(Options.Speed), 0, 0, 0); glPrint(10, SizeY-35, 'Hits : '+IntToStr(Options.clicksHitted), 0.3, 1, 0.3); glPrint(10, SizeY-55, 'Missed : '+IntToStr(Options.clicksMissed), 1, 0.3, 0.3); glPrint(10, SizeY-75, 'Total : '+IntToStr(Options.clicksTotal), 0, 0, 0); CanClickText := 'You can'#10't hit it now!'; If not Options.CanClick then glPrint(SizeX div 2 - Canvas.TextWidth(CanClickText) div 2, SizeY-95, CanClickText, 1, 0, 0); glPushMatrix; glLoadName(1); glTranslatef(SelPlane.pX, SelPlane.pY, 0); Case SelPlane.Direction of dir_LEFT: glRotatef(90*1, 0, 0, 1); dir_RIGHT: glRotatef(90*3, 0, 0, 1); end; glBindTexture(GL_TEXTURE_2D, PlaneTex); DrawQuad(0,0,ObjWidth,ObjHeight); glPopMatrix; glPushMatrix; glLoadName(2); glTranslatef(Player.pX, Player.pY, 0); glBindTexture(GL_TEXTURE_2D, ManTex); DrawQuad(0,0,ManWidth,ManHeight); glPopMatrix; SwapBuffers(DC); Done := False; end; procedure TMainForm.FormResize(Sender: TObject); begin SetSizes; end; procedure TMainForm.FormDestroy(Sender: TObject); begin DeactivateRenderingContext; DestroyRenderingContext(RC); ReleaseDC(Handle, DC); end; procedure TMainForm.Timer1Timer(Sender: TObject); begin Case SelPlane.Direction of dir_LEFT: SelPlane.pX := SelPlane.pX - Options.Speed; dir_RIGHT: SelPlane.pX := SelPlane.pX + Options.Speed; end; If ((SelPlane.Direction = dir_LEFT) and (SelPlane.pX <= 0-ObjWidth)) or ((SelPlane.Direction = dir_RIGHT) and (SelPlane.pX >= SizeX+ObjWidth)) then NewPlane; end; procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin If Key = VK_F1 then Timer1.Enabled := not Timer1.Enabled; If Timer1.Enabled then begin Options.CanClick := False; Timer2.Enabled := False; Timer2.Enabled := True; end; end; procedure TMainForm.Timer2Timer(Sender: TObject); begin Options.CanClick := True; Timer2.Enabled := False; end; procedure TMainForm.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin If not Options.CanClick then Exit; xs := x; ys := y; If Selection<>-1 then begin ShowMessage(IntToStr(Selection)); Inc(Options.clicksHitted); end else Inc(Options.clicksMissed); Inc(Options.clicksTotal); If Options.clicksTotal mod 20 = 0 then Inc(Options.Speed, 5); end; procedure TMainForm.Timer3Timer(Sender: TObject); begin BorderStyle := bsNone; WindowState := wsMaximized; end; end. |
AW: OpenGL - Prüfen ob Textur angeklickt
Du gestehst OpenGL zu viel "Intelligenz" zu. Es gitb keine "Objekte" in OGL, OGL ist quasi nur ein Pinsel, und der Pinsel für sich ist erstmal doof. Der weiss nicht was er zeichnet, was davon zu einem "Objekt" gehört, nix. Du brauchst also eine ganz und gar eigene Datenstruktur im Hintergrund, die mit OGL überhaupt nichts zu tun hat (zunächst), in der du all deine Logik unterbringst. OGL ist nur zum Zeichnen da. NUR!
Eine Textur ist auch nicht, so wie du es ausdrückst, anklickbar. Das Fenster, in dem OGL was rendert, ist es. Dann bekomst du Fensterkoordinaten, die du (du!) erstmal in Weltkoordinaten deiner grade dargestellten Szene umrechnest. Zunächst mal in der Eye-Plane. Von dort aus musst du (du!) unter Zuhilfenahme von etwas linearer Algebra einen Strahl in deine Szene "schicken", und mit Geraden/Flächen-Schnitt gucken, ob und welches deiner(!) logischen Objekte getroffen wurde, die du idealerweise in einer Liste irgendwo im Sppeicher hast (OGL hat die nämlich nicht, bzw. nicht in auf diese Weise verwertbarer Form). Dann weisst du, welches deiner logischen "Objekte" geklickt wurde, und da du hoffentlich in den Klassen zu deinen Objekten auch die Referenz auf die zu verwendende Textur hast, darüber auch die Textur, des Objektes, das gerade dort zuvorderst dargestellt wird, wo der User auf das Fenster geklickt hat. Verglichen mit einem rosa plüschigen VCL-OnClick() Handler geht dabei natürlich eine ganze Ecke mehr ab, aber so ist das in der "echten" Welt ;) |
AW: OpenGL - Prüfen ob Textur angeklickt
Du willst damit sagen, es ist sehr viel Arbeit etwas anklickbar zu machen? :x
|
AW: OpenGL - Prüfen ob Textur angeklickt
Ja, denn du verlässt bei Benutzung von OpenGL die VCL komplett, was wiederum bedeutet, dass du die gesamte Objekthiearchie, -Verwaltung und Event Handler (wie z.B. ein onClick) deiner gezeichneten Dinge selbst schreiben musst, von Grund auf, angefangen bei (fast) 0.
Beispiel: Eine gezeichnete Textur hat keinerlei Objekt-Referenz in OpenGL, es wird halt einfach gezeichnet. Die Objekt-Struktur musst du dir (vorher) selbst überlegen und dir die Objekte / Klassen selbst ausdenken. (z.B. eine Klasse, die einen texturierten Quad mit den übergebenen Parametern Breite, Höhe, Position zeichnet, die Koordinaten, Verschiebung etc. aber intern sebst verwaltet und eigentlich nur als Draw-Routine eben OpenGL verwendet). Bei OpenGL gibt es eben so etwas Feines wie die VCL nicht, wie Medium bereits gesagt hat, ist OpenGL erstmal nichts andereres als eine Schnittstelle, mit der zu zeichnen kannst, mehr nicht. Als Vorteil der Schnittstelle hast du eben Hardware-Zugriff beim Zeichnen und ein paar nette Funktionen für das Zeichnen und der Transformation der Zeichenfläche selbst, das wars aber schon. (Das ganze Shader-Zeug mal ausgenommen, das würde jetzt aber den Rahmen sprengen...) Willst du aber "ready to use" OnClick, Objekte, etc, musst du eine Game-Engine verwenden, die ein Objekt-System inkl. Eventhandlern usw. bereits implementiert hat und dir diese Arbeit bereits abgenommen hat. Wenn du aber alles von Grund auf lernen willst, also OpenGL nativ verwenden willst, musst du aber auch von Grund auf selbst ran :-) Nicht verzagen, es ist am Anfang sehr hart, aber Stück für Stück lichtet sich das Dunkel und es macht Spass. Auch wenn die Lernkurve echt steil ist und man erstmal Seitenweise lesen muss :-) Ich lege dir nochmal nahe, nimm dir erstmal eine OpenSource Game Engine wie z.B. GLScene und sieh dir den Code und die Objekthiearchie dort an, davon kann man viel lernen. |
AW: OpenGL - Prüfen ob Textur angeklickt
Dann werde ich mir mal GLScene an sehen^^
Danke für alle Antworten! Mfg, Destroxi |
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:16 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz