Pixel in Units

Für Fragen zu Grafik APIs wie DirectX und OpenGL sowie Shaderprogrammierung.
Antworten
Benutzeravatar
Andi
Beiträge: 81
Registriert: 12.03.2009, 00:19

Pixel in Units

Beitrag von Andi »

Hallo liebe ZFX`ler.

Für ein kleines Projekt/Prototype, macht es Sinn einen Passenden Level Editor zu erstellen. Da alles als 2.5D ausgelegt ist, suche ich nach Möglichkeiten, Pixel möglichst genau in World Units umzuwandeln. Was für Möglichkeiten habe ich, wenn auch auf der Z-Achse eine Umrechnung statt finden soll? Wie üblich fehlt mir das grundlegende Matheverständniss dazu :oops:

Ist vermutlich zu arg Off-Topic aber: der Plan ist, das ganze mit WPF und dem Viewport3D zu realisieren, irgendwelche Tipps oder Einwände dazu?

Wäre nett wenn Ihr Denkanstöße, Links, Sheets etc. mit mir teilt.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2547
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Pixel in Units

Beitrag von Jonathan »

Ich glaube, das Problem lässt sich recht leicht und elegant lösen, aber ich bin mir nicht sicher, was genau du eigentlich willst. Evtl. würde eine Zeichnung oder zumindest eine genaue Beschreibung (vielleicht inklusiv eines konkreten Beispiels) helfen.
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
Benutzeravatar
joeydee
Establishment
Beiträge: 1155
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Pixel in Units

Beitrag von joeydee »

Falls ich dich richtig verstehe: Eine Abbildungsmatrix ist hier das Sinnvollste. Die Matrix enthält dann alle Verschiebungen und Zooms der Kamera, und über die Inverse kannst du zwischen Screen- und Mapkoordinaten hin- und herrechnen.
Spalte 1 enthält den Screen-Vektor, der in World-X-Richtung zeigt mal den Scale, Spalte 2 World-Y-Richtung mal Scale, (Spalte 3 Wordl-Z mal Scale), Spalte 4 den Offset.
Eine 2D-Matrix (3x2) reicht bei Iso-Sicht.
Wenn ich es wiederfinde, poste ich ein Beispiel.


Edit: habs gefunden.

https://zfx.info/viewtopic.php?f=7&t=19 ... ile#p25322
Am Ende des Threads auch nochmal aufbau der 2D-Matrix.

Hier auch nochmal ein Flash-Code (AS3), der ein paar Tiles isometrisch per Mapkoordinaten zeichnet und per Klick "wiederfindet". Der Code sollte selbsterklärend sein. Nur nochmal gepostet, weil dieser mit einer 3D-Matrix arbeitet.
Koordinaten-Konventionen hier: X/Y ist Ost/Süd-Richtung in der Ebene.

Code: Alles auswählen

		private var mapToScreen:Matrix3D=new Matrix3D();
		private var screenToMap:Matrix3D=new Matrix3D();
		
		public function isoTiles() {
			var screenEast:Vector3D=new Vector3D(20,-10,0);			// X = Osten = schräg rechts oben mit Scale
			var screenSouth:Vector3D=new Vector3D(20, 10,0);		// Y = Süden = schräg rechts unten mit Scale
			var screenPosition:Vector3D=new Vector3D(200, 100,0);	// Map-Nullpunkt auf Screen
			prepareView(screenEast,screenSouth,screenPosition);
			stage.addEventListener(MouseEvent.CLICK,mClick);
		}
		
		
		private function prepareView(screenEast:Vector3D,screenSouth:Vector3D,screenPosition:Vector3D):void{
			
			var matrixData:Vector.<Number>=Vector.<Number>([
															screenEast.x,screenEast.y,0,0,			//Spalte 1 = Screen-X-Richtung
															screenSouth.x,screenSouth.y,0,0,		//Spalte 2 = Screen-Y-Richtung
															0,0,1,0,								//Spalte 3 bleibt aus der Einheitsmatrix
															screenPosition.x,screenPosition.y,0,1,	//Spalte 4 = Translation
															]);	
			
			mapToScreen.rawData=matrixData;
			screenToMap.rawData=matrixData;
			screenToMap.invert();
			redraw();			
		}
		
		private function redraw():void{
			this.graphics.clear();
			drawTile(new Vector3D(0,0),0xCCCCCC);
			drawTile(new Vector3D(1,0),0xCCCCCC);
			drawTile(new Vector3D(2,0),0xCCCCCC);
			drawTile(new Vector3D(2,1),0xCCCCCC);			
		}

		private function drawTile(mapPos:Vector3D, color:uint):void{
			//a quad tile in map coords:
			var p0:Vector3D=mapPos;
			var p1:Vector3D=mapPos.add(new Vector3D(1,0,0));
			var p2:Vector3D=mapPos.add(new Vector3D(1,1,0));
			var p3:Vector3D=mapPos.add(new Vector3D(0,1,0));
			//a quad in screen coords
			var s0:Vector3D=mapToScreen.transformVector(p0);
			var s1:Vector3D=mapToScreen.transformVector(p1);
			var s2:Vector3D=mapToScreen.transformVector(p2);
			var s3:Vector3D=mapToScreen.transformVector(p3);
			
			this.graphics.lineStyle(1,color);
			this.graphics.moveTo(s0.x,s0.y);
			this.graphics.lineTo(s1.x,s1.y);
			this.graphics.lineTo(s2.x,s2.y);
			this.graphics.lineTo(s3.x,s3.y);
			this.graphics.lineTo(s0.x,s0.y);
			
		}
		
		private function mClick(event:MouseEvent):void{
			var mouseScreen:Vector3D=new Vector3D(stage.mouseX,stage.mouseY,0);
			var mouseMap:Vector3D=screenToMap.transformVector(mouseScreen);//Map-Koordinaten
			mouseMap.x=Math.floor(mouseMap.x);
			mouseMap.y=Math.floor(mouseMap.y);//Tile-Koordinaten
			redraw();
			drawTile(mouseMap,0x000000);//angeklicktes Tile
			trace(mouseMap);
		}

PPS: die swf, funzt ja hier.
isoTiles.swf
(1.35 KiB) 3754-mal heruntergeladen
Hilft das weiter, oder war das Problem ein anderes?
Benutzeravatar
Andi
Beiträge: 81
Registriert: 12.03.2009, 00:19

Re: Pixel in Units

Beitrag von Andi »

Danke joeydee, dass Hilft schon mal. Was ist wenn ich aber eine perspektivische Sicht habe? Ist dann screenEast sowas wie x / viewportWidth??

Ok, ich sehe es ein, meine Frage ist eindeutig zweideutig. joeydee hat so weit ich das überblicke, zumindest für die Iso Sicht, die richtige Lösung.
Versuch es mit einem Beispiel:
Ich habe 2 Bilder, die sind jeweils 1024x1024 Pixel groß. Ich erstell mir natürlich 2 Planes, wobei die erste auf Z = 0 und die zweite auf Z = 10 liegt. Nun würde ich die Units gerne so um rechnen das die jeweils so skaliert/angepasst werden, dass sie im Viewspace für den Betrachter +/- 1024 Pixel einnehmen und das möglichst Pixel genau. Für die "Z Achse Problematik" sollte eigentlich ein Unit * 10 reichen.

Ich muss gestehen das ich noch keine Zeile Code angefangen habe und nur über mögliche Lösungen spekulieren kann. Die optimalste Lösung mag es vermutlich auch nicht sein. Die Grafiken sind übrigens zu komplex um sie auf jeweils NxN große Tiles zu klatschen.

Verbesserung Vorschläge oder andere Ansätze sind erwünscht.
Benutzeravatar
joeydee
Establishment
Beiträge: 1155
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Pixel in Units

Beitrag von joeydee »

Ja, ich hatte 2.5D natürlich erstmal als irgendeine isometrische Perspektive interpretiert :)
(Das Tile-Raster war übrigens nur zur Veranschaulichung, zur Orientierung. Natürlich kann man auch floats übergeben und irgendetwas irgendwo in der Welt platzieren, und ebenso die zurückgerechnete Screenposition einfach nicht abrunden. Die Matrizen sind also nicht an Tiles gebunden.) - hilft dir aber bei echter Perspektive leider nicht.

Was du da beschreibst, hört sich nach einer Parallax-Welt an? D.h. parallel ausgerichtete Kulissen im Raum, zu denen die Kamera immer senkrecht steht, wie z.B. in 2D-Adventures? (Nur dass dort auf "echte" Tiefenberechnung oft verzichtet wird; die Bühnen sind nicht sonderlich "tief" und Spielfiguren werden einfach linear skaliert, abhängig von ihrer Fußposition und je einer Referenzskalierung vorn/hinten).
Jedenfalls deutet deine Beschreibung darauf hin, dass du auch echte Perspektive nutzen musst und willst (Viewport3D).
Jetzt kommt es natürlich darauf an was du über deine Projektionsmatrix weißt bzw. wie diese erstellt wird, und wo die Kamera (Auge) sitzt. Grundsätzlich kannst du dir aus den Informationen ein Referenz-Rechteck in Weltkoordinaten konstruieren (sei es über Trigonometrie aus den Öffnungswinkeln, oder durch die Clipping-Planes) das z.B. im Abstand 1 vom Auge exakt den Bildschirm abdecken würde. Der Rest ist Dreisatz im Verhältnis Referenzrechteck- zu Pixelmaßen und 1 zu aktuellem Ebenenabstand. Kann man sich leicht auf Karopapier in einer Draufsicht herleiten.
Soviel zum Denkanstoß.

Ich habe mit der WPF noch nicht gearbeitet. Ist das die richtige Referenz, wird so die 3D-Projektion angelegt? https://msdn.microsoft.com/de-de/librar ... .110).aspx
Da kann ich gerne nochmal konkret aushelfen, wenn nötig (und falls ich diesmal richtig liege ;)).
Benutzeravatar
Andi
Beiträge: 81
Registriert: 12.03.2009, 00:19

Re: Pixel in Units

Beitrag von Andi »

Moin, ich komm leider erst jetzt dazu zu antworten.

Wenn ich mir meine Frage nochmals anschaue, kann man eigentlich nur davon ausgehen das ich es isometrisch haben wollte.
Eigentlich ja, im Endprodukt soll das bis zu einem gewissen Grad wie Parallax Scrolling aussehen (für das Zeugs was Vorne/Hinten liegt), so einfach hätte ich das Beschreiben sollen. :oops: Positioniert soll im nachhinein aber nicht zwangsmäßig parallel zu den Achsen, das spielt aber erst mal keine Rolle.

Das macht durchaus sinn mit dem Referenzrechteck, wenn ich dein Ansatz richtig verstehe, dann mache ich das bereits mit einer HUD-Textur so. Wie ich das aber vom Screen ins World-Space umrechnen, erschließt sich mir noch nicht so richtig.

Dein Link sieht Kaput aus, wenn es der war, dann einfach das letzte XAML Beispiel. Dort siehst du wie die Kamera gesetzt und somit die Projektion definiert wird.

Ich werde am Weekend mal bisschen rum probieren. Ob du mir jetzt schon konkret weiter Helfen kannst weiss ich nicht, ich denke muss erst paar Linien Code schreiben. Überigens ist nicht so das du falsch lagst, sondern das ich es falsch formuliert habe. ;)
Benutzeravatar
joeydee
Establishment
Beiträge: 1155
Registriert: 23.04.2003, 15:29
Kontaktdaten:

Re: Pixel in Units

Beitrag von joeydee »

Wird das Beste sein, einfach mal loscoden :) dann kannst du evtl. auch anschaulich mit Screenshots zeigen, was Sache ist.

Ich meinte folgenden Link, letztes C#: https://msdn.microsoft.com/de-de/librar ... t3d.camera
Darin steht, dass mit FieldOfView der "horizontal field of view" angegeben wird - die Info ist wichtig.
Ich habe 2 Bilder, die sind jeweils 1024x1024 Pixel groß. Ich erstell mir natürlich 2 Planes, wobei die erste auf Z = 0 und die zweite auf Z = 10 liegt. Nun würde ich die Units gerne so um rechnen das die jeweils so skaliert/angepasst werden, dass sie im Viewspace für den Betrachter +/- 1024 Pixel einnehmen und das möglichst Pixel genau.
Du musst noch deine Positionen in den Kamera-Space bringen (z=0 und z=10 würden z.B. zu z=50 und z=60 bei KameraZ=-50)
Dass dann ein Bild von 1024px auf die errechnete Breite gerendert wird, das passiert natürlich durch die Texturkoordinaten, d.h. der Wert 1024 ist nicht relevant.

Hier nochmal der von mir angesprochene Weg - und falls du es nicht gebrauchen kannst, auch für die Nachwelt:
1. Mittels Tangens berechnet man aus dem Öffnungswinkel (hFov), wie breit der Screen im Abstand 1 wäre: width1=2*tan(hFov/2)
[allgemein: falls man an die Einzelwerte der fertigen Projektionsmatrix kommt, da steht im Prinzip schon alles drin was man braucht; Eintrag 0 und 5 (Diagonale) müssten 1/w1 und 1/h1 sein wenn ich mich nicht irre]
2. Ein Rechteck im Abstand d Units vor der Kamera muss dann d*width1 Units breit sein, um den Bildschirm auszufüllen. (Strahlensatz)
3. Es muss d*width1/screenWidth*screenHeight hoch sein. (Dreisatz)

Herleitung, Zusammenhänge, Zahlenbeispiel:
screenRect.jpg
Benutzeravatar
Krishty
Establishment
Beiträge: 8316
Registriert: 26.02.2009, 11:18
Benutzertext: state is the enemy
Kontaktdaten:

Re: Pixel in Units

Beitrag von Krishty »

joeydee hat geschrieben:Ich meinte folgenden Link, letztes C#: https://msdn.microsoft.com/de-de/librar ... t3d.camera
Darin steht, dass mit FieldOfView der "horizontal field of view" angegeben wird - die Info ist wichtig.
Neben die Tüte gekotzt: Benutzt vertikal, wo immer es geht. In den letzten 20 Jahren sind die Bildschirme immer breiter geworden, aber kaum höher. Wer sehen will, wie horizontales FOV mit der Zeit gealtert ist, kann heute nochmal Far Cry installieren. War für 4:3 gemacht; auf meinem 20:9-Bildschirm wird mir beim Spielen schlecht, so weit ist das FOV daneben.
seziert Ace Combat, Driver, und S.T.A.L.K.E.R.   —   rendert Sterne
Benutzeravatar
Andi
Beiträge: 81
Registriert: 12.03.2009, 00:19

Re: Pixel in Units

Beitrag von Andi »

Ich komme leider wieder spät zum antworten.

Vielen dank euch beiden für die Hilfe, das bring mich schon mal eine Ecke weitere und zu der Erkenntnis, ich sollte die Kamera postieren anstatt die Objekte zu skalieren. Sonst kann ich nicht praktikabel auf Größenänderungen des Fenster reagieren.
joeydee hat geschrieben: Dass dann ein Bild von 1024px auf die errechnete Breite gerendert wird, das passiert natürlich durch die Texturkoordinaten, d.h. der Wert 1024 ist nicht relevant.
Für den Editor ist es schon relevant was für eine Auflösung/Größe das Bild hat. Nicht alle Bilder haben die gleiche Auflösung/Größe und Drag and Drop wird zum Problem.

Dies bezüglich macht es mehr sinn die Kamera anzupassen, oder hab ich wieder ein Konzeptfehler?
Antworten