Text über Objekt ausserhalb des Viewports anzeigen

Fragen zu Grafik- & Soundproblemen und zur Spieleprogrammierung haben hier ihren Platz.
MightyMAC
Beiträge: 55
Registriert: 07.01.2007 18:11
Wohnort: Duisburg
Kontaktdaten:

Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von MightyMAC »

Hallo PBler,

ich möchte in meinem Projekt einen Text überhalb eines (3D-)Objekts darstellen. Das klappt auch super, solange das Objekt innerhalb des Viewports ist, da ich mir die Koordinaten des Objekts mittels CameraProjectionX/Y hole und dann dort den Text hinzeichne. Jetzt hätte ich gerne, daß wenn das Objekt den Viewport z.B. nach rechts verlässt, der Text am rechten Bildschirmrand weiterhin angezeigt wird, was mit den CameraProjection-Befehlen nicht mehr funktioniert, da diese dann -1 zurückgeben.
Die Sache ist einfach, wenn das Objekt den Viewport verlässt, da ich ja dann einfach die letzte Position an welcher das Objekt im Viewport war speichern kann und weiterhin dort den Text anzeigen. Wenn jedoch ein Objekt nie im Viewport war und es erscheint sagen wir mal links von der Kamera/dem Viewport und kommt dann ins Bild hat sich das mit dem Koordinaten speichern erledigt.
Hat von euch einer eine gute Idee parat wie ich sowas umsetzen kann?

Gruß
MAC
Windows XP 32-bit SP3, Windows 7 64-bit, PB 4.60, PB 5.11, PB 5.20
Benutzeravatar
Chimorin
Beiträge: 451
Registriert: 30.01.2013 16:11
Computerausstattung: MSI GTX 660 OC mit TwinFrozr III
6Gb DDR 3 RAM
AMD Phenom II X4 B55 @ 3,6GHz
Windows 7 Home Premium 64-bit

Re: Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von Chimorin »

Gut, so könnte das funktionieren:
1. Du erstellst eine Textur.
2. Du malst mit DrawText() deinen Text darauf.
3. Aus Textur wird Material gemacht.
4. Mit dem Material erstellst du eine Billboardgruppe an der Stelle bei deinem Objekt, nur halt drüber.
5. Du fügst ein Billboard mit den relativen Kooordinaten 0/0/0 hinzu.
6. fertig.

P.S. Die Billboardgruppe und die Textur würde ich am Anfang des Programms erstellen, das Material der Billboardgruppe kann auch im Nachhinein geändert werden.
Bild

- formerly known as Bananenfreak -
MightyMAC
Beiträge: 55
Registriert: 07.01.2007 18:11
Wohnort: Duisburg
Kontaktdaten:

Re: Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von MightyMAC »

Danke, aber das ist nicht mein Problem. Den Text habe ich schon auf dem Bildschirm, es geht mir darum, daß der Text nicht mit dem Objekt über den Bildschirmrand hinaus verschwinden soll, sondern daß er dann sichtbar am Bildschirmrand verharren soll, selbst wenn das Objekt schon raus ist. Also quasi so: Objekt ist im Bild -> Text wird über dem Objekt dargestellt (funktioniert schon); Kamera dreht nach links bis das Objekt auf der rechten Seite den Viewport verlässt -> Text soll am rechten Bildschirmrand stehen bleiben, so das man erkennen kann, das rechts ausserhalb des Bildschirm noch ein Objekt ist.
Ich brauche also im Grunde genommen eine Funktion die mir sagt: ein Objekt ist links/rechts/oben/unten vom Viewport. In anderen 3D-Engines haben die Projection-Funktionen immer Koordinaten zurückgegeben die halt größer/kleiner waren als die Koordinaten im Screen und so konnte man dann abfragen (PseudoCode):

Code: Alles auswählen

If ProjectionX>ScreenWidth
  TextX=ScreenWidth-TextFeldBreite
EndIf
If ProjectionX<0
  TextX=0
EndIf
PB liefert hier allerdings keine Koodinaten ausserhalb des Screen-Bereichs zurück, sondern -1 wenn das Objekt nicht im Screen ist, was diese Vorgehensweise unmöglich macht.
Windows XP 32-bit SP3, Windows 7 64-bit, PB 4.60, PB 5.11, PB 5.20
Benutzeravatar
Makke
Beiträge: 156
Registriert: 24.08.2011 18:00
Computerausstattung: AMD Ryzen 7 5700X - AMD Radeon RX 6800 XT - 32 GB DDR4 SDRAM
Wohnort: Ruhrpott
Kontaktdaten:

Re: Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von Makke »

Hi,

den Text erstellst Du ja im 3D Raum wenn ich das richtig verstanden habe, Du müsstest noch ein paar Infos mehr geben, z.B.:
- bedienst Du tatsächlich alle drei Achsen (Beispiel: Luftkampfspiel) oder nur zwei Achsen (Beispie: 3D Shooter) ?
- sollen immer alle Objecte außerhalb des Viewports "am Bildrand" kleben oder nur ein bestimmtes (Beispiel: Flugzeug hat einen Gegner im Target, der verfolgt werden soll)
- weiterhin ist noch wichtig welchen FieldOfView Wert (CameraFOV()) Du benutzt

Ich meine sowas schon im OGRE Forum gelesen zu haben, das das (nur) über eine Projektions-Matrix zu lösen ist. Das schöne an OGRE ist, das viele Berechnungen zu Matricen und Quaternions mitgeliefert werden, in PB musst Du Dir leider alles selber zusammenschreiben.
---
Windows 11 (64 bit)
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von STARGÅTE »

Da ich sowas bereits geschrieben habe, hier mal meine Variante:

Es ermittelt die CameraProjection, und wenn diese -1 ergibt, rechnet er mit Matrizen.
ExamineCameraProjection() muss dabei die Camera, die Koordinaten und die Bildschirmgröße bekommen.
Außerdem kann ein Padding angegeben werden, jenachdem, wie viel Abstand zum Bildschirmrand sein soll.

Sry, für den CodeStil, aber ich hab das eben aus meinem Projekt rausgerissen.

Code: Alles auswählen

;- Vector3D und Matrix3D

Structure Vector3
	X.f
	Y.f
	Z.f
EndStructure

Structure Matrix3
	A11.f : A12.f : A13.f
	A21.f : A22.f : A23.f
	A31.f : A32.f : A33.f 
EndStructure

Procedure.i V3_Set(*Use.Vector3, X.f, Y.f, Z.f)
	*Use\X = X
	*Use\Y = Y
	*Use\Z = Z
	ProcedureReturn *Use
EndProcedure

Procedure.f V3_Length(*Source.Vector3)
	ProcedureReturn Sqr(*Source\X * *Source\X + *Source\Y * *Source\Y + *Source\Z * *Source\Z)
EndProcedure

Procedure.i V3_Multiply(*Use.Vector3, Value.f)
	*Use\X * Value
	*Use\Y * Value
	*Use\Z * Value
	ProcedureReturn *Use
EndProcedure

Procedure.i V3_Subtraction(*Use.Vector3, *Source1.Vector3, *Source2.Vector3)
	*Use\X = *Source1\X - *Source2\X
	*Use\Y = *Source1\Y - *Source2\Y
	*Use\Z = *Source1\Z - *Source2\Z
	ProcedureReturn *Use
EndProcedure

Procedure.i V3_Normalize(*Use.Vector3)
	Protected Length.f = V3_Length(*Use)
	If Length
		*Use\X / Length
		*Use\Y / Length
		*Use\Z / Length
	EndIf
	ProcedureReturn *Use
EndProcedure

Procedure.i V3_SetLength(*Use.Vector3, Length.f)
	V3_Normalize(*Use)
	V3_Multiply(*Use, Length)
	ProcedureReturn *Use
EndProcedure


Procedure.i V3_Rotate(*Use.Vector3, *Source.Matrix3)
	Protected Buffer.Vector3 
	CopyMemory(*Use, @Buffer, SizeOf(Vector3)) 
	*Use\X = Buffer\X**Source\A11 + Buffer\Y**Source\A12 + Buffer\Z**Source\A13
	*Use\Y = Buffer\X**Source\A21 + Buffer\Y**Source\A22 + Buffer\Z**Source\A23
	*Use\Z = Buffer\X**Source\A31 + Buffer\Y**Source\A32 + Buffer\Z**Source\A33
	ProcedureReturn *Use
EndProcedure

Procedure M3_Inverse(*Use.Matrix3, *Source.Matrix3)
	Protected Factor.f
	With *Source
		Factor.f = 1 / (\A11*\A22*\A33-\A13*\A22*\A31+\A12*\A23*\A31+\A13*\A21*\A32-\A11*\A23*\A32-\A12*\A21*\A33)
		*Use\A11 = (\A22*\A33-\A23*\A32) * Factor
		*Use\A12 = (\A13*\A32-\A12*\A33) * Factor
		*Use\A13 = (\A12*\A23-\A13*\A22) * Factor
		*Use\A21 = (\A23*\A31-\A21*\A33) * Factor
		*Use\A22 = (\A11*\A33-\A13*\A31) * Factor
		*Use\A23 = (\A13*\A21-\A11*\A23) * Factor
		*Use\A31 = (\A21*\A32-\A22*\A31) * Factor
		*Use\A32 = (\A12*\A31-\A11*\A32) * Factor
		*Use\A33 = (\A11*\A22-\A12*\A21) * Factor
	EndWith
EndProcedure

Procedure M3_Orientation(*Use.Matrix3, X.f, Y.f, Z.f, W.f)
	With *Use
		\A11 = W*W+X*X-Y*Y-Z*Z
		\A12 = 2*X*Y-2*W*Z
		\A13 = 2*X*Z+2*W*Y
		\A21 = 2*X*Y+2*W*Z
		\A22 = W*W-X*X+Y*Y-Z*Z
		\A23 = 2*Y*Z-2*W*X
		\A31 = 2*X*Z-2*W*Y
		\A32 = 2*Y*Z+2*W*X
		\A33 = W*W-X*X-Y*Y+Z*Z
	EndWith
EndProcedure



;- Camera Projection

Structure CameraProjection
	X.f
	Y.f
	Distance.f
	Direction.f
EndStructure

Global CameraProjection.CameraProjection

Procedure ExamineCameraProjection(Camera.i, X.f, Y.f, Z.f, Width.i, Height.i, Padding.f=0.0)
	Protected ProjectionX.f = CameraProjectionX(Camera, X, Y, Z)
	Protected ProjectionY.f = CameraProjectionY(Camera, X, Y, Z)
	Protected Direction.Vector3, CameraDirection.Vector3
	Protected Projection.Vector3, Length.f, Inverse.Matrix3, Orientation.Matrix3
	V3_Set(Direction, X-CameraX(Camera), Y-CameraY(Camera), Z-CameraZ(Camera))
	CameraProjection\Distance = V3_Length(Direction)
	If ProjectionX = -1 Or ProjectionY = -1
		V3_Normalize(Direction)
		V3_Set(CameraDirection, CameraDirectionX(Camera), CameraDirectionY(Camera), CameraDirectionZ(Camera))
		V3_Subtraction(Projection, CameraDirection, Direction)
		FetchOrientation(CameraID(Camera))
		M3_Orientation(Orientation, GetX(), GetY(), GetZ(), GetW())
		M3_Inverse(Inverse, Orientation)
		V3_Rotate(Projection, Inverse)
		Projection\Z = 0
		Projection\X = -Projection\X
		Length = Sqr(Width*Width/4+Height*Height/4) - Sqr(Padding*Padding*2)
		V3_SetLength(Projection, Length)
		If Projection\X < -(Width/2-Padding)
			CameraProjection\X = Padding
			CameraProjection\Y = Projection\Y * Abs((Width/2-Padding)/Projection\X) + Height/2
		ElseIf Projection\X > Width/2-Padding
			CameraProjection\X = Width-Padding
			CameraProjection\Y = Projection\Y * Abs((Width/2-Padding)/Projection\X) + Height/2
		ElseIf Projection\Y < -(Height/2-Padding)
			CameraProjection\X = Projection\X * Abs((Height/2-Padding)/Projection\Y) + Width/2
			CameraProjection\Y = Padding
		ElseIf Projection\Y > Height/2-Padding
			CameraProjection\X = Projection\X * Abs((Height/2-Padding)/Projection\Y) + Width/2
			CameraProjection\Y = Height-Padding
		Else
			CameraProjection\X = Projection\X + Width/2
			CameraProjection\Y = Projection\Y + Height/2
 		EndIf
	Else
		CameraProjection\X = ProjectionX
		CameraProjection\Y = ProjectionY
	EndIf
EndProcedure

;- Demo

InitEngine3D()
InitSprite()
UsePNGImageDecoder()
InitMouse()

Enumeration
	#Window
	#Camera
	#Sprite
	#Light
	#Entity
EndEnumeration

OpenWindow(#Window, 0, 0, 800, 600, "ScreenTitle", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(#Window), 0, 0, WindowWidth(#Window), WindowHeight(#Window), 0, 0, 0)

CatchSprite(#Sprite, ?cross, #PB_Sprite_AlphaBlending)

CreateCamera(#Camera, 0, 0, 100, 100)
MoveCamera(#Camera, 0, 0, 4)
CameraLookAt(#Camera, 0, 0, 0)

CreateLight(#Light, $FFFFFF, 5, 0, 5)

CreateEntity(#Entity, MeshID(CreateCube(#PB_Any, 1)), #PB_Material_None, 1, 0, 0)

Repeat
	
	Repeat
		
		Select WindowEvent()
			Case #PB_Event_CloseWindow
				End
			Case #PB_Event_None
				Break
		EndSelect
		
	ForEver
	
	RenderWorld()
	
	ExamineMouse()
	RotateCamera(#Camera, -MouseDeltaY()/10, -MouseDeltaX()/10, 0, #PB_Relative)
	
	ExamineCameraProjection(#Camera, EntityX(#Entity), EntityY(#Entity), EntityZ(#Entity), 800, 600, 20)
	
	DisplayTransparentSprite(#Sprite, CameraProjection\X-16, CameraProjection\Y-16)
	
	FlipBuffers()
	
ForEver

DataSection
	cross:
	Data.q $0A1A0A0D474E5089,$524448490D000000,$2000000020000000,$7A7A730000000608,$58457419000000F4
	Data.q $72617774666F5374,$2065626F64410065,$6165526567616D49,$00003C65C9717964,$DA7854414449BB03
	Data.q $3E145114486B57AC,$607CAFADADBAAE3B,$2432528F96AE618A,$C922C2148928CD4B,$A20A230485032908
	Data.q $814487E920CBF91F,$05945191FC0F4245,$928888A4A9A26519,$956CB528B335DDCF,$EE3BDDAEE1F75D5D
	Data.q $70BD59DDEF663EC8,$7DDF7DF39CCEE776,$674F9BF80067B9CC,$379E0D7C360AEA4E,$6B0B674D20D8708F
	Data.q $EB506ACE11E110EB,$6BE1AC09B99F95FB,$1B1DD9A9C708440F,$E20B59BE3FE61D86,$8E0847C22013DF0C
	Data.q $866784C72754FF08,$3B8584AB5F274C04,$E0C1572F9BA8BC95,$5D45F7EB6CC82AED,$05C4470420DC8123
	Data.q $C49BDABA0EB95D25,$B54D50C06FCB49A1,$87EFA830E11E112B,$88BC62204C98AE6F,$055C562416E0F4B6
	Data.q $867E392C1CB0E44C,$F0FCDACB9838687D,$89DD00478B21040C,$91751EFEA1812F17,$6E5DFEF8602B8B7D
	Data.q $5D43EEC41E415826,$08316430923AC885,$1FCF4C1CB4A13DA8,$5D48C1974FBC8152,$A3679106342D7B2D
	Data.q $6D0A6E223FB204EE,$A7C6E60A5F3CEC45,$FBFBFEC2D18D4054,$FA307382AF5F5430,$2BC084DB9C8ECEA4
	Data.q $23601AEF2C04B8A2,$9D8FF5A3045F931A,$9C762257435ED7C8,$DCF63EB57E680629,$4F9C979EACF63093
	Data.q $373E6022C288B380,$2F630798396DC479,$2224E012BB925C1A,$44127D771029C4FE,$125FAF1404719CBE
	Data.q $002F1C459C0249C9,$B37B4DC8B776DEEF,$989B8E4A91B6F141,$B31C26AE06B46380,$6D6BE4356E224D99
	Data.q $70CB5819B4E448BF,$D04FA464818F4771,$7BC3F280F613E812,$7F1E4C025E41D9DA,$426D1E43E3241738
	Data.q $22899A5A28126C7D,$0FE9021CE791C444,$281C745D42DEBAE5,$05D5F1108A5D5ADB,$F02CACB899B2C1E9
	Data.q $B118B44490DC9A9B,$04EC22BC1D1D940D,$FEC83F633C817570,$1FFB2D1AD581514D,$8044B76AFAA32FEC
	Data.q $3C89C608938BEBAA,$678ED066E7FC1D3D,$59E9C9850C0DA688,$6C62631FCD35F0D6,$06969E476C5CA3C7
	Data.q $6EBF20E4E8F38B81,$42E07A7AA81912F3,$13B1696162A158EF,$1871896BD58D89A0,$244553837F21FB1B
	Data.q $953A9EB320854D4F,$ACA00606A82F8C73,$5AE18DD1AC3F914F,$1494F2564E245906,$50125E18E818B208
	Data.q $222AE621CBB3F7F5,$B222DA8D13532F30,$8C02AC66B7441F25,$2577CBB591A1EB38,$6BCB544942B33043
	Data.q $FAA2757007BB1115,$E21AE5D9936A083A,$319360DC81C7D867,$1115AC717708B027,$910838F8F2445538
	Data.q $52A0756ACF04ED49,$1C241D9E5DC8F928,$C1A10EDD8F24456A,$8D5079EABF83EC81,$078E38BB8391A37F
	Data.q $D03BC0F4F8E8B714,$6F80416374FBE8F4,$147A4B7404936489,$5AB74E1DB92EE134,$71C5B59CC24072D3
	Data.q $C596428823C474E7,$3F50F34BFA26547D,$0C70CD3E42B4171A,$22BAFC7289C0758E,$18DDBFE7D6914455
	Data.q $56D91C2C8E056F39,$C7E445484679A39B,$104CC6EA71D272A5,$53B45600300BFE71,$000000AF4D4CDE60
	Data.q $6042AE444E454900,$0000000000000082
EndDataSection
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
MightyMAC
Beiträge: 55
Registriert: 07.01.2007 18:11
Wohnort: Duisburg
Kontaktdaten:

Re: Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von MightyMAC »

Hi, im konkreten Fall geht es darum Untertitel von Charakteren in einem Spiel anzuzeigen, wenn diese sprechen. Die Untertitel sollen dann über dem Charakter angezeigt werden (was sie zu Übertiteln macht :wink: ). Und wenn jetzt ein Charakter am Bildschrimrand herausmarschiert, soll der Untertitel weiterhin zu sehen sein wenn er dabei weiterplaudert, so daß der Spieler sehen kann: "Aha, rechts im Off steht einer und redet!". Ich habe mir jetzt überlegt ich versuche es mal so:

Code: Alles auswählen

Kamera-Projektions-Koodinaten abfragen 
-> wenn die Werte plausibel sind (Objekt ist sichtbar), den Text normal anzeigen
-> wenn die Werte -1 ergeben könnte ich hingehen und mir die aktuellen Kamerawinkel merken, dann ein CameraLookAt auf das Objekt machen und die Winkeldifferenz benutzen um zu erkennen ob das Objekt z.B. links oder rechts vom Kamera-Viewport ist (je nachdem ob die Winkel größer oder kleiner werden), danach die Kamera auf die Ursprungsausrichtung zurücksetzen
Ich schaue mal ob das so klappt wie ich mir das vorstelle.

[EDIT] Danke, Stargate. Deinen Code schaue ich mir mal an, scheint ja genau das zu sein was ich brauche!
Windows XP 32-bit SP3, Windows 7 64-bit, PB 4.60, PB 5.11, PB 5.20
Benutzeravatar
Makke
Beiträge: 156
Registriert: 24.08.2011 18:00
Computerausstattung: AMD Ryzen 7 5700X - AMD Radeon RX 6800 XT - 32 GB DDR4 SDRAM
Wohnort: Ruhrpott
Kontaktdaten:

Re: Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von Makke »

@Stargate: Hut ab ! Sehr schick.
---
Windows 11 (64 bit)
MightyMAC
Beiträge: 55
Registriert: 07.01.2007 18:11
Wohnort: Duisburg
Kontaktdaten:

Re: Text über Objekt ausserhalb des Viewports anzeigen

Beitrag von MightyMAC »

Da schließe ich mich an, der Code ist perfekt, danke!
Windows XP 32-bit SP3, Windows 7 64-bit, PB 4.60, PB 5.11, PB 5.20
Antworten