<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
		<id>https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tak2004</id>
		<title>DGL Wiki - Benutzerbeiträge [de]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.delphigl.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Tak2004"/>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php/Spezial:Beitr%C3%A4ge/Tak2004"/>
		<updated>2026-05-25T09:17:38Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27025</id>
		<title>DGL Treffen/2019/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27025"/>
				<updated>2019-07-20T08:36:35Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Orga =&lt;br /&gt;
&lt;br /&gt;
== Raumkonstellation ==&lt;br /&gt;
&lt;br /&gt;
# Doppel Bett&lt;br /&gt;
#* Thomas&lt;br /&gt;
#* Nini&lt;br /&gt;
# Einzelbett&lt;br /&gt;
#* i0n0s&lt;br /&gt;
# Einzelbett&lt;br /&gt;
#* Flash&lt;br /&gt;
# Einzelbett&lt;br /&gt;
#* Frase&lt;br /&gt;
# Einzelbett&lt;br /&gt;
#* Phobeus&lt;br /&gt;
# Einzelbett&lt;br /&gt;
#* Pixelschubser&lt;br /&gt;
# Einzelbett&lt;br /&gt;
#* End&lt;br /&gt;
&lt;br /&gt;
= Essen =&lt;br /&gt;
&lt;br /&gt;
== Hauptgerichte: ==&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3216831478679797/Kartoffelsuppe-mit-Gemueseeinlage.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/272411104287283/Lasagne-mit-buntem-Gemuese.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/148291065256295/Zwiebelsuppe-franzoesische-Art.html (mit Gemüsebrüge statt Fleischbrühe)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2922871444587593/Vegetarisches-Thai-Curry-mit-Kokosmilch-fuer-Geniesser.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1350991210704/Tortellini-aus-dem-Ofen.html (geht natürlich auch ohne den Schinken)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3227981480245936/Spaetzle-mit-Champignon-Rahm-Sauce.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/148978964319/Tomatensuppe.html (schmeckt auch super wenn man noch Gnocchi reinmacht)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2322571370268259/Asiatische-Mie-Nudeln-mit-Gemuese-gebraten.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/595441159189225/Chili-sin-Carne.html&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/pasta-in-paprika-cheddar-sosse/hhiayg61-e3c2a-207386-cfcd2-pcp02m7v&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/389651126291925/Quattro-Formaggi.html (mit irgendeiner Pasta)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/193101081875403/Pilzragout-mit-Semmelknoedel.html (geht natürlich auch ohne Bacon)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1847311299234839/Killer-Mac-and-Cheese.html&lt;br /&gt;
&lt;br /&gt;
== Snacks/Salate/Beilagen: ==&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3519451524912866/Vegetarischer-Taco-Salat.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1349881239714469/Melonen-Rucola-Salat-mit-Feta.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/543061151735261/Nudelsalat-mit-Joghurt-Dip.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1819441295342197/Kartoffelsalat-mit-Avocado.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2102521339361536/Deftige-Muffins.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1395581244471444/Kaesestangen-aus-Blaetterteig.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/998571205222584/Kraeuterbutter-Zwiebel-Muffins.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/107771045311561/Leckere-gefuellte-Kartoffeln.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/682471170749212/Mini-Pizzaschnecken.html (geht natürlich auch veggie nur mit Gemüse)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2007071325278890/Vegane-Gemuesefrikadellen.html&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/zucchini-feta-muffins/4e7avmvh-dc621-905827-cfcd2-45ntc3ci&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/pizza-ring/nbm69krr-5f3da-578240-cfcd2-twmtc6jp (geht natürlich auch veggie)&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/grundrezepte-rezepte/tomaten-knobi-falte/pq08pv7g-4312d-461293-cfcd2-lej25uez&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/zucchini-puffer-glutenfrei-weizenfrei/adx81qya-60b88-327159-cfcd2-9yn0ptkw&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/mini-kaesehoernchen-suchtfaktor/g8uam4h2-51fe6-174536-cfcd2-zujmpnp4&lt;br /&gt;
&lt;br /&gt;
== Coole Projekte/Spielzeug im Schlepptau ==&lt;br /&gt;
&lt;br /&gt;
# VR ?&lt;br /&gt;
# QAMFIO (Quests, Achievements, Meta, Friends, IO) zusammen gehackt mit AWS Cognito, LDAP, NodeJS(typescript), neDB, Unity 3D, WebSocket&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27024</id>
		<title>DGL Treffen/2019/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27024"/>
				<updated>2019-07-20T08:19:07Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Hauptgerichte: ==&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3216831478679797/Kartoffelsuppe-mit-Gemueseeinlage.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/272411104287283/Lasagne-mit-buntem-Gemuese.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/148291065256295/Zwiebelsuppe-franzoesische-Art.html (mit Gemüsebrüge statt Fleischbrühe)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2922871444587593/Vegetarisches-Thai-Curry-mit-Kokosmilch-fuer-Geniesser.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1350991210704/Tortellini-aus-dem-Ofen.html (geht natürlich auch ohne den Schinken)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3227981480245936/Spaetzle-mit-Champignon-Rahm-Sauce.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/148978964319/Tomatensuppe.html (schmeckt auch super wenn man noch Gnocchi reinmacht)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2322571370268259/Asiatische-Mie-Nudeln-mit-Gemuese-gebraten.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/595441159189225/Chili-sin-Carne.html&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/pasta-in-paprika-cheddar-sosse/hhiayg61-e3c2a-207386-cfcd2-pcp02m7v&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/389651126291925/Quattro-Formaggi.html (mit irgendeiner Pasta)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/193101081875403/Pilzragout-mit-Semmelknoedel.html (geht natürlich auch ohne Bacon)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1847311299234839/Killer-Mac-and-Cheese.html&lt;br /&gt;
&lt;br /&gt;
== Snacks/Salate/Beilagen: ==&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3519451524912866/Vegetarischer-Taco-Salat.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1349881239714469/Melonen-Rucola-Salat-mit-Feta.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/543061151735261/Nudelsalat-mit-Joghurt-Dip.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1819441295342197/Kartoffelsalat-mit-Avocado.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2102521339361536/Deftige-Muffins.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/1395581244471444/Kaesestangen-aus-Blaetterteig.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/998571205222584/Kraeuterbutter-Zwiebel-Muffins.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/107771045311561/Leckere-gefuellte-Kartoffeln.html&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/682471170749212/Mini-Pizzaschnecken.html (geht natürlich auch veggie nur mit Gemüse)&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/2007071325278890/Vegane-Gemuesefrikadellen.html&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/zucchini-feta-muffins/4e7avmvh-dc621-905827-cfcd2-45ntc3ci&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/pizza-ring/nbm69krr-5f3da-578240-cfcd2-twmtc6jp (geht natürlich auch veggie)&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/grundrezepte-rezepte/tomaten-knobi-falte/pq08pv7g-4312d-461293-cfcd2-lej25uez&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/zucchini-puffer-glutenfrei-weizenfrei/adx81qya-60b88-327159-cfcd2-9yn0ptkw&lt;br /&gt;
&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/mini-kaesehoernchen-suchtfaktor/g8uam4h2-51fe6-174536-cfcd2-zujmpnp4&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27023</id>
		<title>DGL Treffen/2019/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27023"/>
				<updated>2019-07-20T08:17:59Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
== Hauptgerichte: ==&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3216831478679797/Kartoffelsuppe-mit-Gemueseeinlage.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/272411104287283/Lasagne-mit-buntem-Gemuese.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/148291065256295/Zwiebelsuppe-franzoesische-Art.html (mit Gemüsebrüge statt Fleischbrühe)&lt;br /&gt;
https://www.chefkoch.de/rezepte/2922871444587593/Vegetarisches-Thai-Curry-mit-Kokosmilch-fuer-Geniesser.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1350991210704/Tortellini-aus-dem-Ofen.html (geht natürlich auch ohne den Schinken)&lt;br /&gt;
https://www.chefkoch.de/rezepte/3227981480245936/Spaetzle-mit-Champignon-Rahm-Sauce.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/148978964319/Tomatensuppe.html (schmeckt auch super wenn man noch Gnocchi reinmacht)&lt;br /&gt;
https://www.chefkoch.de/rezepte/2322571370268259/Asiatische-Mie-Nudeln-mit-Gemuese-gebraten.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/595441159189225/Chili-sin-Carne.html&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/pasta-in-paprika-cheddar-sosse/hhiayg61-e3c2a-207386-cfcd2-pcp02m7v&lt;br /&gt;
https://www.chefkoch.de/rezepte/389651126291925/Quattro-Formaggi.html (mit irgendeiner Pasta)&lt;br /&gt;
https://www.chefkoch.de/rezepte/193101081875403/Pilzragout-mit-Semmelknoedel.html (geht natürlich auch ohne Bacon)&lt;br /&gt;
https://www.chefkoch.de/rezepte/1847311299234839/Killer-Mac-and-Cheese.html&lt;br /&gt;
&lt;br /&gt;
== Snacks/Salate/Beilagen: ==&lt;br /&gt;
&lt;br /&gt;
https://www.chefkoch.de/rezepte/3519451524912866/Vegetarischer-Taco-Salat.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1349881239714469/Melonen-Rucola-Salat-mit-Feta.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/543061151735261/Nudelsalat-mit-Joghurt-Dip.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1819441295342197/Kartoffelsalat-mit-Avocado.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/2102521339361536/Deftige-Muffins.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1395581244471444/Kaesestangen-aus-Blaetterteig.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/998571205222584/Kraeuterbutter-Zwiebel-Muffins.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/107771045311561/Leckere-gefuellte-Kartoffeln.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/682471170749212/Mini-Pizzaschnecken.html (geht natürlich auch veggie nur mit Gemüse)&lt;br /&gt;
https://www.chefkoch.de/rezepte/2007071325278890/Vegane-Gemuesefrikadellen.html&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/zucchini-feta-muffins/4e7avmvh-dc621-905827-cfcd2-45ntc3ci&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/pizza-ring/nbm69krr-5f3da-578240-cfcd2-twmtc6jp (geht natürlich auch veggie)&lt;br /&gt;
https://www.rezeptwelt.de/grundrezepte-rezepte/tomaten-knobi-falte/pq08pv7g-4312d-461293-cfcd2-lej25uez&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/zucchini-puffer-glutenfrei-weizenfrei/adx81qya-60b88-327159-cfcd2-9yn0ptkw&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/mini-kaesehoernchen-suchtfaktor/g8uam4h2-51fe6-174536-cfcd2-zujmpnp4&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27022</id>
		<title>DGL Treffen/2019/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2019/Organisation&amp;diff=27022"/>
				<updated>2019-07-20T08:14:46Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: Die Seite wurde neu angelegt: „Hauptgerichte: https://www.chefkoch.de/rezepte/3216831478679797/Kartoffelsuppe-mit-Gemueseeinlage.html https://www.chefkoch.de/rezepte/272411104287283/Lasagne-…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Hauptgerichte:&lt;br /&gt;
https://www.chefkoch.de/rezepte/3216831478679797/Kartoffelsuppe-mit-Gemueseeinlage.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/272411104287283/Lasagne-mit-buntem-Gemuese.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/148291065256295/Zwiebelsuppe-franzoesische-Art.html (mit Gemüsebrüge statt Fleischbrühe)&lt;br /&gt;
https://www.chefkoch.de/rezepte/2922871444587593/Vegetarisches-Thai-Curry-mit-Kokosmilch-fuer-Geniesser.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1350991210704/Tortellini-aus-dem-Ofen.html (geht natürlich auch ohne den Schinken)&lt;br /&gt;
https://www.chefkoch.de/rezepte/3227981480245936/Spaetzle-mit-Champignon-Rahm-Sauce.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/148978964319/Tomatensuppe.html (schmeckt auch super wenn man noch Gnocchi reinmacht)&lt;br /&gt;
https://www.chefkoch.de/rezepte/2322571370268259/Asiatische-Mie-Nudeln-mit-Gemuese-gebraten.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/595441159189225/Chili-sin-Carne.html&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/pasta-in-paprika-cheddar-sosse/hhiayg61-e3c2a-207386-cfcd2-pcp02m7v&lt;br /&gt;
https://www.chefkoch.de/rezepte/389651126291925/Quattro-Formaggi.html (mit irgendeiner Pasta)&lt;br /&gt;
https://www.chefkoch.de/rezepte/193101081875403/Pilzragout-mit-Semmelknoedel.html (geht natürlich auch ohne Bacon)&lt;br /&gt;
https://www.chefkoch.de/rezepte/1847311299234839/Killer-Mac-and-Cheese.html&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Snacks/Salate/Beilagen:&lt;br /&gt;
https://www.chefkoch.de/rezepte/3519451524912866/Vegetarischer-Taco-Salat.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1349881239714469/Melonen-Rucola-Salat-mit-Feta.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/543061151735261/Nudelsalat-mit-Joghurt-Dip.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1819441295342197/Kartoffelsalat-mit-Avocado.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/2102521339361536/Deftige-Muffins.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/1395581244471444/Kaesestangen-aus-Blaetterteig.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/998571205222584/Kraeuterbutter-Zwiebel-Muffins.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/107771045311561/Leckere-gefuellte-Kartoffeln.html&lt;br /&gt;
https://www.chefkoch.de/rezepte/682471170749212/Mini-Pizzaschnecken.html (geht natürlich auch veggie nur mit Gemüse)&lt;br /&gt;
https://www.chefkoch.de/rezepte/2007071325278890/Vegane-Gemuesefrikadellen.html&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/zucchini-feta-muffins/4e7avmvh-dc621-905827-cfcd2-45ntc3ci&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/pizza-ring/nbm69krr-5f3da-578240-cfcd2-twmtc6jp (geht natürlich auch veggie)&lt;br /&gt;
https://www.rezeptwelt.de/grundrezepte-rezepte/tomaten-knobi-falte/pq08pv7g-4312d-461293-cfcd2-lej25uez&lt;br /&gt;
https://www.rezeptwelt.de/hauptgerichte-mit-gemuese-rezepte/zucchini-puffer-glutenfrei-weizenfrei/adx81qya-60b88-327159-cfcd2-9yn0ptkw&lt;br /&gt;
https://www.rezeptwelt.de/backen-herzhaft-rezepte/mini-kaesehoernchen-suchtfaktor/g8uam4h2-51fe6-174536-cfcd2-zujmpnp4&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2017/Organisation&amp;diff=26376</id>
		<title>DGL Treffen/2017/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2017/Organisation&amp;diff=26376"/>
				<updated>2017-05-30T05:15:10Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Was gibts zu essen? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Wie bereits im Forum angedroht, planen wir momentan ein DGL-Treffen in Schweden im Juli 2017. Hierfür geht es an einen See in Ryd.&lt;br /&gt;
&lt;br /&gt;
;Thema: &amp;quot;Going Wild&amp;quot; ;-)&lt;br /&gt;
&lt;br /&gt;
Weitere Infos und detaillierte Besprechungen finden in [https://delphigl.com/forum/viewtopic.php?f=4&amp;amp;t=11569 diesem Forenthread] statt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Wo?==&lt;br /&gt;
S25105&lt;br /&gt;
Södra Rimshult 2,&lt;br /&gt;
Ryd&lt;br /&gt;
&lt;br /&gt;
[http://www.novasol.de/p/S25105?PE=8&amp;amp;K=0&amp;amp;SD=01-07-2017&amp;amp;DUR=14&amp;amp;ED=15-07-2017&amp;amp;wt.si_n=NormalSearchBookingFlow#overview-tab Novasol Link]&lt;br /&gt;
&lt;br /&gt;
Latitude:56.41619, Longitude:14.7563549.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Wann?==&lt;br /&gt;
*Anreise: Sa. 01.07.2017&lt;br /&gt;
*Abreise: Sa. 15.07.2017&lt;br /&gt;
&lt;br /&gt;
==Was kostet das?==&lt;br /&gt;
Ein Preis von 500€-700€ wird angestrebt. Letztendlich hängt der Preis davon ab, wieviel verzerrt und unternommen wird. Anreise erfolgt gemeinsam über Gruppen. Die Anreise bis zu einem gemeinsamen Treffpunkt muss selbstständig organisiert werden.&lt;br /&gt;
Die Verpflegung erfolgt üblicherweise über eine Umlage und wir holen uns gemeinsam etwas.&lt;br /&gt;
&lt;br /&gt;
Die Abrechnung erfolgt einige Wochen nach Ende. Wer einen längeren Zahlungshorizont braucht, sollte dies bitte vorher bei Phobeus melden.&lt;br /&gt;
 Sollte jemand aus Kostengründen nicht teilnehmen können, kann er sich per Mail an Phobeus wenden.&lt;br /&gt;
&lt;br /&gt;
==Wer kommt mit?==&lt;br /&gt;
Zumindest nicht mehr, wer sich nicht bisher angemeldet hat. Es sind 8 Betten im Haus und diese sind bereits alle belegt. Bitte beim nächsten Mal rechtzeitig melden und alle mit Bedarf können mitkommen ;)&lt;br /&gt;
&lt;br /&gt;
ARG = Anreisegruppe ;)&lt;br /&gt;
&lt;br /&gt;
[[Datei:DGL_Treffen_2017_Feldkarte.jpg|200px|thumb|right|Feldkarte für die Anfahrt]]&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Teilnehmer&lt;br /&gt;
!Tage&lt;br /&gt;
(14=max)&lt;br /&gt;
!Anreise&lt;br /&gt;
!Kommentar&lt;br /&gt;
|-&lt;br /&gt;
|Phobeus&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(ARG Nord: 1 Plätze im PKW frei ab Hamburg.)&lt;br /&gt;
|-&lt;br /&gt;
|i0n0s&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(ARG SÜD: 1 Platz im PKW frei ab Gießen.)&lt;br /&gt;
|-&lt;br /&gt;
|Pixelschubser&lt;br /&gt;
|14&lt;br /&gt;
| -&lt;br /&gt;
|(Anreise über ARG Nord)&lt;br /&gt;
|-&lt;br /&gt;
|Flash&lt;br /&gt;
|14&lt;br /&gt;
|PKW&lt;br /&gt;
| ARG Ost: 2-3 Plätze im Wagen (?) frei ab Chemnitz&lt;br /&gt;
|-&lt;br /&gt;
|TAK2004&lt;br /&gt;
|14&lt;br /&gt;
| -&lt;br /&gt;
| Anreise über ARG Ost?&lt;br /&gt;
|-&lt;br /&gt;
|Frase&lt;br /&gt;
|14&lt;br /&gt;
| -&lt;br /&gt;
| Anreise über ARG Ost&lt;br /&gt;
|-&lt;br /&gt;
|End&lt;br /&gt;
|14&lt;br /&gt;
| -&lt;br /&gt;
| Anreise über ARG Süd oder ARG Nord&lt;br /&gt;
|-&lt;br /&gt;
| ''belegt''&lt;br /&gt;
| &lt;br /&gt;
| -&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Wie kommt man hin?==&lt;br /&gt;
Die Anreisedetails stehen noch nicht fest. Mögliche Anreise einen Tag vorher und Übernachtung in Hamburg bei Phobeus ist möglich. Von dort aus geht es Richtung Rostock, wo der nächste Treffpunkt für die Überfahrt mit der Fähre ist. Von da aus geht es dann mit dem Auto bis zum Ziel&lt;br /&gt;
&lt;br /&gt;
==Was muss man persönlich mitbringen?==&lt;br /&gt;
* ggf. Reisekasse für eigene Einkäufe (Schweden hat keinen Euro!)&lt;br /&gt;
* Bettwäsche und Handtücher&lt;br /&gt;
* Wechsel-Kleidung&lt;br /&gt;
* Reisedokumente (Führerschein, Personalausweis, Versicherungs- und Geldkarten)&lt;br /&gt;
* Reiseapotheke&lt;br /&gt;
* Hygieneartikel &lt;br /&gt;
* Badesachen (inkl. Sonnencreme, Mückencreme)&lt;br /&gt;
* Sonstiges (was zu lesen, Schreibzeug etc.)&lt;br /&gt;
&lt;br /&gt;
==Was müssen wir gemeinsammitbringen?==&lt;br /&gt;
* Klopapier&lt;br /&gt;
* Netzwerkkabel (!!!!)&lt;br /&gt;
* Steckdosenleisten (!!!!!)&lt;br /&gt;
* Küchenequipement (Gewürze, Dosenöffner/Korkenzieher/Flaschenöffner, Kaffeefilter, Geschirrtücher, Wischtücher, Küchenrolle, Spülmittel)&lt;br /&gt;
* Elektronik (1 Router, Laptop, Netzwerkkabel, Fotoapparat)&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu erleben?==&lt;br /&gt;
*DGLer in echt ;)&lt;br /&gt;
*Spiel und Spannung&lt;br /&gt;
*Eine große weiße Leinwand zum bewundern (?)&lt;br /&gt;
*Ausgebildete Barkeeper&lt;br /&gt;
*Baden und Grillen&lt;br /&gt;
*Mini-LAN&lt;br /&gt;
*Virtuelle Realitäten (?)&lt;br /&gt;
*Live Projektvorstellung&lt;br /&gt;
*Wildnis pur! (To be discussed, ob draußen oder drinnen)&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu essen?==&lt;br /&gt;
&lt;br /&gt;
Wir kochen und essen gemeinschaftlich. So kommt jeder an die Reihe und sollte entsprechend etwas parat haben. Jeder Koch verfügt über eine beliebige Anzahl an Hilfssklaven. Urbanen Legenden zufolge sollen schlechte Köche früher häufiger mal über Bord gegangen sein. Zudem verhindern satte Beuche Aufstände bereits im Keim!&lt;br /&gt;
&lt;br /&gt;
Hauptmahlzeiten&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Koch&lt;br /&gt;
!Speise&lt;br /&gt;
!Benötigte Zutaten&lt;br /&gt;
|-&lt;br /&gt;
|Flow&lt;br /&gt;
|Köttbullar&lt;br /&gt;
|http://www.lecker.de/schwedische-rezepte-49945.html&lt;br /&gt;
|-&lt;br /&gt;
|Flash&lt;br /&gt;
|Franz. Spektorte (LowCarb/Carb)&lt;br /&gt;
|http://www.chefkoch.de/rezepte/1635271271083105/Franzoesischer-Schinkenkuchen.html&lt;br /&gt;
Zutaten p.P. lowCarb (Füllung only):&lt;br /&gt;
* 150g Schinken&lt;br /&gt;
* 150g Käse&lt;br /&gt;
* 150ml saure Sahne&lt;br /&gt;
* 3Eier&lt;br /&gt;
* Salz, Pfeffer, Weißwein, Chili etc nach Geschmack&lt;br /&gt;
|-&lt;br /&gt;
|Alle&lt;br /&gt;
|Grillen&lt;br /&gt;
|Steak, Würste, Speck, Garnelen, (Lottencreme - rezept wird ermittelt)&lt;br /&gt;
|-&lt;br /&gt;
|Pixelschubser&lt;br /&gt;
|Lasagne&lt;br /&gt;
|Folgt&lt;br /&gt;
|-&lt;br /&gt;
|Thomas&lt;br /&gt;
|Spinat(selbstgemacht), Kartoffeln und Ei&lt;br /&gt;
|REZEPT/ZUTATEN&lt;br /&gt;
|-&lt;br /&gt;
|Thomas&lt;br /&gt;
|Schupfnudeln , wurst käse überbacken&lt;br /&gt;
|Rezept&lt;br /&gt;
|-&lt;br /&gt;
|WER&lt;br /&gt;
|WAS&lt;br /&gt;
|REZEPT/ZUTATEN&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Zwischenmahlzeiten / Snacks&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Koch&lt;br /&gt;
!Speise&lt;br /&gt;
!Benötigte Zutaten&lt;br /&gt;
|-&lt;br /&gt;
|Flow&lt;br /&gt;
|Surströmming&lt;br /&gt;
|Surströmming&lt;br /&gt;
|-&lt;br /&gt;
|Flow&lt;br /&gt;
|Strammer Max&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Einkaufsliste==&lt;br /&gt;
&lt;br /&gt;
Alt aus Dänemark und nur als Orientierung drin:&lt;br /&gt;
----Frühstück-----&lt;br /&gt;
*100 Eier&lt;br /&gt;
*3kg Bacon&lt;br /&gt;
*14kg Müsli&lt;br /&gt;
*40l H-Milch&lt;br /&gt;
*100 Aufback-Brötchen (ohne Kühlung!)&lt;br /&gt;
*8 Aufback-Baguettes (ohne Kühlung!)&lt;br /&gt;
*8kg Käse &amp;amp; Wurst&lt;br /&gt;
*8 Marmeladen&lt;br /&gt;
*4 Butter&lt;br /&gt;
*60l Orangensaft&lt;br /&gt;
*20 Packungen Quark&lt;br /&gt;
*300gr Speck&lt;br /&gt;
----Obst------&lt;br /&gt;
*10kg Äpfel&lt;br /&gt;
*2kg Birnen&lt;br /&gt;
*2kg Pfirsiche,&lt;br /&gt;
*2 große Wassermelonen&lt;br /&gt;
*4 Honigmelonen (Zergeneier ^^)&lt;br /&gt;
*2kg Kiwis&lt;br /&gt;
*5kg Tomaten&lt;br /&gt;
*2kg Paprika&lt;br /&gt;
*4 Gurken&lt;br /&gt;
*2kg Zwiebeln&lt;br /&gt;
*2-3 Salate (Haltbarkeit :()&lt;br /&gt;
*6kg Kartoffeln&lt;br /&gt;
----Abgepacktes----&lt;br /&gt;
*4 Dosen Mais&lt;br /&gt;
*2 Dosen Thunfisch&lt;br /&gt;
*1kg TK-Spinat&lt;br /&gt;
*8 Pack Schafskäse&lt;br /&gt;
*4kg Pizzakäse&lt;br /&gt;
*2kg Gouda&lt;br /&gt;
*5 Dosen Tomaten&lt;br /&gt;
*5 Dosen Bohnen&lt;br /&gt;
*3kg Mehl (550)&lt;br /&gt;
*3 Pack Frischhefe&lt;br /&gt;
*Rinderbrühe&lt;br /&gt;
*3 Packungen Sauerkraut&lt;br /&gt;
*1 Glas eingelegte Gurken&lt;br /&gt;
----Knapperkram---&lt;br /&gt;
*30 diverse Chipstüten&lt;br /&gt;
*6kg Nussmischungen&lt;br /&gt;
----Cocktails-----&lt;br /&gt;
*1 Flasche Havana Club&lt;br /&gt;
*2 Flaschen Wodka&lt;br /&gt;
*4l Ananassaft&lt;br /&gt;
*4l Grapefruitsaft&lt;br /&gt;
*8l Marakuja Saft&lt;br /&gt;
*Zuckersirup&lt;br /&gt;
----Sonstiges----&lt;br /&gt;
*Toilettenpapier (1 Großpack)&lt;br /&gt;
*Küchenpapier&lt;br /&gt;
*Müllbeutel &amp;gt;30l&lt;br /&gt;
*Waschmittel&lt;br /&gt;
*Backpapier&lt;br /&gt;
*1 Pack Zucker&lt;br /&gt;
*Salz&lt;br /&gt;
*Körniges Salz&lt;br /&gt;
*Pfeffer&lt;br /&gt;
*2l Olivenöl&lt;br /&gt;
*1l Essig&lt;br /&gt;
*Grillkohle&lt;br /&gt;
*Grillanzünder &amp;amp; Feuerzeug&lt;br /&gt;
*Alufolie&lt;br /&gt;
----Fleisch------&lt;br /&gt;
*2kg Fleisch zum Grillen&lt;br /&gt;
*2kg Kassler&lt;br /&gt;
*1kg geräucherte Mettenden&lt;br /&gt;
*2kg Hähnchenbrust&lt;br /&gt;
*48 Hotdogwürstchen&lt;br /&gt;
*24 Hotdogbrötchen&lt;br /&gt;
*Remouladensoße&lt;br /&gt;
*Diverse Grillsoßen&lt;br /&gt;
*Geröstete Zwiebeln&lt;br /&gt;
*Ketchup&lt;br /&gt;
*Senf&lt;br /&gt;
-----Onigiri----&lt;br /&gt;
*Sushireis&lt;br /&gt;
*Sushi-Essig&lt;br /&gt;
*Nori&lt;br /&gt;
----Ends patentierte Pfannkuchen----&lt;br /&gt;
1x Pfannkuchen fuer alle =&lt;br /&gt;
*10 Eier&lt;br /&gt;
*1kg Mehl&lt;br /&gt;
*1 Liter Milch&lt;br /&gt;
*1 Mixer&lt;br /&gt;
*1 bis 2kg Zucker&lt;br /&gt;
*eine Prise Salz&lt;br /&gt;
&lt;br /&gt;
Wahlweise kann Mehl durch Zucker jeder Sorte oder Muesli substituiert werden&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2016/Organisation&amp;diff=26333</id>
		<title>DGL Treffen/2016/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2016/Organisation&amp;diff=26333"/>
				<updated>2016-05-23T21:26:40Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Für den August 2016 planen wir wieder ein DGL Treffen. Diesmal geht es für 2 Wochen an die Küste von Dänemark.&lt;br /&gt;
&lt;br /&gt;
;Thema: &amp;quot;Nerds On Tour.&amp;quot; ;-)&lt;br /&gt;
&lt;br /&gt;
Weitere Infos und detaillierte Besprechungen finden in [https://delphigl.com/forum/viewtopic.php?f=4&amp;amp;p=100328#p100328 diesem Forenthread] statt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Wo?==&lt;br /&gt;
Wird noch im Thread diskutiert.&lt;br /&gt;
&lt;br /&gt;
==Wann?==&lt;br /&gt;
*Anreise: Sa. 06.08.2016&lt;br /&gt;
*Abreise: Sa. 20.08.2016&lt;br /&gt;
&lt;br /&gt;
==Was kostet das?==&lt;br /&gt;
Je besser die Auslastung des Hauses, desto besser. Die Preise werden im gewohnten Rahmen bleiben.&lt;br /&gt;
Verpflegung und Anreise sind da aber nicht mit dabei. Die Verpflegung erfolgt üblicherweise über eine Umlage und wir holen uns gemeinsam etwas. Sollte jemand aus Kostengründen nicht teilnehmen können, kann er sich per Mail an Phobeus wenden.&lt;br /&gt;
&lt;br /&gt;
==Wer kommt mit?==&lt;br /&gt;
Hier eine vorläufige Teilnehmerliste. Es sind insgesamt 8 Betten im Haus.&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Teilnehmer&lt;br /&gt;
!Tage&lt;br /&gt;
(14=max)&lt;br /&gt;
!Anreise&lt;br /&gt;
!Kommentar&lt;br /&gt;
|-&lt;br /&gt;
|Phobeus&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(1,5 Plätze im PKW frei ab Hamburg.)&lt;br /&gt;
|-&lt;br /&gt;
|i0n0s&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(1 Platz im PKW frei ab Gießen.)&lt;br /&gt;
|-&lt;br /&gt;
|Polarwolf&lt;br /&gt;
|14&lt;br /&gt;
|PKW&lt;br /&gt;
|(1 Platz im PKW frei ab Hamburg.)&lt;br /&gt;
|-&lt;br /&gt;
|Seraliel&lt;br /&gt;
|2.5&lt;br /&gt;
|PKW &lt;br /&gt;
|(1 Platz frei ab Hamburg. Am Fr.12.8)&lt;br /&gt;
|-&lt;br /&gt;
|Flash&lt;br /&gt;
|14&lt;br /&gt;
|PKW&lt;br /&gt;
|3 Plätze ab Chemnitz (via Leipzig, Hannover) &lt;br /&gt;
|-&lt;br /&gt;
|TAK2004&lt;br /&gt;
|14&lt;br /&gt;
|&lt;br /&gt;
|Braucht ein Platz ab Berlin. &lt;br /&gt;
|-&lt;br /&gt;
|Mr Frase&lt;br /&gt;
|14&lt;br /&gt;
|--- &lt;br /&gt;
|---&lt;br /&gt;
|-&lt;br /&gt;
|Ms Frase&lt;br /&gt;
|14&lt;br /&gt;
|--- &lt;br /&gt;
|---&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Wie kommt man hin?==&lt;br /&gt;
Die Anreise steht noch nicht fest. Treffpunkt wird vor Hamburg sein, dort besteht die Möglichkeit die PKWs stehen zu lassen und sich besser auf die Wagen zu verteilen. Eine Anreise zum Bahnhof HH lässt sich ebenfalls organisieren. Fahrgemeinschaften bitte so früh wie möglich bilden!&lt;br /&gt;
&lt;br /&gt;
==Was muss man mitbringen?==&lt;br /&gt;
* Bargeld (Kaution ''(siehe Forum)'' + Reisekasse)&lt;br /&gt;
* Bettwäsche und Handtücher (1 Set kostet vor Ort 13Euro)&lt;br /&gt;
* Wechsel-Kleidung&lt;br /&gt;
* Nahrungsmittel&lt;br /&gt;
* Reisedokumente (Führerschein, Personalausweis, Versicherungs und Geldkarten)&lt;br /&gt;
* Reiseapotheke&lt;br /&gt;
* Hygieneartikel &lt;br /&gt;
* Klopapier&lt;br /&gt;
* Badesachen (inkl. Sonnencreme)&lt;br /&gt;
* Küchenequipement (Gewürze, Dosenöffner/Korkenzieher/Flaschenöffner, Kaffeefilter, Geschirrtücher, Wischtücher, Küchenrolle, Spülmittel)&lt;br /&gt;
* Elektronik (1 Router, Laptop, Netzwerkkabel, Fotoapparat)&lt;br /&gt;
* Sonstiges (was zu lesen, Schreibzeug etc.)&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu erleben?==&lt;br /&gt;
*DGLer in echt ;)&lt;br /&gt;
*Baden und Grillen&lt;br /&gt;
*Eine Minni-LAN&lt;br /&gt;
*Live Projektvorstellung&lt;br /&gt;
*Däninnen *hust* ;)&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu essen?==&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Koch&lt;br /&gt;
!Speise&lt;br /&gt;
!Benötigte Zutaten&lt;br /&gt;
|-&lt;br /&gt;
|Thomas&lt;br /&gt;
|Pitataschen&lt;br /&gt;
|Tomaten, Paprika, Mais, Schafskäsen, Gurken, Tunfisch, Hänchenbrust, Pitataschen, Salami, Schinken, Gouda, Pfanne+Herd/Ofen/Toaster&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2016/Organisation&amp;diff=26329</id>
		<title>DGL Treffen/2016/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2016/Organisation&amp;diff=26329"/>
				<updated>2016-05-17T10:55:07Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Für den August 2016 planen wir wieder ein DGL Treffen. Diesmal geht es für 2 Wochen an die Küste von Dänemark.&lt;br /&gt;
&lt;br /&gt;
;Thema: &amp;quot;Nerds On Tour.&amp;quot; ;-)&lt;br /&gt;
&lt;br /&gt;
Weitere Infos und detaillierte Besprechungen finden in [https://delphigl.com/forum/viewtopic.php?f=4&amp;amp;p=100328#p100328 diesem Forenthread] statt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Wo?==&lt;br /&gt;
Wird noch im Thread diskutiert.&lt;br /&gt;
&lt;br /&gt;
==Wann?==&lt;br /&gt;
*Anreise: Sa. 06.08.2016&lt;br /&gt;
*Abreise: Sa. 20.08.2016&lt;br /&gt;
&lt;br /&gt;
==Was kostet das?==&lt;br /&gt;
Je besser die Auslastung des Hauses, desto besser. Die Preise werden im gewohnten Rahmen bleiben.&lt;br /&gt;
Verpflegung und Anreise sind da aber nicht mit dabei. Die Verpflegung erfolgt üblicherweise über eine Umlage und wir holen uns gemeinsam etwas. Sollte jemand aus Kostengründen nicht teilnehmen können, kann er sich per Mail an Phobeus wenden.&lt;br /&gt;
&lt;br /&gt;
==Wer kommt mit?==&lt;br /&gt;
Hier eine vorläufige Teilnehmerliste. Es sind insgesamt 8 Betten im Haus.&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Teilnehmer&lt;br /&gt;
!Tage&lt;br /&gt;
(14=max)&lt;br /&gt;
!Anreise&lt;br /&gt;
!Kommentar&lt;br /&gt;
|-&lt;br /&gt;
|Phobeus&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(1,5 Plätze im PKW frei ab Hamburg.)&lt;br /&gt;
|-&lt;br /&gt;
|i0n0s&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(1 Platz im PKW frei ab Gießen.)&lt;br /&gt;
|-&lt;br /&gt;
|Polarwolf&lt;br /&gt;
|14&lt;br /&gt;
|PKW&lt;br /&gt;
|(1 Platz im PKW frei ab Hamburg.)&lt;br /&gt;
|-&lt;br /&gt;
|Seraliel&lt;br /&gt;
|2.5&lt;br /&gt;
|PKW &lt;br /&gt;
|(1 Platz frei ab Hamburg. Am Fr.12.8)&lt;br /&gt;
|-&lt;br /&gt;
|Flash&lt;br /&gt;
|14&lt;br /&gt;
|PKW&lt;br /&gt;
|3 Plätze ab Chemnitz (via Leipzig oder Dresden, Berlin) &lt;br /&gt;
|-&lt;br /&gt;
|TAK2004&lt;br /&gt;
|14&lt;br /&gt;
|&lt;br /&gt;
|Braucht ein Platz ab Berlin. &lt;br /&gt;
|-&lt;br /&gt;
|Du&lt;br /&gt;
|14&lt;br /&gt;
|--- &lt;br /&gt;
|---&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Wie kommt man hin?==&lt;br /&gt;
Die Anreise steht noch nicht fest. Treffpunkt wird vor Hamburg sein, dort besteht die Möglichkeit die PKWs stehen zu lassen und sich besser auf die Wagen zu verteilen. Eine Anreise zum Bahnhof HH lässt sich ebenfalls organisieren. Fahrgemeinschaften bitte so früh wie möglich bilden!&lt;br /&gt;
&lt;br /&gt;
==Was muss man mitbringen?==&lt;br /&gt;
* Bargeld (Kaution ''(siehe Forum)'' + Reisekasse)&lt;br /&gt;
* Bettwäsche und Handtücher (1 Set kostet vor Ort 13Euro)&lt;br /&gt;
* Wechsel-Kleidung&lt;br /&gt;
* Nahrungsmittel&lt;br /&gt;
* Reisedokumente (Führerschein, Personalausweis, Versicherungs und Geldkarten)&lt;br /&gt;
* Reiseapotheke&lt;br /&gt;
* Hygieneartikel &lt;br /&gt;
* Klopapier&lt;br /&gt;
* Badesachen (inkl. Sonnencreme)&lt;br /&gt;
* Küchenequipement (Gewürze, Dosenöffner/Korkenzieher/Flaschenöffner, Kaffeefilter, Geschirrtücher, Wischtücher, Küchenrolle, Spülmittel)&lt;br /&gt;
* Elektronik (1 Router, Laptop, Netzwerkkabel, Fotoapparat)&lt;br /&gt;
* Sonstiges (was zu lesen, Schreibzeug etc.)&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu erleben?==&lt;br /&gt;
*DGLer in echt ;)&lt;br /&gt;
*Baden und Grillen&lt;br /&gt;
*Eine Minni-LAN&lt;br /&gt;
*Live Projektvorstellung&lt;br /&gt;
*Däninnen *hust* ;)&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2016/Organisation&amp;diff=26328</id>
		<title>DGL Treffen/2016/Organisation</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2016/Organisation&amp;diff=26328"/>
				<updated>2016-05-17T10:54:42Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Für den August 2016 planen wir wieder ein DGL Treffen. Diesmal geht es für 2 Wochen an die Küste von Dänemark.&lt;br /&gt;
&lt;br /&gt;
;Thema: &amp;quot;Nerds On Tour.&amp;quot; ;-)&lt;br /&gt;
&lt;br /&gt;
Weitere Infos und detaillierte Besprechungen finden in [https://delphigl.com/forum/viewtopic.php?f=4&amp;amp;p=100328#p100328 diesem Forenthread] statt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Wo?==&lt;br /&gt;
Wird noch im Thread diskutiert.&lt;br /&gt;
&lt;br /&gt;
==Wann?==&lt;br /&gt;
*Anreise: Sa. 06.08.2016&lt;br /&gt;
*Abreise: Sa. 20.08.2016&lt;br /&gt;
&lt;br /&gt;
==Was kostet das?==&lt;br /&gt;
Je besser die Auslastung des Hauses, desto besser. Die Preise werden im gewohnten Rahmen bleiben.&lt;br /&gt;
Verpflegung und Anreise sind da aber nicht mit dabei. Die Verpflegung erfolgt üblicherweise über eine Umlage und wir holen uns gemeinsam etwas. Sollte jemand aus Kostengründen nicht teilnehmen können, kann er sich per Mail an Phobeus wenden.&lt;br /&gt;
&lt;br /&gt;
==Wer kommt mit?==&lt;br /&gt;
Hier eine vorläufige Teilnehmerliste. Es sind insgesamt 8 Betten im Haus.&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Teilnehmer&lt;br /&gt;
!Tage&lt;br /&gt;
(14=max)&lt;br /&gt;
!Anreise&lt;br /&gt;
!Kommentar&lt;br /&gt;
|-&lt;br /&gt;
|Phobeus&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(1,5 Plätze im PKW frei ab Hamburg.)&lt;br /&gt;
|-&lt;br /&gt;
|i0n0s&lt;br /&gt;
|14&lt;br /&gt;
|PKW &lt;br /&gt;
|(1 Platz im PKW frei ab Gießen.)&lt;br /&gt;
|-&lt;br /&gt;
|Polarwolf&lt;br /&gt;
|14&lt;br /&gt;
|PKW&lt;br /&gt;
|(1 Platz im PKW frei ab Hamburg.)&lt;br /&gt;
|-&lt;br /&gt;
|Seraliel&lt;br /&gt;
|2.5&lt;br /&gt;
|PKW &lt;br /&gt;
|(1 Platz frei ab Hamburg. Am Fr.12.8)&lt;br /&gt;
|-&lt;br /&gt;
|Flash&lt;br /&gt;
|14&lt;br /&gt;
|PKW&lt;br /&gt;
|3 Plätze ab Chemnitz (via Leipzig oder Dresden, Berlin) &lt;br /&gt;
|-&lt;br /&gt;
|TAK2004&lt;br /&gt;
|14&lt;br /&gt;
|-&lt;br /&gt;
|Braucht ein Platz ab Berlin. &lt;br /&gt;
|-&lt;br /&gt;
|Du&lt;br /&gt;
|14&lt;br /&gt;
|--- &lt;br /&gt;
|---&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Wie kommt man hin?==&lt;br /&gt;
Die Anreise steht noch nicht fest. Treffpunkt wird vor Hamburg sein, dort besteht die Möglichkeit die PKWs stehen zu lassen und sich besser auf die Wagen zu verteilen. Eine Anreise zum Bahnhof HH lässt sich ebenfalls organisieren. Fahrgemeinschaften bitte so früh wie möglich bilden!&lt;br /&gt;
&lt;br /&gt;
==Was muss man mitbringen?==&lt;br /&gt;
* Bargeld (Kaution ''(siehe Forum)'' + Reisekasse)&lt;br /&gt;
* Bettwäsche und Handtücher (1 Set kostet vor Ort 13Euro)&lt;br /&gt;
* Wechsel-Kleidung&lt;br /&gt;
* Nahrungsmittel&lt;br /&gt;
* Reisedokumente (Führerschein, Personalausweis, Versicherungs und Geldkarten)&lt;br /&gt;
* Reiseapotheke&lt;br /&gt;
* Hygieneartikel &lt;br /&gt;
* Klopapier&lt;br /&gt;
* Badesachen (inkl. Sonnencreme)&lt;br /&gt;
* Küchenequipement (Gewürze, Dosenöffner/Korkenzieher/Flaschenöffner, Kaffeefilter, Geschirrtücher, Wischtücher, Küchenrolle, Spülmittel)&lt;br /&gt;
* Elektronik (1 Router, Laptop, Netzwerkkabel, Fotoapparat)&lt;br /&gt;
* Sonstiges (was zu lesen, Schreibzeug etc.)&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu erleben?==&lt;br /&gt;
*DGLer in echt ;)&lt;br /&gt;
*Baden und Grillen&lt;br /&gt;
*Eine Minni-LAN&lt;br /&gt;
*Live Projektvorstellung&lt;br /&gt;
*Däninnen *hust* ;)&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2014/OrganisationERZ&amp;diff=26283</id>
		<title>DGL Treffen/2014/OrganisationERZ</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2014/OrganisationERZ&amp;diff=26283"/>
				<updated>2014-11-24T22:13:16Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In MeckPom wurde von Polarwolf und Seraliel vorgeschlagen, etwas für den Winter zu planen. Flash schlug seine Heimat - das Erzgebirge vor.&lt;br /&gt;
&lt;br /&gt;
Weitere Infos und detaillierte Besprechungen finden in [http://delphigl.com/forum/viewtopic.php?f=4&amp;amp;t=11192&amp;amp;start=0 diesem Forenthread] statt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Wo?==&lt;br /&gt;
'''Erzgebirge'''&amp;lt;br&amp;gt;&lt;br /&gt;
[http://booking.com/3acd56747484d Ferienwohnungen], &amp;lt;br&amp;gt;&lt;br /&gt;
Hotel Arena &amp;lt;br&amp;gt;&lt;br /&gt;
Mostecka ulice 5900, &amp;lt;br&amp;gt;&lt;br /&gt;
Chomutov, 43001, &amp;lt;br&amp;gt;&lt;br /&gt;
Tschechische Republik&lt;br /&gt;
&lt;br /&gt;
==Wann?==&lt;br /&gt;
*Anreise: Fr 26.12.2014&lt;br /&gt;
*Abreise: So 04.01.2015&lt;br /&gt;
&lt;br /&gt;
==Was kostet das?==&lt;br /&gt;
Für die Übernachter ca 25Eur pro Nacht plus Nahrung.&lt;br /&gt;
Für Ausflüge, (Ski) ca. 20Eur&lt;br /&gt;
Die Anreise ist, wie üblich, von den Teilnehmern zu tragen. Allerdings versuchen wir natürlich beides zu optimieren d.h. Fahrgemeinschaften auf den Fahrten und Gemeinschaftskasse bei der Verpflegung.&lt;br /&gt;
&lt;br /&gt;
==Wer kommt mit?==&lt;br /&gt;
Hier eine vorläufige Teilnehmerliste. Anzahl Betten und Schlafzimmer noch offen.&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Teilnehmer&lt;br /&gt;
!Fest&lt;br /&gt;
!Tage&lt;br /&gt;
(9=max)&lt;br /&gt;
!Anreise&lt;br /&gt;
!Kommentar&lt;br /&gt;
|-&lt;br /&gt;
|Flash&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW ab Chemnitz &lt;br /&gt;
|(3 Plätze im PKW frei.)&lt;br /&gt;
|-&lt;br /&gt;
|i0n0s&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW ab Gießen&lt;br /&gt;
|(1 Platz im PKW frei.)&lt;br /&gt;
|-&lt;br /&gt;
|Phobeus&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW ab Hamburg&lt;br /&gt;
|(3 Plätze im PKW frei.)&lt;br /&gt;
|-&lt;br /&gt;
|Polarwolf&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW ab Bad Salzung, rückzu nach Hamburg&lt;br /&gt;
| (2 *Notplätze* im Fox frei)&lt;br /&gt;
|-&lt;br /&gt;
|Seraliel&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
| Mit Polarwolf&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|''frei''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Bergmann&lt;br /&gt;
''frei''&lt;br /&gt;
|X&lt;br /&gt;
.&lt;br /&gt;
|2 (27.12.-29.12.)&lt;br /&gt;
7 (29.12.-04.01)&lt;br /&gt;
|PWK ab Schmölln (bei Altenburg)&lt;br /&gt;
|(2 Plätze im PKW frei)&lt;br /&gt;
|-&lt;br /&gt;
|''frei''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;6&amp;quot;|Gäste (ohne Übernachtung)&lt;br /&gt;
|-&lt;br /&gt;
|''frei''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|''frei''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Wie kommt man hin?==&lt;br /&gt;
Auto oder Bahn.&lt;br /&gt;
'''Treffpunkt ist Chemnitz. Zeitpunkt: 15:00Uhr'''&lt;br /&gt;
&lt;br /&gt;
Von dort aus geht's Richtung Zielort in Kolonne. Die Anfahrt wird bereits mit einem kleinen Rahmenprogramm versehen...&lt;br /&gt;
&lt;br /&gt;
== Sonstiges Organisatorisches ==&lt;br /&gt;
In jedem Fall sollte jeder Mitfahrer eigenständig Kontakt mit mindestens seinem Fahrer aufnehmen und die genaue Anreise klären. Handynummer können an Phobeus geschickt werden. Jeder der seine Nummer preisgibt, erhält die Nummern der jeweilig Anderen. Sofern also niemand damit bedenken hat, sollte davon gebrauch machen. Das letzte Mal hatten lediglich die Fahrer die Nummern untereinander, was unglücklich ist, da gerade diese am Steuer sitzen ;)&lt;br /&gt;
&lt;br /&gt;
==Was muss man mitbringen?==&lt;br /&gt;
===1x für Alle===&lt;br /&gt;
* Tapeziertisch(!) (Flash erinnern, falls er das vergessen hat!)&lt;br /&gt;
* Küchenequipement (Gewürze, Dosenöffner/Korkenzieher/Flaschenöffner, Kaffeefilter, Geschirrtücher, Wischtücher, Küchenrolle, Spülmittel)&lt;br /&gt;
* Klopapier&lt;br /&gt;
* 1 Router&lt;br /&gt;
* Netzwerkkabel (1x für alle? Ich weiß ja net... *g*)&lt;br /&gt;
* Was W-Lan Router mäßiges wäre suuuuper! Ist aber kein muss&lt;br /&gt;
* Cocktail Zeug! (Flash erinnern, falls er das vergessen hat!)&lt;br /&gt;
&lt;br /&gt;
===Jeder===&lt;br /&gt;
* Ski-Ausrüstung falls vorhanden.&lt;br /&gt;
* Das [[DGL Shirt]] - wer eins hat!&lt;br /&gt;
* Bargeld (Kaution (siehe Forum) + Reisekasse)&lt;br /&gt;
* Reisedokumente (Führerschein, Personalausweis, Versicherungs und Geldkarten)&lt;br /&gt;
* Reiseapotheke&lt;br /&gt;
* Hygieneartikel&lt;br /&gt;
* Warme Sachen (Schneetauglich)&lt;br /&gt;
* Badesachen!&lt;br /&gt;
* Elektronik (Laptop, Fotoapparat, Tanzmatten, MEHRFACHSTECKDOSEN!)&lt;br /&gt;
* Sonstiges (was zu lesen, Schreibzeug etc.) &lt;br /&gt;
''zu klären''&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu erleben?==&lt;br /&gt;
*DGLer in echt ;)&lt;br /&gt;
*Ski&lt;br /&gt;
*Eine Minni-LAN&lt;br /&gt;
*Videoabende&lt;br /&gt;
*Live Projektvorstellung&lt;br /&gt;
*Umgebung erkunden&lt;br /&gt;
&lt;br /&gt;
==Nahrungsmittel==&lt;br /&gt;
*Die ersten Tag werden wir wohl die Restaurants vor Ort nutzen müssen (Feiertag). Danach schauen wir, ob wir eine Kochmöglichkeit haben.&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DGL_Treffen/2014/OrganisationERZ&amp;diff=26278</id>
		<title>DGL Treffen/2014/OrganisationERZ</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DGL_Treffen/2014/OrganisationERZ&amp;diff=26278"/>
				<updated>2014-11-18T19:20:53Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In MeckPom wurde von Polarwolf und Seraliel vorgeschlagen, etwas für den Winter zu planen. Flash schlug seine Heimat - das Erzgebirge vor.&lt;br /&gt;
&lt;br /&gt;
Weitere Infos und detaillierte Besprechungen finden in [http://delphigl.com/forum/viewtopic.php?f=4&amp;amp;t=11192&amp;amp;start=0 diesem Forenthread] statt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Wo?==&lt;br /&gt;
'''Erzgebirge'''&amp;lt;br&amp;gt;&lt;br /&gt;
[http://booking.com/3acd56747484d Ferienwohnungen], &amp;lt;br&amp;gt;&lt;br /&gt;
Hotel Arena &amp;lt;br&amp;gt;&lt;br /&gt;
Mostecka ulice 5900, &amp;lt;br&amp;gt;&lt;br /&gt;
Chomutov, 43001, &amp;lt;br&amp;gt;&lt;br /&gt;
Tschechische Republik&lt;br /&gt;
&lt;br /&gt;
==Wann?==&lt;br /&gt;
*Anreise: Fr 26.12.2014&lt;br /&gt;
*Abreise: So 04.01.2015&lt;br /&gt;
&lt;br /&gt;
==Was kostet das?==&lt;br /&gt;
Für die Übernachter ca 25Eur pro Nacht plus Nahrung.&lt;br /&gt;
Für Ausflüge, (Ski) ca. 20Eur&lt;br /&gt;
Die Anreise ist, wie üblich, von den Teilnehmern zu tragen. Allerdings versuchen wir natürlich beides zu optimieren d.h. Fahrgemeinschaften auf den Fahrten und Gemeinschaftskasse bei der Verpflegung.&lt;br /&gt;
&lt;br /&gt;
==Wer kommt mit?==&lt;br /&gt;
Hier eine vorläufige Teilnehmerliste. Anzahl Betten und Schlafzimmer noch offen.&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!Teilnehmer&lt;br /&gt;
!Fest&lt;br /&gt;
!Tage&lt;br /&gt;
(9=max)&lt;br /&gt;
!Anreise&lt;br /&gt;
!Kommentar&lt;br /&gt;
|-&lt;br /&gt;
|Flash&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW ab Chemnitz &lt;br /&gt;
|(3 Plätze im PKW frei.)&lt;br /&gt;
|-&lt;br /&gt;
|i0n0s&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW ab Gießen&lt;br /&gt;
|(1 Platz im PKW frei.)&lt;br /&gt;
|-&lt;br /&gt;
|Phobeus&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW ab Hamburg&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Polarwolf&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|PKW? ab Hamburg&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|Seraliel&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
| Mit Polarwolf&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|TAK2004&lt;br /&gt;
|X&lt;br /&gt;
|9&lt;br /&gt;
|von Berlin&lt;br /&gt;
|Kein Plan wie ich hin kommen soll ^^&lt;br /&gt;
|-&lt;br /&gt;
|Bergmann&lt;br /&gt;
''frei''&lt;br /&gt;
|X&lt;br /&gt;
.&lt;br /&gt;
|2 (27.12.-29.12.)&lt;br /&gt;
7 (29.12.-04.01)&lt;br /&gt;
|PWK ab Schmölln (bei Altenburg)&lt;br /&gt;
|(2 Plätze im PKW frei)&lt;br /&gt;
|-&lt;br /&gt;
|''frei''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
!colspan=&amp;quot;6&amp;quot;|Gäste (ohne Übernachtung)&lt;br /&gt;
|-&lt;br /&gt;
|''frei''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|''frei''&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Wie kommt man hin?==&lt;br /&gt;
Auto oder Bahn.&lt;br /&gt;
'''Treffpunkt ist Chemnitz. Zeitpunkt: 15:00Uhr'''&lt;br /&gt;
&lt;br /&gt;
Von dort aus geht's Richtung Zielort in Kolonne. Die Anfahrt wird bereits mit einem kleinen Rahmenprogramm versehen...&lt;br /&gt;
&lt;br /&gt;
== Sonstiges Organisatorisches ==&lt;br /&gt;
In jedem Fall sollte jeder Mitfahrer eigenständig Kontakt mit mindestens seinem Fahrer aufnehmen und die genaue Anreise klären. Handynummer können an Phobeus geschickt werden. Jeder der seine Nummer preisgibt, erhält die Nummern der jeweilig Anderen. Sofern also niemand damit bedenken hat, sollte davon gebrauch machen. Das letzte Mal hatten lediglich die Fahrer die Nummern untereinander, was unglücklich ist, da gerade diese am Steuer sitzen ;)&lt;br /&gt;
&lt;br /&gt;
==Was muss man mitbringen?==&lt;br /&gt;
===1x für Alle===&lt;br /&gt;
* Tapeziertisch(!) (Flash erinnern, falls er das vergessen hat!)&lt;br /&gt;
* Küchenequipement (Gewürze, Dosenöffner/Korkenzieher/Flaschenöffner, Kaffeefilter, Geschirrtücher, Wischtücher, Küchenrolle, Spülmittel)&lt;br /&gt;
* Klopapier&lt;br /&gt;
* 1 Router&lt;br /&gt;
* Netzwerkkabel (1x für alle? Ich weiß ja net... *g*)&lt;br /&gt;
* Was W-Lan Router mäßiges wäre suuuuper! Ist aber kein muss&lt;br /&gt;
* Cocktail Zeug! (Flash erinnern, falls er das vergessen hat!)&lt;br /&gt;
&lt;br /&gt;
===Jeder===&lt;br /&gt;
* Ski-Ausrüstung falls vorhanden.&lt;br /&gt;
* Das [[DGL Shirt]] - wer eins hat!&lt;br /&gt;
* Bargeld (Kaution (siehe Forum) + Reisekasse)&lt;br /&gt;
* Reisedokumente (Führerschein, Personalausweis, Versicherungs und Geldkarten)&lt;br /&gt;
* Reiseapotheke&lt;br /&gt;
* Hygieneartikel&lt;br /&gt;
* Warme Sachen (Schneetauglich)&lt;br /&gt;
* Badesachen!&lt;br /&gt;
* Elektronik (Laptop, Fotoapparat, Tanzmatten, MEHRFACHSTECKDOSEN!)&lt;br /&gt;
* Sonstiges (was zu lesen, Schreibzeug etc.) &lt;br /&gt;
''zu klären''&lt;br /&gt;
&lt;br /&gt;
==Was gibts zu erleben?==&lt;br /&gt;
*DGLer in echt ;)&lt;br /&gt;
*Ski&lt;br /&gt;
*Eine Minni-LAN&lt;br /&gt;
*Videoabende&lt;br /&gt;
*Live Projektvorstellung&lt;br /&gt;
*Umgebung erkunden&lt;br /&gt;
&lt;br /&gt;
==Nahrungsmittel==&lt;br /&gt;
*Die ersten Tag werden wir wohl die Restaurants vor Ort nutzen müssen (Feiertag). Danach schauen wir, ob wir eine Kochmöglichkeit haben.&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=26257</id>
		<title>Techniken und Algorithmen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=26257"/>
				<updated>2014-06-08T13:22:22Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Nützliche Helfer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Artikel dieses Wiki-Abschnittes sind im Gegensatz zu den [[Tutorial]]s meist kürzer. Dafür enthalten sie mitunter sehr viel Code der direkt verwendet werden, oder als Grundlage für die eigene Arbeit dienen kann.&lt;br /&gt;
&lt;br /&gt;
== Was hier hinein gehört ==&lt;br /&gt;
Hier kommen, wie der Name vermuten lässt, '''Erklärungen''' zu in der 3D-Echtzeitprogrammierung verwendeten '''Techniken''' hin. Z.B. verschiedene Schattentechniken, Bump-Mapping, etc.&lt;br /&gt;
&lt;br /&gt;
[[Hintergrundwissen]] gehört hier nicht rein. Sachen wie ''&amp;quot;was ist ein Tiefenpuffer und wofür ist er gut&amp;quot;'' haben hier nichts zu suchen.&amp;lt;br&amp;gt;&lt;br /&gt;
Sollte es für eine Technik/Thematik (siehe unten für Beispiel) mehrere &amp;quot;Lösungswege&amp;quot; geben, sollte eine kleine Überschrift eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr einen Technik- oder Algorithmus-Artikel erstellt, so solltet ihr unter den Artikel ein&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[Kategorie:Technik_oder_Algorithmus]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
stellen. Damit wird der Artikel der  [[:Kategorie:Technik_oder_Algorithmus]] zugeordnet.&lt;br /&gt;
Falls dieser Artikel nicht nur erklärt, was der Begriff bedeutet, sondern auch noch eine Anleitung ist, wie man die entsprechende Technik realisiert, so könnt ihr den Artikel auch noch der Kategorie [[:Kategorie:Anleitung|Anleitung]] zuweisen.&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
=== Sammlungen ===&lt;br /&gt;
* [[Materialsammlung]] (Enthält Materialien für [[glMaterial]].)&lt;br /&gt;
* [[Shadersammlung]] (Enthält Shader.)&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Helfer ===&lt;br /&gt;
In dieser Rubrik findet sich all das, was ein OpenGL/Graphikprogrammierer immer brauch oder schnell mal zur Hand haben muss:&lt;br /&gt;
* [[Framecounter]] (Wie schnell läuft mein Programm?)&lt;br /&gt;
* [[Frameratenbegrenzung]] (Beschränken der Bildwiederholrate und sparen von CPU-Leistung und Strom)&lt;br /&gt;
* [[Texture Loader]] (Laden und verwalten von Texturen)&lt;br /&gt;
* [[Model Loader]] (Laden von Modellen die mit Programmen wie 3D Studio Max, Lightwave, Milkshape usw. erstellt wurden.)&lt;br /&gt;
* Eine Möglichkeit zum [[Text ausgeben]]&lt;br /&gt;
* [[Kamera]]&lt;br /&gt;
** [[Kamera (1)]] (Szene in drei Ebenen verschieben und drehen, jetzt mit Beispielprogramm)&lt;br /&gt;
** [[Kamera (2)]] (Kamera Source, letztes Update 1.10.2006)&lt;br /&gt;
** [[Kamera (3)]] (Für die Kamera benötigte Utilities)&lt;br /&gt;
* [[Extensionausgabe]] (Ausgabe der unterstützten Extensions und sonstiger Eigenschaften)&lt;br /&gt;
* [[Techniken_zur_Matrixinversion|Techniken zur Matrixinversion]]&lt;br /&gt;
* [[Render_Thread|Render Thread]] (Verwendung eines Render Threads)&lt;br /&gt;
&lt;br /&gt;
=== Mathematisches ===&lt;br /&gt;
==== Geometrie Objekte ====&lt;br /&gt;
In dieser Rubrik findet ihr Code zum erzeugen von komplexen geometrischen Objekten, denn nicht immer ist die Kapselung die z.B. eine [[Quadrik]] bietet das was man sucht. &lt;br /&gt;
&lt;br /&gt;
* [[Würfel]]&lt;br /&gt;
* [[Kugel]]&lt;br /&gt;
* [[Zylinder]]&lt;br /&gt;
* [[Paraboloid]]&lt;br /&gt;
* [[Hyperboloid]]&lt;br /&gt;
* [[Capsule]]&lt;br /&gt;
* [[Scheibe]]&lt;br /&gt;
* [[Kreis]]&lt;br /&gt;
* [[Kuchenstück]]&lt;br /&gt;
* [[Zweifach_Parametrisierte_Geometrie|Geometrie durch zwei Parameter]]&lt;br /&gt;
* [[Geometrie_durch_Kurven|Geometrie durch Kurven]]&lt;br /&gt;
* [[Rotationskörper]]&lt;br /&gt;
&lt;br /&gt;
==== Rechenhilfen ====&lt;br /&gt;
* [[Matrixmultiplikation]]&lt;br /&gt;
&lt;br /&gt;
=== Licht und Schatten ===&lt;br /&gt;
Das Beleuchtungsmodell von OpenGL besitzt von Haus aus keine Möglichkeit zur Darstellung von Schatten (nicht zuletzt weil es dafür immernoch keine einheitliche Methode gibt), allerdings haben sich über die Jahre hinweg einige Techniken mehr oder weniger durchgesetzt :&lt;br /&gt;
* [[Lightmaps]]&lt;br /&gt;
* [[Projezierte Shadowmaps]] / [[Projezierte Textur]]en&lt;br /&gt;
* [[Volumetrische Stencilschatten]]{{excIcon}}&lt;br /&gt;
* [[Silhouette]] {{icpIcon}}&lt;br /&gt;
* [[Bloom(pseudo-HDR)]] {{icpIcon}}&lt;br /&gt;
&lt;br /&gt;
=== Statische Umgebungen ===&lt;br /&gt;
Besonders in Aussenszenen ist es oft nötig dem Betrachter den Eindruck zu vermitteln, er befinde sich in einer unendlich großen Umgebung. Da man dies jedoch schlecht über speziell dafür erstellte Geometrie lösen kann (weil das schlichtweg zu viel Aufwand und zu leistungsintensiv wäre), haben sich einige Techniken eingebürgert, mit denen man dem Betrachter eine solche unendliche Landschaft mit  wenig Geometrie und einigen Tricks vorgaugeln kann :&lt;br /&gt;
* [[Skyboxen]]&lt;br /&gt;
* [[Skydome]]&lt;br /&gt;
* [[Skysphere]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Dynamische Effekte ===&lt;br /&gt;
Das Auge isst bekanntlich mit. Auch bei 3D Anwendungen, vor allem in der Unterhaltungsindustrie, spielen gigantische Effekte, die dem User ein &amp;quot;Ohhh&amp;quot; und &amp;quot;Ahhh&amp;quot; und vor allem &amp;quot;Wow!&amp;quot; entlocken eine immer größere Rolle. Wie man solche Effekte am besten implementiert finden Sie in den Artikeln dieses Abschnitts.&amp;lt;br&amp;gt;&lt;br /&gt;
(Befassen Sie sich zuerst mit den Grundlagen von [[Partikelsysteme|Partikelsystemen]].)&lt;br /&gt;
* [[Explosionen]] (Allseits gern gesehen. Außer in direkter Nachbarschaft)&lt;br /&gt;
* [[Lichtsäulen]] (Bekannt für die magischen Momente in diversen Rollenspielen.)&lt;br /&gt;
* [[Partikelsysteme]] {{excIcon}} (Grundlage für viele Effekte)&lt;br /&gt;
** [[GLSL Partikel]] (Partikelsystem auf der GPU)&lt;br /&gt;
** [[GLSL Partikel 2]] (Partikelsystem auf der GPU mit Shader Model 4.0)&lt;br /&gt;
&lt;br /&gt;
=== Natürliche Phänomene ===&lt;br /&gt;
Ziel vieler Echtzeit 3D-Anwendung (auch wenn genau der gegenteilige Trend manchmal interessant sein dürfte) ist eine zumindest optische Annäherung an die Realität, also Szenen möglichst &amp;quot;naturgetreu&amp;quot; (auch urbane Szenen können &amp;quot;naturgetreu&amp;quot; sein, auch wenn diese wenig natürlich sind) darzustellen. Dazu gehören auch natürliche Phänomene, wie z.B. realistisch spiegelndes Wasser, Wetterbedingungen (Regen, Schnee, Nebel), Feuer, etc. Oft gibt es für ein natürliches Phänomen recht fortgeschrittene Umsetzungsmöglichkeiten, manchmal liegt die Lösung aber auch recht nahe :&lt;br /&gt;
* [[Prozeduale Bäume|Bäume]]&lt;br /&gt;
* [[Blitz]]&lt;br /&gt;
* [[Feuer]]&lt;br /&gt;
* [[Himmel]]&lt;br /&gt;
* [[Nebel]]&lt;br /&gt;
* [[Staub]]&lt;br /&gt;
* [[Tiefenunschärfe]]&lt;br /&gt;
* [[Wasser]]&lt;br /&gt;
* [[Wettereffekt]]e (Regen, Schnee)&lt;br /&gt;
* [[Wolken]] (als Ergänzung zu den statischen Umgebungen)&lt;br /&gt;
&lt;br /&gt;
=== Raumunterteilungstechniken ===&lt;br /&gt;
Moderne 3D-Anwendungen müssen immer größere und komplexere 3D-Umgebungen darstellen, wobei oft jedoch große Teile eben dieser nicht sichtbar sind, aber ohne entsprechende Optimierungen trotzdem über den Datenbus geschoben (und von der Grafikkarte geclippt) werden müssen. Deshalb finden diverse Raumunterteilungstechniken (die u.a. aus anderen Bereichen stammen) in modernen 3D-Programmen Anwendung :&lt;br /&gt;
* [[BSP-Bäume]] (Binary Space Partitioning = Binäre Raumunterteilung)&lt;br /&gt;
* [[Quadtree]]s &lt;br /&gt;
* [[Octree]]s (Dreidimensionale Erweiterung eines [[Quadtree]]s)&lt;br /&gt;
* [[Portal]]e (Logische Sichtbegrenzung an Durchgängen)&lt;br /&gt;
* [[PVS]] (Potentially Visible Sets = Mögliche sichtbare Sets)&lt;br /&gt;
&lt;br /&gt;
=== Terrain Darstellung ===&lt;br /&gt;
In vielen 3D Anwendungen, vom Flugsimulator über Egoshooter bis zum Strategiespiel, muss die Umgebung visualisiert werden. Welche Techniken bei der Speicherung (siehe auch '''Raumunterteilungstechniken'''), Bildaufbau und Texturierung zum Einsatz kommen, findet ihr hier:&amp;lt;br&amp;gt;&lt;br /&gt;
:'''[[LOD|Level of Detail]] Algorithmen für Landschaften'''&lt;br /&gt;
&lt;br /&gt;
*[[VDPM]] ('''V'''iew-'''D'''ependent '''P'''rogressive '''M'''eshes)&lt;br /&gt;
*[[ROAM]] ('''R'''eal-time '''O'''ptimally '''A'''dapting '''M'''eshes)&lt;br /&gt;
*[[Tutorial_Terrain3|Röttger Algorithmus]]&lt;br /&gt;
*[[Geometrical Mipmapping]]&lt;br /&gt;
*[[VIPMs]] ('''V'''iew '''I'''ndependent '''P'''rogressive '''M'''eshe'''s''')&lt;br /&gt;
&lt;br /&gt;
:'''Texturierung'''&lt;br /&gt;
&lt;br /&gt;
*[[Texture Splatting]] (Kombination von Texturen mittels [[Blenden|Blending]] und [[Multitexturing]])&lt;br /&gt;
*[[Texture Backing]] (Dynamisches erstellen von Texturen)&lt;br /&gt;
&lt;br /&gt;
=== Prozeduale Grafiken ===&lt;br /&gt;
Prozeduale Grafiken werden häufig verwendet um&lt;br /&gt;
*eine vielfältige Umgebung zu gewährleisten&lt;br /&gt;
*Speicherplatz auf der Festplatte zu sparen&lt;br /&gt;
*den Grafikern die Arbeit zu erleichtern (und teilweise sogar erst zu ermöglichen)&lt;br /&gt;
Die Algorithmen und Möglichkeiten die sich dabei bieten sind hier aufgelistet:&lt;br /&gt;
* [[Perlin Noise]] {{excIcon}} (Algorithmus für Texturen, Landschaft und vieles mehr)&lt;br /&gt;
* [[L-Systems]] (aus wenig mach viel, Landschaftsgenerierung, Baumgenerierung, ...)&lt;br /&gt;
* [[Fault Formation]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Prozeduale Landschaft]] (Spezielle Hinweise und Techniken zur Landschaftsgenerierung&lt;br /&gt;
* [[Midpoint Displacement]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Hügel_Algorithmen]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Prozeduale Bäume]] (Techniken und Algorithmen speziell zur Baumgenerierung)&lt;br /&gt;
* [[Prozeduale Texturen]] (Spezielle Hinweise zu Wasser, Lava und ähnliches)&lt;br /&gt;
&lt;br /&gt;
=== Pathfinding ===&lt;br /&gt;
Pathfinding ist einer der grundlegenden Bereiche der Künstlichen Intelligenz, und aus diesem Grund für Spiele mit Computergegnern meistens unumgänglich.&lt;br /&gt;
* [[Tiefensuche]]&lt;br /&gt;
* [[Breitensuche]]&lt;br /&gt;
* [[A-Stern]]&lt;br /&gt;
* [[Dijkstra]]&lt;br /&gt;
* [[Floyd Warshall]]&lt;br /&gt;
* [[Navigation Meshes]]&lt;br /&gt;
* [[Pathfinding-Level of Detail]]&lt;br /&gt;
&lt;br /&gt;
=== Sonstiges ===&lt;br /&gt;
* [[Bilder als Ressourcen]] speichern und laden&lt;br /&gt;
* [[Blenderscript|Exportscript für Blender]]&lt;br /&gt;
* [[Blenderexporter|Blenderexport ausführliche Anleitung]]&lt;br /&gt;
* [[GUI_Leitfaden|Leitfaden Graphisches Nutzerinterface]]&lt;br /&gt;
* [[Interpolation]]&lt;br /&gt;
* [[Lokalisierung]]&lt;br /&gt;
* [[Pixelweise Bildbearbeitung]]&lt;br /&gt;
* [[Physik und 3D|Wie verbinde ich Physikberechnung und 3D Rendering?]]&lt;br /&gt;
* [[Screenshot]]s von OpenGL Ausgaben&lt;br /&gt;
* [[Tesselierung|Polygone tesselieren]]&lt;br /&gt;
* [[TGA Bilder laden]]&lt;br /&gt;
* [[Verfügbare Auflösungen]] anzeigen&lt;br /&gt;
* [[Zielen auf bewegte Gegner]]&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
Weitere Links zum Thema &amp;quot;Effekte unter OpenGL&amp;quot; findet ihr in der [[Link]]-Sammlung unter [[Link#Effekte_und_Techniken_mit_OpenGL|Effekte und Techniken mit OpenGL]].&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=26256</id>
		<title>Techniken und Algorithmen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Techniken_und_Algorithmen&amp;diff=26256"/>
				<updated>2014-06-08T13:22:01Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Nützliche Helfer */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Artikel dieses Wiki-Abschnittes sind im Gegensatz zu den [[Tutorial]]s meist kürzer. Dafür enthalten sie mitunter sehr viel Code der direkt verwendet werden, oder als Grundlage für die eigene Arbeit dienen kann.&lt;br /&gt;
&lt;br /&gt;
== Was hier hinein gehört ==&lt;br /&gt;
Hier kommen, wie der Name vermuten lässt, '''Erklärungen''' zu in der 3D-Echtzeitprogrammierung verwendeten '''Techniken''' hin. Z.B. verschiedene Schattentechniken, Bump-Mapping, etc.&lt;br /&gt;
&lt;br /&gt;
[[Hintergrundwissen]] gehört hier nicht rein. Sachen wie ''&amp;quot;was ist ein Tiefenpuffer und wofür ist er gut&amp;quot;'' haben hier nichts zu suchen.&amp;lt;br&amp;gt;&lt;br /&gt;
Sollte es für eine Technik/Thematik (siehe unten für Beispiel) mehrere &amp;quot;Lösungswege&amp;quot; geben, sollte eine kleine Überschrift eingefügt werden.&lt;br /&gt;
&lt;br /&gt;
Wenn ihr einen Technik- oder Algorithmus-Artikel erstellt, so solltet ihr unter den Artikel ein&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;[[Kategorie:Technik_oder_Algorithmus]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
stellen. Damit wird der Artikel der  [[:Kategorie:Technik_oder_Algorithmus]] zugeordnet.&lt;br /&gt;
Falls dieser Artikel nicht nur erklärt, was der Begriff bedeutet, sondern auch noch eine Anleitung ist, wie man die entsprechende Technik realisiert, so könnt ihr den Artikel auch noch der Kategorie [[:Kategorie:Anleitung|Anleitung]] zuweisen.&lt;br /&gt;
&lt;br /&gt;
== Übersicht ==&lt;br /&gt;
=== Sammlungen ===&lt;br /&gt;
* [[Materialsammlung]] (Enthält Materialien für [[glMaterial]].)&lt;br /&gt;
* [[Shadersammlung]] (Enthält Shader.)&lt;br /&gt;
&lt;br /&gt;
=== Nützliche Helfer ===&lt;br /&gt;
In dieser Rubrik findet sich all das, was ein OpenGL/Graphikprogrammierer immer brauch oder schnell mal zur Hand haben muss:&lt;br /&gt;
* [[Framecounter]] (Wie schnell läuft mein Programm?)&lt;br /&gt;
* [[Frameratenbegrenzung]] (Beschränken der Bildwiederholrate und sparen von CPU-Leistung und Strom)&lt;br /&gt;
* [[Texture Loader]] (Laden und verwalten von Texturen)&lt;br /&gt;
* [[Model Loader]] (Laden von Modellen die mit Programmen wie 3D Studio Max, Lightwave, Milkshape usw. erstellt wurden.)&lt;br /&gt;
* Eine Möglichkeit zum [[Text ausgeben]]&lt;br /&gt;
* [[Kamera]]&lt;br /&gt;
** [[Kamera (1)]] (Szene in drei Ebenen verschieben und drehen, jetzt mit Beispielprogramm)&lt;br /&gt;
** [[Kamera (2)]] (Kamera Source, letztes Update 1.10.2006)&lt;br /&gt;
** [[Kamera (3)]] (Für die Kamera benötigte Utilities)&lt;br /&gt;
* [[Extensionausgabe]] (Ausgabe der unterstützten Extensions und sonstiger Eigenschaften)&lt;br /&gt;
* [[Techniken_zur_Matrixinversion|Techniken zur Matrixinversion]]&lt;br /&gt;
* [[Render_Thread]] (Verwendung eines Render Threads)&lt;br /&gt;
&lt;br /&gt;
=== Mathematisches ===&lt;br /&gt;
==== Geometrie Objekte ====&lt;br /&gt;
In dieser Rubrik findet ihr Code zum erzeugen von komplexen geometrischen Objekten, denn nicht immer ist die Kapselung die z.B. eine [[Quadrik]] bietet das was man sucht. &lt;br /&gt;
&lt;br /&gt;
* [[Würfel]]&lt;br /&gt;
* [[Kugel]]&lt;br /&gt;
* [[Zylinder]]&lt;br /&gt;
* [[Paraboloid]]&lt;br /&gt;
* [[Hyperboloid]]&lt;br /&gt;
* [[Capsule]]&lt;br /&gt;
* [[Scheibe]]&lt;br /&gt;
* [[Kreis]]&lt;br /&gt;
* [[Kuchenstück]]&lt;br /&gt;
* [[Zweifach_Parametrisierte_Geometrie|Geometrie durch zwei Parameter]]&lt;br /&gt;
* [[Geometrie_durch_Kurven|Geometrie durch Kurven]]&lt;br /&gt;
* [[Rotationskörper]]&lt;br /&gt;
&lt;br /&gt;
==== Rechenhilfen ====&lt;br /&gt;
* [[Matrixmultiplikation]]&lt;br /&gt;
&lt;br /&gt;
=== Licht und Schatten ===&lt;br /&gt;
Das Beleuchtungsmodell von OpenGL besitzt von Haus aus keine Möglichkeit zur Darstellung von Schatten (nicht zuletzt weil es dafür immernoch keine einheitliche Methode gibt), allerdings haben sich über die Jahre hinweg einige Techniken mehr oder weniger durchgesetzt :&lt;br /&gt;
* [[Lightmaps]]&lt;br /&gt;
* [[Projezierte Shadowmaps]] / [[Projezierte Textur]]en&lt;br /&gt;
* [[Volumetrische Stencilschatten]]{{excIcon}}&lt;br /&gt;
* [[Silhouette]] {{icpIcon}}&lt;br /&gt;
* [[Bloom(pseudo-HDR)]] {{icpIcon}}&lt;br /&gt;
&lt;br /&gt;
=== Statische Umgebungen ===&lt;br /&gt;
Besonders in Aussenszenen ist es oft nötig dem Betrachter den Eindruck zu vermitteln, er befinde sich in einer unendlich großen Umgebung. Da man dies jedoch schlecht über speziell dafür erstellte Geometrie lösen kann (weil das schlichtweg zu viel Aufwand und zu leistungsintensiv wäre), haben sich einige Techniken eingebürgert, mit denen man dem Betrachter eine solche unendliche Landschaft mit  wenig Geometrie und einigen Tricks vorgaugeln kann :&lt;br /&gt;
* [[Skyboxen]]&lt;br /&gt;
* [[Skydome]]&lt;br /&gt;
* [[Skysphere]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Dynamische Effekte ===&lt;br /&gt;
Das Auge isst bekanntlich mit. Auch bei 3D Anwendungen, vor allem in der Unterhaltungsindustrie, spielen gigantische Effekte, die dem User ein &amp;quot;Ohhh&amp;quot; und &amp;quot;Ahhh&amp;quot; und vor allem &amp;quot;Wow!&amp;quot; entlocken eine immer größere Rolle. Wie man solche Effekte am besten implementiert finden Sie in den Artikeln dieses Abschnitts.&amp;lt;br&amp;gt;&lt;br /&gt;
(Befassen Sie sich zuerst mit den Grundlagen von [[Partikelsysteme|Partikelsystemen]].)&lt;br /&gt;
* [[Explosionen]] (Allseits gern gesehen. Außer in direkter Nachbarschaft)&lt;br /&gt;
* [[Lichtsäulen]] (Bekannt für die magischen Momente in diversen Rollenspielen.)&lt;br /&gt;
* [[Partikelsysteme]] {{excIcon}} (Grundlage für viele Effekte)&lt;br /&gt;
** [[GLSL Partikel]] (Partikelsystem auf der GPU)&lt;br /&gt;
** [[GLSL Partikel 2]] (Partikelsystem auf der GPU mit Shader Model 4.0)&lt;br /&gt;
&lt;br /&gt;
=== Natürliche Phänomene ===&lt;br /&gt;
Ziel vieler Echtzeit 3D-Anwendung (auch wenn genau der gegenteilige Trend manchmal interessant sein dürfte) ist eine zumindest optische Annäherung an die Realität, also Szenen möglichst &amp;quot;naturgetreu&amp;quot; (auch urbane Szenen können &amp;quot;naturgetreu&amp;quot; sein, auch wenn diese wenig natürlich sind) darzustellen. Dazu gehören auch natürliche Phänomene, wie z.B. realistisch spiegelndes Wasser, Wetterbedingungen (Regen, Schnee, Nebel), Feuer, etc. Oft gibt es für ein natürliches Phänomen recht fortgeschrittene Umsetzungsmöglichkeiten, manchmal liegt die Lösung aber auch recht nahe :&lt;br /&gt;
* [[Prozeduale Bäume|Bäume]]&lt;br /&gt;
* [[Blitz]]&lt;br /&gt;
* [[Feuer]]&lt;br /&gt;
* [[Himmel]]&lt;br /&gt;
* [[Nebel]]&lt;br /&gt;
* [[Staub]]&lt;br /&gt;
* [[Tiefenunschärfe]]&lt;br /&gt;
* [[Wasser]]&lt;br /&gt;
* [[Wettereffekt]]e (Regen, Schnee)&lt;br /&gt;
* [[Wolken]] (als Ergänzung zu den statischen Umgebungen)&lt;br /&gt;
&lt;br /&gt;
=== Raumunterteilungstechniken ===&lt;br /&gt;
Moderne 3D-Anwendungen müssen immer größere und komplexere 3D-Umgebungen darstellen, wobei oft jedoch große Teile eben dieser nicht sichtbar sind, aber ohne entsprechende Optimierungen trotzdem über den Datenbus geschoben (und von der Grafikkarte geclippt) werden müssen. Deshalb finden diverse Raumunterteilungstechniken (die u.a. aus anderen Bereichen stammen) in modernen 3D-Programmen Anwendung :&lt;br /&gt;
* [[BSP-Bäume]] (Binary Space Partitioning = Binäre Raumunterteilung)&lt;br /&gt;
* [[Quadtree]]s &lt;br /&gt;
* [[Octree]]s (Dreidimensionale Erweiterung eines [[Quadtree]]s)&lt;br /&gt;
* [[Portal]]e (Logische Sichtbegrenzung an Durchgängen)&lt;br /&gt;
* [[PVS]] (Potentially Visible Sets = Mögliche sichtbare Sets)&lt;br /&gt;
&lt;br /&gt;
=== Terrain Darstellung ===&lt;br /&gt;
In vielen 3D Anwendungen, vom Flugsimulator über Egoshooter bis zum Strategiespiel, muss die Umgebung visualisiert werden. Welche Techniken bei der Speicherung (siehe auch '''Raumunterteilungstechniken'''), Bildaufbau und Texturierung zum Einsatz kommen, findet ihr hier:&amp;lt;br&amp;gt;&lt;br /&gt;
:'''[[LOD|Level of Detail]] Algorithmen für Landschaften'''&lt;br /&gt;
&lt;br /&gt;
*[[VDPM]] ('''V'''iew-'''D'''ependent '''P'''rogressive '''M'''eshes)&lt;br /&gt;
*[[ROAM]] ('''R'''eal-time '''O'''ptimally '''A'''dapting '''M'''eshes)&lt;br /&gt;
*[[Tutorial_Terrain3|Röttger Algorithmus]]&lt;br /&gt;
*[[Geometrical Mipmapping]]&lt;br /&gt;
*[[VIPMs]] ('''V'''iew '''I'''ndependent '''P'''rogressive '''M'''eshe'''s''')&lt;br /&gt;
&lt;br /&gt;
:'''Texturierung'''&lt;br /&gt;
&lt;br /&gt;
*[[Texture Splatting]] (Kombination von Texturen mittels [[Blenden|Blending]] und [[Multitexturing]])&lt;br /&gt;
*[[Texture Backing]] (Dynamisches erstellen von Texturen)&lt;br /&gt;
&lt;br /&gt;
=== Prozeduale Grafiken ===&lt;br /&gt;
Prozeduale Grafiken werden häufig verwendet um&lt;br /&gt;
*eine vielfältige Umgebung zu gewährleisten&lt;br /&gt;
*Speicherplatz auf der Festplatte zu sparen&lt;br /&gt;
*den Grafikern die Arbeit zu erleichtern (und teilweise sogar erst zu ermöglichen)&lt;br /&gt;
Die Algorithmen und Möglichkeiten die sich dabei bieten sind hier aufgelistet:&lt;br /&gt;
* [[Perlin Noise]] {{excIcon}} (Algorithmus für Texturen, Landschaft und vieles mehr)&lt;br /&gt;
* [[L-Systems]] (aus wenig mach viel, Landschaftsgenerierung, Baumgenerierung, ...)&lt;br /&gt;
* [[Fault Formation]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Prozeduale Landschaft]] (Spezielle Hinweise und Techniken zur Landschaftsgenerierung&lt;br /&gt;
* [[Midpoint Displacement]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Hügel_Algorithmen]] (primär zur Landschaftsgenerierung)&lt;br /&gt;
* [[Prozeduale Bäume]] (Techniken und Algorithmen speziell zur Baumgenerierung)&lt;br /&gt;
* [[Prozeduale Texturen]] (Spezielle Hinweise zu Wasser, Lava und ähnliches)&lt;br /&gt;
&lt;br /&gt;
=== Pathfinding ===&lt;br /&gt;
Pathfinding ist einer der grundlegenden Bereiche der Künstlichen Intelligenz, und aus diesem Grund für Spiele mit Computergegnern meistens unumgänglich.&lt;br /&gt;
* [[Tiefensuche]]&lt;br /&gt;
* [[Breitensuche]]&lt;br /&gt;
* [[A-Stern]]&lt;br /&gt;
* [[Dijkstra]]&lt;br /&gt;
* [[Floyd Warshall]]&lt;br /&gt;
* [[Navigation Meshes]]&lt;br /&gt;
* [[Pathfinding-Level of Detail]]&lt;br /&gt;
&lt;br /&gt;
=== Sonstiges ===&lt;br /&gt;
* [[Bilder als Ressourcen]] speichern und laden&lt;br /&gt;
* [[Blenderscript|Exportscript für Blender]]&lt;br /&gt;
* [[Blenderexporter|Blenderexport ausführliche Anleitung]]&lt;br /&gt;
* [[GUI_Leitfaden|Leitfaden Graphisches Nutzerinterface]]&lt;br /&gt;
* [[Interpolation]]&lt;br /&gt;
* [[Lokalisierung]]&lt;br /&gt;
* [[Pixelweise Bildbearbeitung]]&lt;br /&gt;
* [[Physik und 3D|Wie verbinde ich Physikberechnung und 3D Rendering?]]&lt;br /&gt;
* [[Screenshot]]s von OpenGL Ausgaben&lt;br /&gt;
* [[Tesselierung|Polygone tesselieren]]&lt;br /&gt;
* [[TGA Bilder laden]]&lt;br /&gt;
* [[Verfügbare Auflösungen]] anzeigen&lt;br /&gt;
* [[Zielen auf bewegte Gegner]]&lt;br /&gt;
&lt;br /&gt;
== Externe Links ==&lt;br /&gt;
Weitere Links zum Thema &amp;quot;Effekte unter OpenGL&amp;quot; findet ihr in der [[Link]]-Sammlung unter [[Link#Effekte_und_Techniken_mit_OpenGL|Effekte und Techniken mit OpenGL]].&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26255</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26255"/>
				<updated>2014-06-08T13:19:20Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
Ein weiterer Vorteil tritt auf, wenn man eine Anwendung mit mehreren Fenstern entwickelt, da man einfach für jedes Fenster eine weitere Instanz erzeugen kann und die Logik für was auf welchen Fenster gezeichnet werden soll in der Programm Logik und nicht Render Logik liegt.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer('''BB1''','''BB2''') und ein Front-Buffer('''FB1''') erzeugt, der Front-Buffer wird von der Programmlogik befüllt und der Render Thread kann ein Back-Buffer verarbeiten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:renderthread_communication.png]]&lt;br /&gt;
&lt;br /&gt;
Die Programm Logik kann nie auf die Back-Buffer zugreifen aber indirekt mit dem Front-Buffer Swap Befehl den Front-Buffer und den gerade nicht verwendetend Back-Buffer austauschen.&lt;br /&gt;
Der Render Thread verwendet immer nur ein Back-Buffer und wenn er fertig ist, macht er ein Swap auf den Back-Buffern und bekommt so eine neue Queue aus den 2. Back-Buffer.&lt;br /&gt;
In '''BB1''' Slot wird also immer die Queue verarbeitet, in '''BB2''' liegt immer ein vollständige Befehlsliste, für die Verarbeitung, bereit und im Front-Buffer wird eine neue Befehlsliste erstellt.&lt;br /&gt;
&lt;br /&gt;
Wenn die Program Logik mit 2000 Frames arbeitet, dann füllt sie 2000 mal den Front-Buffer und führt den Swap Befehle aus.&lt;br /&gt;
Sollte der Render Thread mit einer niederen Frequenz laufen, dann wird die Programm Logik nichts anderes machen als den noch nicht gerenderten Stand auf ein aktuelleren Stand zu bringen, damit der Render Thread den letzten vollständigen Stand wieder spiegelt.&lt;br /&gt;
Wenn die Game Logik mit einer niederen Frequenz läuft, dann kann man 2 Möglichkeiten implementieren.&lt;br /&gt;
Entweder wechselt man einfach die beiden Back-Buffer und rendert mal den letzen und mal den Vorletzen oder der Render Thread räumt die Queue auf, bevor man den Swap aufruft und wenn man eine leere Queue hat wird garnicht SwapBuffer von der Render API aufgerufen und somit bleibt der letzte gerenderte Frame im Grafikkarten Speicher erhalten.&lt;br /&gt;
&lt;br /&gt;
Der Render Thread sollte mit einer anderen Frequenz laufen als die Programm Logik, z.B. der aktuellen Monitor Frequenz(VSync) oder niederer.&lt;br /&gt;
Dies ermöglicht es z.B. präzise Physik Simulationen mit hunderten bis tausenden durchläufen pro Sekunde.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und so schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Window1.Context.Enqueue(RedTintedCatMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Window1.Context.Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
Window1.Context.Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
Window1.Context.Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
Window1.Context.Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
Window1.Context.Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
Window1.Context.Enqueue(EndMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
Window1.Context.Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
Window1.Context.Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
Window1.Context.Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
Window1.Context.Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26254</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26254"/>
				<updated>2014-06-08T13:17:30Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
Ein weiterer Vorteil tritt auf, wenn man eine Anwendung mit mehreren Fenstern entwickelt, da man einfach für jedes Fenster eine weitere Instanz erzeugen kann und die Logik für was auf welchen Fenster gezeichnet werden soll in der Programm Logik und nicht Render Logik liegt.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer('''BB1''','''BB2''') und ein Front-Buffer('''FB1''') erzeugt, der Front-Buffer wird von der Programmlogik befüllt und der Render Thread kann ein Back-Buffer verarbeiten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:renderthread_communication.png]]&lt;br /&gt;
&lt;br /&gt;
Die Programm Logik kann nie auf die Back-Buffer zugreifen aber indirekt mit dem Front-Buffer Swap Befehl den Front-Buffer und den gerade nicht verwendetend Back-Buffer austauschen.&lt;br /&gt;
Der Render Thread verwendet immer nur ein Back-Buffer und wenn er fertig ist, macht er ein Swap auf den Back-Buffern und bekommt so eine neue Queue aus den 2. Back-Buffer.&lt;br /&gt;
In '''BB1''' Slot wird also immer die Queue verarbeitet, in '''BB2''' liegt immer ein vollständige Befehlsliste, für die Verarbeitung, bereit und im Front-Buffer wird eine neue Befehlsliste erstellt.&lt;br /&gt;
&lt;br /&gt;
Wenn die Program Logik mit 2000 Frames arbeitet, dann füllt sie 2000 mal den Front-Buffer und führt den Swap Befehle aus.&lt;br /&gt;
Sollte der Render Thread mit einer niederen Frequenz laufen, dann wird die Programm Logik nichts anderes machen als den noch nicht gerenderten Stand auf ein aktuelleren Stand zu bringen, damit der Render Thread den letzten vollständigen Stand wieder spiegelt.&lt;br /&gt;
Wenn die Game Logik mit einer niederen Frequenz läuft, dann kann man 2 Möglichkeiten implementieren.&lt;br /&gt;
Entweder wechselt man einfach die beiden Back-Buffer und rendert mal den letzen und mal den Vorletzen oder der Render Thread räumt die Queue auf, bevor man den Swap aufruft und wenn man eine leere Queue hat wird garnicht SwapBuffer von der Render API aufgerufen und somit bleibt der letzte gerenderte Frame im Grafikkarten Speicher erhalten.&lt;br /&gt;
&lt;br /&gt;
Der Render Thread sollte mit einer anderen Frequenz laufen als die Programm Logik, z.B. der aktuellen Monitor Frequenz(VSync) oder niederer.&lt;br /&gt;
Dies ermöglicht es z.B. präzise Physik Simulationen mit hunderten bis tausenden durchläufen pro Sekunde.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und so schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(RedTintedCatMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
RenderThread::Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
RenderThread::Enqueue(EndMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
RenderThread::Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
RenderThread::Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
RenderThread::Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26253</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26253"/>
				<updated>2014-06-08T13:12:23Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer('''BB1''','''BB2''') und ein Front-Buffer('''FB1''') erzeugt, der Front-Buffer wird von der Programmlogik befüllt und der Render Thread kann ein Back-Buffer verarbeiten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:renderthread_communication.png]]&lt;br /&gt;
&lt;br /&gt;
Die Programm Logik kann nie auf die Back-Buffer zugreifen aber indirekt mit dem Front-Buffer Swap Befehl den Front-Buffer und den gerade nicht verwendetend Back-Buffer austauschen.&lt;br /&gt;
Der Render Thread verwendet immer nur ein Back-Buffer und wenn er fertig ist, macht er ein Swap auf den Back-Buffern und bekommt so eine neue Queue aus den 2. Back-Buffer.&lt;br /&gt;
In '''BB1''' Slot wird also immer die Queue verarbeitet, in '''BB2''' liegt immer ein vollständige Befehlsliste, für die Verarbeitung, bereit und im Front-Buffer wird eine neue Befehlsliste erstellt.&lt;br /&gt;
&lt;br /&gt;
Wenn die Program Logik mit 2000 Frames arbeitet, dann füllt sie 2000 mal den Front-Buffer und führt den Swap Befehle aus.&lt;br /&gt;
Sollte der Render Thread mit einer niederen Frequenz laufen, dann wird die Programm Logik nichts anderes machen als den noch nicht gerenderten Stand auf ein aktuelleren Stand zu bringen, damit der Render Thread den letzten vollständigen Stand wieder spiegelt.&lt;br /&gt;
Wenn die Game Logik mit einer niederen Frequenz läuft, dann kann man 2 Möglichkeiten implementieren.&lt;br /&gt;
Entweder wechselt man einfach die beiden Back-Buffer und rendert mal den letzen und mal den Vorletzen oder der Render Thread räumt die Queue auf, bevor man den Swap aufruft und wenn man eine leere Queue hat wird garnicht SwapBuffer von der Render API aufgerufen und somit bleibt der letzte gerenderte Frame im Grafikkarten Speicher erhalten.&lt;br /&gt;
&lt;br /&gt;
Der Render Thread sollte mit einer anderen Frequenz laufen als die Programm Logik, z.B. der aktuellen Monitor Frequenz(VSync) oder niederer.&lt;br /&gt;
Dies ermöglicht es z.B. präzise Physik Simulationen mit hunderten bis tausenden durchläufen pro Sekunde.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und so schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(RedTintedCatMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
RenderThread::Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
RenderThread::Enqueue(EndMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
RenderThread::Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
RenderThread::Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
RenderThread::Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26252</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26252"/>
				<updated>2014-06-08T13:10:07Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Schwache Bindung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer(BB1,BB2) und ein Front-Buffer(FB1) erzeugt, der Front-Buffer wird von der Programmlogik befüllt und der Render Thread kann ein Back-Buffer verarbeiten.&lt;br /&gt;
&lt;br /&gt;
[[Datei:renderthread_communication.png]]&lt;br /&gt;
&lt;br /&gt;
Die Programm Logik kann nie auf die Back-Buffer zugreifen aber indirekt mit dem Front-Buffer Swap Befehl den Front-Buffer und den gerade nicht verwendetend Back-Buffer austauschen.&lt;br /&gt;
Der Render Thread verwendet immer nur ein Back-Buffer und wenn er fertig ist, macht er ein Swap auf den Back-Buffern und bekommt so eine neue Queue aus den 2. Back-Buffer.&lt;br /&gt;
In BB1 Slot wird also immer die Queue verarbeitet, in BB2 liegt immer ein vollständige Befehlsliste, für die Verarbeitung, bereit und im Front-Buffer wird eine neue Befehlsliste erstellt.&lt;br /&gt;
&lt;br /&gt;
Wenn die Program Logik mit 2000 Frames arbeitet, dann füllt sie 2000 mal den Front-Buffer und führt den Swap Befehle aus.&lt;br /&gt;
Sollte der Render Thread mit einer niederen Frequenz laufen, dann wird die Programm Logik nichts anderes machen als den noch nicht gerenderten Stand auf ein aktuelleren Stand zu bringen, damit der Render Thread den letzten vollständigen Stand wieder spiegelt.&lt;br /&gt;
Wenn die Game Logik mit einer niederen Frequenz läuft, dann kann man 2 Möglichkeiten implementieren.&lt;br /&gt;
Entweder wechselt man einfach die beiden Back-Buffer und rendert mal den letzen und mal den Vorletzen oder der Render Thread räumt die Queue auf, bevor man den Swap aufruft und wenn man eine leere Queue hat wird garnicht SwapBuffer von der Render API aufgerufen und somit bleibt der letzte gerenderte Frame im Grafikkarten Speicher erhalten.&lt;br /&gt;
&lt;br /&gt;
Der Render Thread sollte mit einer anderen Frequenz laufen als die Programm Logik, z.B. der aktuellen Monitor Frequenz(VSync) oder niederer.&lt;br /&gt;
Dies ermöglicht es z.B. präzise Physik Simulationen mit hunderten bis tausenden durchläufen pro Sekunde.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und so schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(RedTintedCatMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
RenderThread::Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
RenderThread::Enqueue(EndMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
RenderThread::Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
RenderThread::Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
RenderThread::Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:renderthread_communication.png&amp;diff=26251</id>
		<title>Datei:renderthread communication.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:renderthread_communication.png&amp;diff=26251"/>
				<updated>2014-06-08T12:47:34Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: Tak2004 lud eine neue Version von „Datei:renderthread communication.png“ hoch&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:renderthread_communication.png&amp;diff=26250</id>
		<title>Datei:renderthread communication.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:renderthread_communication.png&amp;diff=26250"/>
				<updated>2014-06-08T12:29:14Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26249</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26249"/>
				<updated>2014-06-08T12:28:44Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer(B1,B2) und ein Front-Buffer(FB) erzeugt, der Front-Buffer wird von der Programmlogik befüllt und der Render Thread kann ein Back-Buffer verarbeiten.&lt;br /&gt;
[[Datei:renderthread_communication.png]]&lt;br /&gt;
Nun wird der Front-Buffer mit dem 1. Back-Buffer(B1) geswapped, sollte nun der Renderer durch sein, wird er B1 mit B2 austauschen und beginnt mit der verarbeitung von B1, während die Programmlogik FB und B2 swappen kann.&lt;br /&gt;
Der Sinn ist, dass nun Render Thread und Logik mit unterschiedlichen Frequenzen arbeiten können und immer ein aktueller vollständiger Stand verfügbar ist.&lt;br /&gt;
Mit dieser Variante muss man sich nur um Multithreading sichere Programmierung bei den 3 Queues kümmern.&lt;br /&gt;
Dies kann man auch Lösen, in dem man Lock-Free Queues benutzt.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(RedTintedCatMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
RenderThread::Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
RenderThread::Enqueue(EndMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
RenderThread::Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
RenderThread::Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
RenderThread::Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26248</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26248"/>
				<updated>2014-06-07T16:57:20Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer(B1,B2) und ein Front-Buffer(FB) erzeugt, der Front-Buffer wird von der Programmlogik befüllt und am Ende wird ein Swap angefordert.&lt;br /&gt;
Nun wird der Front-Buffer mit dem 1. Back-Buffer(B1) geswapped, sollte nun der Renderer durch sein, wird er B1 mit B2 austauschen und beginnt mit der verarbeitung von B1, während die Programmlogik FB und B2 swappen kann.&lt;br /&gt;
Der Sinn ist, dass nun Render Thread und Logik mit unterschiedlichen Frequenzen arbeiten können und immer ein aktueller vollständiger Stand verfügbar ist.&lt;br /&gt;
Mit dieser Variante muss man sich nur um Multithreading sichere Programmierung bei den 3 Queues kümmern.&lt;br /&gt;
Dies kann man auch Lösen, in dem man Lock-Free Queues benutzt.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(RedTintedCatMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
RenderThread::Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
RenderThread::Enqueue(EndMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
RenderThread::Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
RenderThread::Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
RenderThread::Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26247</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26247"/>
				<updated>2014-06-07T16:57:00Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Schwache Bindung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Render Thread=&lt;br /&gt;
Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer(B1,B2) und ein Front-Buffer(FB) erzeugt, der Front-Buffer wird von der Programmlogik befüllt und am Ende wird ein Swap angefordert.&lt;br /&gt;
Nun wird der Front-Buffer mit dem 1. Back-Buffer(B1) geswapped, sollte nun der Renderer durch sein, wird er B1 mit B2 austauschen und beginnt mit der verarbeitung von B1, während die Programmlogik FB und B2 swappen kann.&lt;br /&gt;
Der Sinn ist, dass nun Render Thread und Logik mit unterschiedlichen Frequenzen arbeiten können und immer ein aktueller vollständiger Stand verfügbar ist.&lt;br /&gt;
Mit dieser Variante muss man sich nur um Multithreading sichere Programmierung bei den 3 Queues kümmern.&lt;br /&gt;
Dies kann man auch Lösen, in dem man Lock-Free Queues benutzt.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(RedTintedCatMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;RenderThread::Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
RenderThread::Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
RenderThread::Enqueue(EndMessage());&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
RenderThread::Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
RenderThread::Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
RenderThread::Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/source&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26246</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26246"/>
				<updated>2014-06-07T16:56:02Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Render Thread=&lt;br /&gt;
Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer(B1,B2) und ein Front-Buffer(FB) erzeugt, der Front-Buffer wird von der Programmlogik befüllt und am Ende wird ein Swap angefordert.&lt;br /&gt;
Nun wird der Front-Buffer mit dem 1. Back-Buffer(B1) geswapped, sollte nun der Renderer durch sein, wird er B1 mit B2 austauschen und beginnt mit der verarbeitung von B1, während die Programmlogik FB und B2 swappen kann.&lt;br /&gt;
Der Sinn ist, dass nun Render Thread und Logik mit unterschiedlichen Frequenzen arbeiten können und immer ein aktueller vollständiger Stand verfügbar ist.&lt;br /&gt;
Mit dieser Variante muss man sich nur um Multithreading sichere Programmierung bei den 3 Queues kümmern.&lt;br /&gt;
Dies kann man auch Lösen, in dem man Lock-Free Queues benutzt.&lt;br /&gt;
&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;br /&gt;
Zu spezielle Befehle erkennt man in der Regel, dass diese keine Parameter haben und sehr selten verwendet werden.&lt;br /&gt;
&amp;lt;code=cpp&amp;gt;RenderThread::Enqueue(RedTintedCatMessage());&amp;lt;/code&amp;gt;&lt;br /&gt;
Zu Atomare Befehle erkennt man in der Regel, dass man sehr große Codeblöcke auf der Logikseite schreiben muss, um einzelne Daten zu visualisieren.&lt;br /&gt;
&amp;lt;code=cpp&amp;gt;RenderThread::Enqueue(BeginMessage(FaceType::Triangle));&lt;br /&gt;
RenderThread::Enqueue(ColorMessage(FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(-1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(1,-1,0);&lt;br /&gt;
RenderThread::Enqueue(VertexMessage(0,1,0);&lt;br /&gt;
RenderThread::Enqueue(EndMessage());&amp;lt;/code&amp;gt;&lt;br /&gt;
Eine einfache Möglichkeit ist Renderdaten als Objekte zu zerlegen und auf diesen auf zu bauen.&lt;br /&gt;
&amp;lt;code=cpp&amp;gt;Mesh catMesh(&amp;quot;cat.mesh&amp;quot;);&lt;br /&gt;
Shader redTinting(&amp;quot;tinting.shader&amp;quot;);&lt;br /&gt;
RenderThread::Enqueue(BindMeshMessage(catMesh));&lt;br /&gt;
RenderThread::Enqueue(BindShaderMessage(redTinting));&lt;br /&gt;
RenderThread::Enqueue(SetShaderVariable(&amp;quot;tintingColor&amp;quot;, FaceColor::Red));&lt;br /&gt;
RenderThread::Enqueue(Draw(catMesh.StartIndex(), catMesh.LastIndex()));&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26245</id>
		<title>Frameratenbegrenzung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26245"/>
				<updated>2014-06-07T16:23:31Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Siehe auch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Problemstellung==&lt;br /&gt;
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. Das wiederum benötigt jede Menge Strom. Unser Auge wiederum nimmt eine Bewegung ab ca. 24 Bildern pro Sekunde [[Framerate#24_fps_Mythos|theoretisch]] als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit sehr hohen [[FPS]] läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung.&lt;br /&gt;
Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten.&lt;br /&gt;
Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat.&lt;br /&gt;
Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss, andere dinge machen lässt.&lt;br /&gt;
Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst.&lt;br /&gt;
Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.&lt;br /&gt;
&lt;br /&gt;
==Ansatz==&lt;br /&gt;
&lt;br /&gt;
===Die naive Lösung===&lt;br /&gt;
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der &amp;quot;Sleep&amp;quot; Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, dass das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 10FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisierten Wert entfernen.&lt;br /&gt;
&lt;br /&gt;
===Die intelligente Lösung===&lt;br /&gt;
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.&lt;br /&gt;
&lt;br /&gt;
==Implementierung==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  FMaximumFrameRate: double;&lt;br /&gt;
  FLastSleep: double = 0;&lt;br /&gt;
&lt;br /&gt;
procedure LimitFrameRate(atd: double); //&amp;quot;atd&amp;quot; ist die Zeitdifferenz zwischen zwei Frames - inklusive der &amp;quot;Sleeptime&amp;quot;&lt;br /&gt;
var&lt;br /&gt;
  sleeptime: Double;&lt;br /&gt;
begin&lt;br /&gt;
  sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep);&lt;br /&gt;
  if sleeptime &amp;gt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden &lt;br /&gt;
    Sleep(trunc(sleeptime));&lt;br /&gt;
    FLastSleep := sleeptime;&lt;br /&gt;
  end else&lt;br /&gt;
    FLastSleep := 0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Genauigkeit und zuverlässigkeit von Framebeschränkungen==&lt;br /&gt;
===Zuverlässigkeit===&lt;br /&gt;
Wenn man mit hilfe der Funktion Sleep den Prozess pausiert, erwartet man das dieser auch so lange wie angegeben pausiert.&lt;br /&gt;
Dies ist leider nicht der Fall.&lt;br /&gt;
Sleep ruft die System Funktion für Sleep auf, welche bei Windows Milisekunden und Unix basierte Betriebssysteme Microsekunden an nimmt.&lt;br /&gt;
Allerdings bedeutet dies noch nicht, dass das Betriebssystem auch wirklich so genau ist, denn dies hängt von mehreren Faktoren ab.&lt;br /&gt;
Die Prozess Sheduler, die für das schlafen legen und wieder aufwäcken zuständig sind haben Gemeinsamkeiten.&lt;br /&gt;
Jeder Prozess hat eine Priorität, die den Sheduler erlaubt mehr Zeit ein zu räumen.&lt;br /&gt;
Die meisten Process Sheduler arbeiten mit Time-Slices/Time-Windows, welche den Prozessen zugewiesen werden.&lt;br /&gt;
Unter Windows hat ein Prozess, welcher mit normaler Priorität erzeugt wird ein 16ms Time-Slice zur verfügung, danach legt der Sheduler den Prozess schlafen und wechselt den zu dem folgendem Prozesscontext.&lt;br /&gt;
Dies bedeutet auch, dass ein Sleep von 16ms Fatal wäre, da im Idealfall der Prozess im nächsten Slice wieder dran wäre und weil er noch schläft, kann er nicht mehr die ganzen 16ms vom Time-Slice nutzen, bzw. auch noch übergangen werden und den Time-Slice nicht bekommt.&lt;br /&gt;
Man kann die Process Priorität mit der Betriebssystem API erhöhen und so nimmt die Laufzeit und auch Sleep Genauigkeit zu.&lt;br /&gt;
Es ist also zu empfehlen, die Prozess Priorität zu erhöhen, weil die Genauigkeit von Sleep zu nimmt.&lt;br /&gt;
&lt;br /&gt;
===Genauigkeit===&lt;br /&gt;
Wie schon erwähnt, ist die Genauigkeit der Sleep Funktionen nicht genau und es gibt keine Garantie für die wiederaufnahme des Prozess.&lt;br /&gt;
Wenn man also weniger als 16ms Sleep erreichen will, dann ist man unter Unix mit usleep auf der sicheren Seite aber Windows liefert dann alternative Lösungen.&lt;br /&gt;
Man kann z.B. ein MediaTimer erzeugen und diesen für die Render-Loop einsetzen, die Media Timer API ist für höhere Präzision ausgelegt.&lt;br /&gt;
Möchte man eine Präzision von 1ms oder weniger kann man auf Sleep(0) setzen.&lt;br /&gt;
Sleep und usleep verhalten sich bei 0 als Wartezeit gleich, der Prozess gibt sofort die Kontrolle an den Sheduler, dieser Prüft, ob ein anderer Prozess auf den Logischen Kern, wo der Prozess/Prozess-Thread läuft, laufen will und wechselt erst dann auf diesen für die '''restliche Zeit''', für den aktuelle Time Slice.&lt;br /&gt;
Wenn der andere Prozess durch ist, dann wird er entsprechend niederer in der Ausführungsliste gestuft und im kommenden Slice ist die Wahrscheinlichkeit, dass der eigene Prozess wieder läuft viel höher.&lt;br /&gt;
Sollte kein anderer Prozess auf den Kern laufen wollen, dann springt der Sleep Aufruf wieder zurück und arbeitet für die restliche Zeit.&lt;br /&gt;
Dies kann dann auf Systemen, wo leerlauf ist zu hoher CPU Last führen und das ist kontraproduktiv für Mobile Geräte.&lt;br /&gt;
Daher ist es besser sich für Rendering auf vsync zu verlassen.&lt;br /&gt;
Die beste Lösung ist ein Thread für das render ab zu stellen und vsync für den Renderkontext zu aktivieren.&lt;br /&gt;
[[SwapBuffers]] wird nun bei jedem Aufruf warten, bis der Monitor den nächsten Time-Slice erreicht hat, wechselt Back- und Fron-Buffer, der neue Back-Buffer wird zur Darstellung gebracht und die Funktion kehrt zurück.&lt;br /&gt;
Der [[Render_Thread|Render Thread]] wird nun M mal die Sekunde durch laufen, wobei M für die aktuelle Monitor Frequenz(aF) steht bzw. darunter, wenn das Rendern länger dauert als 1000ms / aF dauert.&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
[[Framecounter]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Framerate]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Render_Thread|Render Thread]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26244</id>
		<title>Frameratenbegrenzung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26244"/>
				<updated>2014-06-07T16:23:15Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Siehe auch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Problemstellung==&lt;br /&gt;
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. Das wiederum benötigt jede Menge Strom. Unser Auge wiederum nimmt eine Bewegung ab ca. 24 Bildern pro Sekunde [[Framerate#24_fps_Mythos|theoretisch]] als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit sehr hohen [[FPS]] läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung.&lt;br /&gt;
Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten.&lt;br /&gt;
Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat.&lt;br /&gt;
Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss, andere dinge machen lässt.&lt;br /&gt;
Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst.&lt;br /&gt;
Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.&lt;br /&gt;
&lt;br /&gt;
==Ansatz==&lt;br /&gt;
&lt;br /&gt;
===Die naive Lösung===&lt;br /&gt;
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der &amp;quot;Sleep&amp;quot; Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, dass das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 10FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisierten Wert entfernen.&lt;br /&gt;
&lt;br /&gt;
===Die intelligente Lösung===&lt;br /&gt;
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.&lt;br /&gt;
&lt;br /&gt;
==Implementierung==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  FMaximumFrameRate: double;&lt;br /&gt;
  FLastSleep: double = 0;&lt;br /&gt;
&lt;br /&gt;
procedure LimitFrameRate(atd: double); //&amp;quot;atd&amp;quot; ist die Zeitdifferenz zwischen zwei Frames - inklusive der &amp;quot;Sleeptime&amp;quot;&lt;br /&gt;
var&lt;br /&gt;
  sleeptime: Double;&lt;br /&gt;
begin&lt;br /&gt;
  sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep);&lt;br /&gt;
  if sleeptime &amp;gt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden &lt;br /&gt;
    Sleep(trunc(sleeptime));&lt;br /&gt;
    FLastSleep := sleeptime;&lt;br /&gt;
  end else&lt;br /&gt;
    FLastSleep := 0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Genauigkeit und zuverlässigkeit von Framebeschränkungen==&lt;br /&gt;
===Zuverlässigkeit===&lt;br /&gt;
Wenn man mit hilfe der Funktion Sleep den Prozess pausiert, erwartet man das dieser auch so lange wie angegeben pausiert.&lt;br /&gt;
Dies ist leider nicht der Fall.&lt;br /&gt;
Sleep ruft die System Funktion für Sleep auf, welche bei Windows Milisekunden und Unix basierte Betriebssysteme Microsekunden an nimmt.&lt;br /&gt;
Allerdings bedeutet dies noch nicht, dass das Betriebssystem auch wirklich so genau ist, denn dies hängt von mehreren Faktoren ab.&lt;br /&gt;
Die Prozess Sheduler, die für das schlafen legen und wieder aufwäcken zuständig sind haben Gemeinsamkeiten.&lt;br /&gt;
Jeder Prozess hat eine Priorität, die den Sheduler erlaubt mehr Zeit ein zu räumen.&lt;br /&gt;
Die meisten Process Sheduler arbeiten mit Time-Slices/Time-Windows, welche den Prozessen zugewiesen werden.&lt;br /&gt;
Unter Windows hat ein Prozess, welcher mit normaler Priorität erzeugt wird ein 16ms Time-Slice zur verfügung, danach legt der Sheduler den Prozess schlafen und wechselt den zu dem folgendem Prozesscontext.&lt;br /&gt;
Dies bedeutet auch, dass ein Sleep von 16ms Fatal wäre, da im Idealfall der Prozess im nächsten Slice wieder dran wäre und weil er noch schläft, kann er nicht mehr die ganzen 16ms vom Time-Slice nutzen, bzw. auch noch übergangen werden und den Time-Slice nicht bekommt.&lt;br /&gt;
Man kann die Process Priorität mit der Betriebssystem API erhöhen und so nimmt die Laufzeit und auch Sleep Genauigkeit zu.&lt;br /&gt;
Es ist also zu empfehlen, die Prozess Priorität zu erhöhen, weil die Genauigkeit von Sleep zu nimmt.&lt;br /&gt;
&lt;br /&gt;
===Genauigkeit===&lt;br /&gt;
Wie schon erwähnt, ist die Genauigkeit der Sleep Funktionen nicht genau und es gibt keine Garantie für die wiederaufnahme des Prozess.&lt;br /&gt;
Wenn man also weniger als 16ms Sleep erreichen will, dann ist man unter Unix mit usleep auf der sicheren Seite aber Windows liefert dann alternative Lösungen.&lt;br /&gt;
Man kann z.B. ein MediaTimer erzeugen und diesen für die Render-Loop einsetzen, die Media Timer API ist für höhere Präzision ausgelegt.&lt;br /&gt;
Möchte man eine Präzision von 1ms oder weniger kann man auf Sleep(0) setzen.&lt;br /&gt;
Sleep und usleep verhalten sich bei 0 als Wartezeit gleich, der Prozess gibt sofort die Kontrolle an den Sheduler, dieser Prüft, ob ein anderer Prozess auf den Logischen Kern, wo der Prozess/Prozess-Thread läuft, laufen will und wechselt erst dann auf diesen für die '''restliche Zeit''', für den aktuelle Time Slice.&lt;br /&gt;
Wenn der andere Prozess durch ist, dann wird er entsprechend niederer in der Ausführungsliste gestuft und im kommenden Slice ist die Wahrscheinlichkeit, dass der eigene Prozess wieder läuft viel höher.&lt;br /&gt;
Sollte kein anderer Prozess auf den Kern laufen wollen, dann springt der Sleep Aufruf wieder zurück und arbeitet für die restliche Zeit.&lt;br /&gt;
Dies kann dann auf Systemen, wo leerlauf ist zu hoher CPU Last führen und das ist kontraproduktiv für Mobile Geräte.&lt;br /&gt;
Daher ist es besser sich für Rendering auf vsync zu verlassen.&lt;br /&gt;
Die beste Lösung ist ein Thread für das render ab zu stellen und vsync für den Renderkontext zu aktivieren.&lt;br /&gt;
[[SwapBuffers]] wird nun bei jedem Aufruf warten, bis der Monitor den nächsten Time-Slice erreicht hat, wechselt Back- und Fron-Buffer, der neue Back-Buffer wird zur Darstellung gebracht und die Funktion kehrt zurück.&lt;br /&gt;
Der [[Render_Thread|Render Thread]] wird nun M mal die Sekunde durch laufen, wobei M für die aktuelle Monitor Frequenz(aF) steht bzw. darunter, wenn das Rendern länger dauert als 1000ms / aF dauert.&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
[[Framecounter]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Framerate]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Render_Thread]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26243</id>
		<title>Frameratenbegrenzung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26243"/>
				<updated>2014-06-07T16:22:57Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Genauigkeit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Problemstellung==&lt;br /&gt;
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. Das wiederum benötigt jede Menge Strom. Unser Auge wiederum nimmt eine Bewegung ab ca. 24 Bildern pro Sekunde [[Framerate#24_fps_Mythos|theoretisch]] als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit sehr hohen [[FPS]] läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung.&lt;br /&gt;
Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten.&lt;br /&gt;
Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat.&lt;br /&gt;
Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss, andere dinge machen lässt.&lt;br /&gt;
Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst.&lt;br /&gt;
Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.&lt;br /&gt;
&lt;br /&gt;
==Ansatz==&lt;br /&gt;
&lt;br /&gt;
===Die naive Lösung===&lt;br /&gt;
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der &amp;quot;Sleep&amp;quot; Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, dass das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 10FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisierten Wert entfernen.&lt;br /&gt;
&lt;br /&gt;
===Die intelligente Lösung===&lt;br /&gt;
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.&lt;br /&gt;
&lt;br /&gt;
==Implementierung==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  FMaximumFrameRate: double;&lt;br /&gt;
  FLastSleep: double = 0;&lt;br /&gt;
&lt;br /&gt;
procedure LimitFrameRate(atd: double); //&amp;quot;atd&amp;quot; ist die Zeitdifferenz zwischen zwei Frames - inklusive der &amp;quot;Sleeptime&amp;quot;&lt;br /&gt;
var&lt;br /&gt;
  sleeptime: Double;&lt;br /&gt;
begin&lt;br /&gt;
  sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep);&lt;br /&gt;
  if sleeptime &amp;gt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden &lt;br /&gt;
    Sleep(trunc(sleeptime));&lt;br /&gt;
    FLastSleep := sleeptime;&lt;br /&gt;
  end else&lt;br /&gt;
    FLastSleep := 0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Genauigkeit und zuverlässigkeit von Framebeschränkungen==&lt;br /&gt;
===Zuverlässigkeit===&lt;br /&gt;
Wenn man mit hilfe der Funktion Sleep den Prozess pausiert, erwartet man das dieser auch so lange wie angegeben pausiert.&lt;br /&gt;
Dies ist leider nicht der Fall.&lt;br /&gt;
Sleep ruft die System Funktion für Sleep auf, welche bei Windows Milisekunden und Unix basierte Betriebssysteme Microsekunden an nimmt.&lt;br /&gt;
Allerdings bedeutet dies noch nicht, dass das Betriebssystem auch wirklich so genau ist, denn dies hängt von mehreren Faktoren ab.&lt;br /&gt;
Die Prozess Sheduler, die für das schlafen legen und wieder aufwäcken zuständig sind haben Gemeinsamkeiten.&lt;br /&gt;
Jeder Prozess hat eine Priorität, die den Sheduler erlaubt mehr Zeit ein zu räumen.&lt;br /&gt;
Die meisten Process Sheduler arbeiten mit Time-Slices/Time-Windows, welche den Prozessen zugewiesen werden.&lt;br /&gt;
Unter Windows hat ein Prozess, welcher mit normaler Priorität erzeugt wird ein 16ms Time-Slice zur verfügung, danach legt der Sheduler den Prozess schlafen und wechselt den zu dem folgendem Prozesscontext.&lt;br /&gt;
Dies bedeutet auch, dass ein Sleep von 16ms Fatal wäre, da im Idealfall der Prozess im nächsten Slice wieder dran wäre und weil er noch schläft, kann er nicht mehr die ganzen 16ms vom Time-Slice nutzen, bzw. auch noch übergangen werden und den Time-Slice nicht bekommt.&lt;br /&gt;
Man kann die Process Priorität mit der Betriebssystem API erhöhen und so nimmt die Laufzeit und auch Sleep Genauigkeit zu.&lt;br /&gt;
Es ist also zu empfehlen, die Prozess Priorität zu erhöhen, weil die Genauigkeit von Sleep zu nimmt.&lt;br /&gt;
&lt;br /&gt;
===Genauigkeit===&lt;br /&gt;
Wie schon erwähnt, ist die Genauigkeit der Sleep Funktionen nicht genau und es gibt keine Garantie für die wiederaufnahme des Prozess.&lt;br /&gt;
Wenn man also weniger als 16ms Sleep erreichen will, dann ist man unter Unix mit usleep auf der sicheren Seite aber Windows liefert dann alternative Lösungen.&lt;br /&gt;
Man kann z.B. ein MediaTimer erzeugen und diesen für die Render-Loop einsetzen, die Media Timer API ist für höhere Präzision ausgelegt.&lt;br /&gt;
Möchte man eine Präzision von 1ms oder weniger kann man auf Sleep(0) setzen.&lt;br /&gt;
Sleep und usleep verhalten sich bei 0 als Wartezeit gleich, der Prozess gibt sofort die Kontrolle an den Sheduler, dieser Prüft, ob ein anderer Prozess auf den Logischen Kern, wo der Prozess/Prozess-Thread läuft, laufen will und wechselt erst dann auf diesen für die '''restliche Zeit''', für den aktuelle Time Slice.&lt;br /&gt;
Wenn der andere Prozess durch ist, dann wird er entsprechend niederer in der Ausführungsliste gestuft und im kommenden Slice ist die Wahrscheinlichkeit, dass der eigene Prozess wieder läuft viel höher.&lt;br /&gt;
Sollte kein anderer Prozess auf den Kern laufen wollen, dann springt der Sleep Aufruf wieder zurück und arbeitet für die restliche Zeit.&lt;br /&gt;
Dies kann dann auf Systemen, wo leerlauf ist zu hoher CPU Last führen und das ist kontraproduktiv für Mobile Geräte.&lt;br /&gt;
Daher ist es besser sich für Rendering auf vsync zu verlassen.&lt;br /&gt;
Die beste Lösung ist ein Thread für das render ab zu stellen und vsync für den Renderkontext zu aktivieren.&lt;br /&gt;
[[SwapBuffers]] wird nun bei jedem Aufruf warten, bis der Monitor den nächsten Time-Slice erreicht hat, wechselt Back- und Fron-Buffer, der neue Back-Buffer wird zur Darstellung gebracht und die Funktion kehrt zurück.&lt;br /&gt;
Der [[Render_Thread|Render Thread]] wird nun M mal die Sekunde durch laufen, wobei M für die aktuelle Monitor Frequenz(aF) steht bzw. darunter, wenn das Rendern länger dauert als 1000ms / aF dauert.&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
[[Framecounter]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Framerate]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26242</id>
		<title>Render Thread</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Render_Thread&amp;diff=26242"/>
				<updated>2014-06-07T16:21:14Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: Die Seite wurde neu angelegt: „=Render Thread= Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung …“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Render Thread=&lt;br /&gt;
Ein Render Thread seperiert die Programm Logik von der Darstellungs Logik und erlaubt so eine Lockere Bindung, wiederverwendung bzw. Änderung von der jeweiligen Logik und unterschiedliche Frequenzen bei der Ausführung.&lt;br /&gt;
&lt;br /&gt;
Ein Render Thread bringt ein Problem mit sich, man muss ein Thread erzeugen und eine Kommunikation mit den zu rendernen Daten herstellen.&lt;br /&gt;
Hier gibt es 2 Prinzipien, 1. der Thread greift direkt auf die Logikdaten zu und interpretiert die Renderbefehle oder 2. die Logik gibt dem Thread die Renderbefehle.&lt;br /&gt;
&lt;br /&gt;
==Starke Bindung==&lt;br /&gt;
Die 1. Möglichkeit macht den Render Thread sehr mächtig und unflexibel, weil er stark an die Programmlogik gekoppelt wird und damit nicht mehr in anderen Programmen, mit anderer Logik, funktionieren kann aber dafür ist es einfach schnelle Ergebnisse zu erzielen und einfacher zu optimieren.&lt;br /&gt;
Der Render Thread greift auf Thread Safe Daten zu und kann anhand dieser die OpenGL Befehle erzeugen.&lt;br /&gt;
&lt;br /&gt;
==Schwache Bindung==&lt;br /&gt;
Die 2. Möglichkeit macht den Render Thread wiederverwendbar aber benötigt mehr Zeit für das Design, Entwickeln und Optimieren.&lt;br /&gt;
Der Render Thread nimmt ein Intermediate Befehlsliste entgegen und kann diese dann in OpenGL Befehle umsetzen.&lt;br /&gt;
Dabei kann man verschiedene Implementierungen machen, wie z.B. 2 Thread safe Queues für Front- und Back-Buffer, die geswapped werden oder Tripple Buffer.&lt;br /&gt;
Bei Tripple Buffer werden 2 Back-Buffer(B1,B2) und ein Front-Buffer(FB) erzeugt, der Front-Buffer wird von der Programmlogik befüllt und am Ende wird ein Swap angefordert.&lt;br /&gt;
Nun wird der Front-Buffer mit dem 1. Back-Buffer(B1) geswapped, sollte nun der Renderer durch sein, wird er B1 mit B2 austauschen und beginnt mit der verarbeitung von B1, während die Programmlogik FB und B2 swappen kann.&lt;br /&gt;
Der Sinn ist, dass nun Render Thread und Logik mit unterschiedlichen Frequenzen arbeiten können und immer ein aktueller vollständiger Stand verfügbar ist.&lt;br /&gt;
Mit dieser Variante muss man sich nur um Multithreading sichere Programmierung bei den 3 Queues kümmern.&lt;br /&gt;
Dies kann man auch Lösen, in dem man Lock-Free Queues benutzt.&lt;br /&gt;
Die Kunst bei diesem Prinzip ist, dass man ein möglichst kleines Kommunikations Protokoll entwickelt.&lt;br /&gt;
Je kleiner das Protokoll ist, des so mehr Code wird wieder verwendet, weniger Fehler können gemacht werden und schneller ist die Kommunikation.&lt;br /&gt;
&lt;br /&gt;
Hier ein paar Beispiele um die Unterschiede besser wieder zu geben.&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26241</id>
		<title>Frameratenbegrenzung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26241"/>
				<updated>2014-06-07T16:11:11Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Genauigkeit */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Problemstellung==&lt;br /&gt;
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. Das wiederum benötigt jede Menge Strom. Unser Auge wiederum nimmt eine Bewegung ab ca. 24 Bildern pro Sekunde [[Framerate#24_fps_Mythos|theoretisch]] als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit sehr hohen [[FPS]] läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung.&lt;br /&gt;
Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten.&lt;br /&gt;
Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat.&lt;br /&gt;
Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss, andere dinge machen lässt.&lt;br /&gt;
Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst.&lt;br /&gt;
Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.&lt;br /&gt;
&lt;br /&gt;
==Ansatz==&lt;br /&gt;
&lt;br /&gt;
===Die naive Lösung===&lt;br /&gt;
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der &amp;quot;Sleep&amp;quot; Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, dass das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 10FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisierten Wert entfernen.&lt;br /&gt;
&lt;br /&gt;
===Die intelligente Lösung===&lt;br /&gt;
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.&lt;br /&gt;
&lt;br /&gt;
==Implementierung==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  FMaximumFrameRate: double;&lt;br /&gt;
  FLastSleep: double = 0;&lt;br /&gt;
&lt;br /&gt;
procedure LimitFrameRate(atd: double); //&amp;quot;atd&amp;quot; ist die Zeitdifferenz zwischen zwei Frames - inklusive der &amp;quot;Sleeptime&amp;quot;&lt;br /&gt;
var&lt;br /&gt;
  sleeptime: Double;&lt;br /&gt;
begin&lt;br /&gt;
  sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep);&lt;br /&gt;
  if sleeptime &amp;gt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden &lt;br /&gt;
    Sleep(trunc(sleeptime));&lt;br /&gt;
    FLastSleep := sleeptime;&lt;br /&gt;
  end else&lt;br /&gt;
    FLastSleep := 0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Genauigkeit und zuverlässigkeit von Framebeschränkungen==&lt;br /&gt;
===Zuverlässigkeit===&lt;br /&gt;
Wenn man mit hilfe der Funktion Sleep den Prozess pausiert, erwartet man das dieser auch so lange wie angegeben pausiert.&lt;br /&gt;
Dies ist leider nicht der Fall.&lt;br /&gt;
Sleep ruft die System Funktion für Sleep auf, welche bei Windows Milisekunden und Unix basierte Betriebssysteme Microsekunden an nimmt.&lt;br /&gt;
Allerdings bedeutet dies noch nicht, dass das Betriebssystem auch wirklich so genau ist, denn dies hängt von mehreren Faktoren ab.&lt;br /&gt;
Die Prozess Sheduler, die für das schlafen legen und wieder aufwäcken zuständig sind haben Gemeinsamkeiten.&lt;br /&gt;
Jeder Prozess hat eine Priorität, die den Sheduler erlaubt mehr Zeit ein zu räumen.&lt;br /&gt;
Die meisten Process Sheduler arbeiten mit Time-Slices/Time-Windows, welche den Prozessen zugewiesen werden.&lt;br /&gt;
Unter Windows hat ein Prozess, welcher mit normaler Priorität erzeugt wird ein 16ms Time-Slice zur verfügung, danach legt der Sheduler den Prozess schlafen und wechselt den zu dem folgendem Prozesscontext.&lt;br /&gt;
Dies bedeutet auch, dass ein Sleep von 16ms Fatal wäre, da im Idealfall der Prozess im nächsten Slice wieder dran wäre und weil er noch schläft, kann er nicht mehr die ganzen 16ms vom Time-Slice nutzen, bzw. auch noch übergangen werden und den Time-Slice nicht bekommt.&lt;br /&gt;
Man kann die Process Priorität mit der Betriebssystem API erhöhen und so nimmt die Laufzeit und auch Sleep Genauigkeit zu.&lt;br /&gt;
Es ist also zu empfehlen, die Prozess Priorität zu erhöhen, weil die Genauigkeit von Sleep zu nimmt.&lt;br /&gt;
&lt;br /&gt;
===Genauigkeit===&lt;br /&gt;
Wie schon erwähnt, ist die Genauigkeit der Sleep Funktionen nicht genau und es gibt keine Garantie für die wiederaufnahme des Prozess.&lt;br /&gt;
Wenn man also weniger als 16ms Sleep erreichen will, dann ist man unter Unix mit usleep auf der sicheren Seite aber Windows liefert dann alternative Lösungen.&lt;br /&gt;
Man kann z.B. ein MediaTimer erzeugen und diesen für die Render-Loop einsetzen, die Media Timer API ist für höhere Präzision ausgelegt.&lt;br /&gt;
Möchte man eine Präzision von 1ms oder weniger kann man auf Sleep(0) setzen.&lt;br /&gt;
Sleep und usleep verhalten sich bei 0 als Wartezeit gleich, der Prozess gibt sofort die Kontrolle an den Sheduler, dieser Prüft, ob ein anderer Prozess auf den Logischen Kern, wo der Prozess/Prozess-Thread läuft, laufen will und wechselt erst dann auf diesen für die '''restliche Zeit''', für den aktuelle Time Slice.&lt;br /&gt;
Wenn der andere Prozess durch ist, dann wird er entsprechend niederer in der Ausführungsliste gestuft und im kommenden Slice ist die Wahrscheinlichkeit, dass der eigene Prozess wieder läuft viel höher.&lt;br /&gt;
Sollte kein anderer Prozess auf den Kern laufen wollen, dann springt der Sleep Aufruf wieder zurück und arbeitet für die restliche Zeit.&lt;br /&gt;
Dies kann dann auf Systemen, wo leerlauf ist zu hoher CPU Last führen und das ist kontraproduktiv für Mobile Geräte.&lt;br /&gt;
Daher ist es besser sich für Rendering auf vsync zu verlassen.&lt;br /&gt;
Die beste Lösung ist ein Thread für das render ab zu stellen und vsync für den Renderkontext zu aktivieren.&lt;br /&gt;
[[SwapBuffers]] wird nun bei jedem Aufruf warten, bis der Monitor den nächsten Time-Slice erreicht hat, wechselt Back- und Fron-Buffer, der neue Back-Buffer wird zur Darstellung gebracht und die Funktion kehrt zurück.&lt;br /&gt;
Der Render Thread wird nun M mal die Sekunde durch laufen, wobei M für die aktuelle Monitor Frequenz(aF) steht bzw. darunter, wenn das Rendern länger dauert als 1000ms / aF dauert.&lt;br /&gt;
Mehr zu Render Threads findet ihr [[Render_Thread|hier]].&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
[[Framecounter]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Framerate]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26240</id>
		<title>Frameratenbegrenzung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26240"/>
				<updated>2014-06-07T16:05:29Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Problemstellung==&lt;br /&gt;
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. Das wiederum benötigt jede Menge Strom. Unser Auge wiederum nimmt eine Bewegung ab ca. 24 Bildern pro Sekunde [[Framerate#24_fps_Mythos|theoretisch]] als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit sehr hohen [[FPS]] läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung.&lt;br /&gt;
Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten.&lt;br /&gt;
Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat.&lt;br /&gt;
Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss, andere dinge machen lässt.&lt;br /&gt;
Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst.&lt;br /&gt;
Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.&lt;br /&gt;
&lt;br /&gt;
==Ansatz==&lt;br /&gt;
&lt;br /&gt;
===Die naive Lösung===&lt;br /&gt;
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der &amp;quot;Sleep&amp;quot; Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, dass das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 10FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisierten Wert entfernen.&lt;br /&gt;
&lt;br /&gt;
===Die intelligente Lösung===&lt;br /&gt;
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.&lt;br /&gt;
&lt;br /&gt;
==Implementierung==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  FMaximumFrameRate: double;&lt;br /&gt;
  FLastSleep: double = 0;&lt;br /&gt;
&lt;br /&gt;
procedure LimitFrameRate(atd: double); //&amp;quot;atd&amp;quot; ist die Zeitdifferenz zwischen zwei Frames - inklusive der &amp;quot;Sleeptime&amp;quot;&lt;br /&gt;
var&lt;br /&gt;
  sleeptime: Double;&lt;br /&gt;
begin&lt;br /&gt;
  sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep);&lt;br /&gt;
  if sleeptime &amp;gt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden &lt;br /&gt;
    Sleep(trunc(sleeptime));&lt;br /&gt;
    FLastSleep := sleeptime;&lt;br /&gt;
  end else&lt;br /&gt;
    FLastSleep := 0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Genauigkeit und zuverlässigkeit von Framebeschränkungen==&lt;br /&gt;
===Zuverlässigkeit===&lt;br /&gt;
Wenn man mit hilfe der Funktion Sleep den Prozess pausiert, erwartet man das dieser auch so lange wie angegeben pausiert.&lt;br /&gt;
Dies ist leider nicht der Fall.&lt;br /&gt;
Sleep ruft die System Funktion für Sleep auf, welche bei Windows Milisekunden und Unix basierte Betriebssysteme Microsekunden an nimmt.&lt;br /&gt;
Allerdings bedeutet dies noch nicht, dass das Betriebssystem auch wirklich so genau ist, denn dies hängt von mehreren Faktoren ab.&lt;br /&gt;
Die Prozess Sheduler, die für das schlafen legen und wieder aufwäcken zuständig sind haben Gemeinsamkeiten.&lt;br /&gt;
Jeder Prozess hat eine Priorität, die den Sheduler erlaubt mehr Zeit ein zu räumen.&lt;br /&gt;
Die meisten Process Sheduler arbeiten mit Time-Slices/Time-Windows, welche den Prozessen zugewiesen werden.&lt;br /&gt;
Unter Windows hat ein Prozess, welcher mit normaler Priorität erzeugt wird ein 16ms Time-Slice zur verfügung, danach legt der Sheduler den Prozess schlafen und wechselt den zu dem folgendem Prozesscontext.&lt;br /&gt;
Dies bedeutet auch, dass ein Sleep von 16ms Fatal wäre, da im Idealfall der Prozess im nächsten Slice wieder dran wäre und weil er noch schläft, kann er nicht mehr die ganzen 16ms vom Time-Slice nutzen, bzw. auch noch übergangen werden und den Time-Slice nicht bekommt.&lt;br /&gt;
Man kann die Process Priorität mit der Betriebssystem API erhöhen und so nimmt die Laufzeit und auch Sleep Genauigkeit zu.&lt;br /&gt;
Es ist also zu empfehlen, die Prozess Priorität zu erhöhen, weil die Genauigkeit von Sleep zu nimmt.&lt;br /&gt;
&lt;br /&gt;
===Genauigkeit===&lt;br /&gt;
Wie schon erwähnt, ist die Genauigkeit der Sleep Funktionen nicht genau und es gibt keine Garantie für die wiederaufnahme des Prozess.&lt;br /&gt;
Wenn man also weniger als 16ms Sleep erreichen will, dann ist man unter Unix mit usleep auf der sicheren Seite aber Windows liefert dann alternative Lösungen.&lt;br /&gt;
Man kann z.B. ein MediaTimer erzeugen und diesen für die Render-Loop einsetzen, die Media Timer API ist für höhere Präzision ausgelegt.&lt;br /&gt;
Möchte man eine Präzision von 1ms oder weniger kann man auf Sleep(0) setzen.&lt;br /&gt;
Sleep und usleep verhalten sich bei 0 als Wartezeit gleich, der Prozess gibt sofort die Kontrolle an den Sheduler, dieser Prüft, ob ein anderer Prozess auf den Logischen Kern, wo der Prozess/Prozess-Thread läuft, laufen will und wechselt erst dann auf diesen für die '''restliche Zeit''', für den aktuelle Time Slice.&lt;br /&gt;
Wenn der andere Prozess durch ist, dann wird er entsprechend niederer in der Ausführungsliste gestuft und im kommenden Slice ist die Wahrscheinlichkeit, dass der eigene Prozess wieder läuft viel höher.&lt;br /&gt;
Sollte kein anderer Prozess auf den Kern laufen wollen, dann springt der Sleep Aufruf wieder zurück und arbeitet für die restliche Zeit.&lt;br /&gt;
Dies kann dann auf Systemen, wo leerlauf ist zu hoher CPU Last führen und das ist kontraproduktiv für Mobile Geräte.&lt;br /&gt;
Daher ist es besser sich für Rendering auf vsync zu verlassen.&lt;br /&gt;
Die beste Lösung ist ein Thread für das render ab zu stellen und vsync für den Renderkontext zu aktivieren.&lt;br /&gt;
[[glSwapBuffer]] wird nun bei jedem Aufruf warten, bis der Monitor den nächsten Time-Slice erreicht hat, wechselt Back- und Fron-Buffer, der neue Back-Buffer wird zur Darstellung gebracht und die Funktion kehrt zurück.&lt;br /&gt;
Der Render Thread wird nun M mal die Sekunde durch laufen, wobei M für die aktuelle Monitor Frequenz(aF) steht bzw. darunter, wenn das Rendern länger dauert als 1000ms / aF dauert.&lt;br /&gt;
Mehr zu Render Threads findet ihr [[Render_Thread|hier]].&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
[[Framecounter]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Framerate]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26239</id>
		<title>Frameratenbegrenzung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26239"/>
				<updated>2014-06-07T08:39:28Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Die naive Lösung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Problemstellung==&lt;br /&gt;
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. Das wiederum benötigt jede Menge Strom. Unser Auge wiederum nimmt eine Bewegung ab ca. 24 Bildern pro Sekunde [[Framerate#24_fps_Mythos|theoretisch]] als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit sehr hohen [[FPS]] läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung.&lt;br /&gt;
Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten.&lt;br /&gt;
Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat.&lt;br /&gt;
Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss, andere dinge machen lässt.&lt;br /&gt;
Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst.&lt;br /&gt;
Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.&lt;br /&gt;
&lt;br /&gt;
==Ansatz==&lt;br /&gt;
&lt;br /&gt;
===Die naive Lösung===&lt;br /&gt;
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der &amp;quot;Sleep&amp;quot; Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, dass das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 10FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisierten Wert entfernen.&lt;br /&gt;
&lt;br /&gt;
===Die intelligente Lösung===&lt;br /&gt;
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.&lt;br /&gt;
&lt;br /&gt;
==Implementierung==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  FMaximumFrameRate: double;&lt;br /&gt;
  FLastSleep: double = 0;&lt;br /&gt;
&lt;br /&gt;
procedure LimitFrameRate(atd: double); //&amp;quot;atd&amp;quot; ist die Zeitdifferenz zwischen zwei Frames - inklusive der &amp;quot;Sleeptime&amp;quot;&lt;br /&gt;
var&lt;br /&gt;
  sleeptime: Double;&lt;br /&gt;
begin&lt;br /&gt;
  sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep);&lt;br /&gt;
  if sleeptime &amp;gt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden &lt;br /&gt;
    Sleep(trunc(sleeptime));&lt;br /&gt;
    FLastSleep := sleeptime;&lt;br /&gt;
  end else&lt;br /&gt;
    FLastSleep := 0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
[[Framecounter]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Framerate]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26238</id>
		<title>Frameratenbegrenzung</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Frameratenbegrenzung&amp;diff=26238"/>
				<updated>2014-06-07T08:36:02Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Problemstellung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Problemstellung==&lt;br /&gt;
Bei vielen 3D-Anwendungen erfolgt die Bildausgabe so schnell hintereinander, wie die Hardware dies ermöglicht. Da die CPU die Befehle erzeugen muss, um ein Frame zu rendern, benötigt diese Zeit auf der CPU und so entsteht bei hohen Frameraten entsprechend hohe Auslastung der CPU. Das wiederum benötigt jede Menge Strom. Unser Auge wiederum nimmt eine Bewegung ab ca. 24 Bildern pro Sekunde [[Framerate#24_fps_Mythos|theoretisch]] als flüssig wahr - es bringt also nicht sehr viel, wenn unsere Anwendung mit sehr hohen [[FPS]] läuft - wir bekommen davon sowieso nichts mit, außer niedriger Akkulaufzeit und hoher Stromrechnung.&lt;br /&gt;
Abhängig von den Lichtquellen, die in der Umgebung strahlen sollte sollte man bis zu 120Hz als maximale FPS wählen, darunter kann es sonnst zu flimmern, oder Jitter Effekten kommen, wenn man das Auge schnell bewegt. Dieses Phänomen kann man üblicherweise bei Leuchtstoffröhren in Büros beobachten.&lt;br /&gt;
Ein hoher Hertz(kurz Hz) Wert entspannt auch das Auge, so das es längere Zeiten vor dem Monitor ermöglicht, bevor der Augenapparat versagt und Zuckungen, Fokusprobleme und verzögertes Fokusieren als resultat zu folge hat.&lt;br /&gt;
Die Lösung für dieses Problem ist eine Frameratenbegrenzung, die die Bildwiederholrate auf einen gewissen Wert limitiert und unsere Anwendung in der Zeit, in der nichts getan werden muss, andere dinge machen lässt.&lt;br /&gt;
Diese Bildwiederholrate wird üblicherweise auf die aktuelle Monitor Frequenz gesetzt bzw. diese auch entsprechend angepasst.&lt;br /&gt;
Der Monitor ist das schwächste Glied in der Kette und die unterstützen Frequenzen gehen bis zu 120Hz, bzw. höher, wenn diese 3D fähig sind.&lt;br /&gt;
&lt;br /&gt;
==Ansatz==&lt;br /&gt;
&lt;br /&gt;
===Die naive Lösung===&lt;br /&gt;
Die einfachste Realisierung der Frameratenbegrenzung ist ein einfaches Hinzufügen der &amp;quot;Sleep&amp;quot; Anweisung in die Hauptschleife. Gehen wir von Sleep(5) aus, so haben wir eine Maximale Framerate von 200FPS. Diese Lösung ist jedoch etwas suboptimal. Gehen wir davon aus, dass das Zeichnen der Inhalte an sich schon 5 Millisekunden dauert, so haben wir nur noch eine Framerate von 100FPS. Auf einem älterem Rechner könnte diese Berechnung auch länger dauern und die erreichte Framerate sich daher noch mehr von unserem anvisierten Wert entfernen.&lt;br /&gt;
&lt;br /&gt;
===Die intelligente Lösung===&lt;br /&gt;
Schlauer ist es, von der Zeit, die unser Programm pausiert, die Dauer des Rendervorgangs abzuziehen. Dazu ist es nötig, die Zeit, die zwischen zwei Frames vergeht zu messen. Um die Schlafenszeit nicht in dieser Messung zu haben, müssen wir uns diese natürlich merken und vorher abziehen. Mit diesem Ansatz passt sich die CPU-Auslastung an die Leistung des Systems an: Auf einem High-End PC wird sie automatisch niedriger als auf einem Rechner aus dem letztem Jahrhundert - so gehört es sich schließlich auch.&lt;br /&gt;
&lt;br /&gt;
==Implementierung==&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  FMaximumFrameRate: double;&lt;br /&gt;
  FLastSleep: double = 0;&lt;br /&gt;
&lt;br /&gt;
procedure LimitFrameRate(atd: double); //&amp;quot;atd&amp;quot; ist die Zeitdifferenz zwischen zwei Frames - inklusive der &amp;quot;Sleeptime&amp;quot;&lt;br /&gt;
var&lt;br /&gt;
  sleeptime: Double;&lt;br /&gt;
begin&lt;br /&gt;
  sleeptime := 1000 / FMaximumFrameRate - (atd - FLastSleep);&lt;br /&gt;
  if sleeptime &amp;gt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    //statt sleep kann unter SDL auch SDL_Delay verwendet werden &lt;br /&gt;
    Sleep(trunc(sleeptime));&lt;br /&gt;
    FLastSleep := sleeptime;&lt;br /&gt;
  end else&lt;br /&gt;
    FLastSleep := 0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Siehe auch==&lt;br /&gt;
[[Framecounter]]&amp;lt;br&amp;gt;&lt;br /&gt;
[[Framerate]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Anleitung]] [[Kategorie:Technik_oder_Algorithmus]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Lineare_Algebra&amp;diff=24985</id>
		<title>Tutorial OpenGL3 Lineare Algebra</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Lineare_Algebra&amp;diff=24985"/>
				<updated>2010-10-24T11:33:01Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Unvollständig|Quaternion,Rechtschreibung und Grammatik sowie ein Inhaltscheck fehlen. Die einzelnen Matrizen müssen noch besser erklärt werden.}}&lt;br /&gt;
=Vorwort=&lt;br /&gt;
Lineare Algebra ist ein Teilgebiet der Mathematik und beschäftigt sich mit Vektorräumen.&lt;br /&gt;
Die für [[OpenGL]] wichtigen Unterbereiche sind Vektoren und Matrizen.&lt;br /&gt;
Der größte Teil der 3D-Programmierung beschäftigt sich mit linearer Algebra, daher sollte auch dieser Grundlage eine besondere Aufmerksamkeit gewidmet werden.&lt;br /&gt;
Sollte der Inhalt vielleicht zu viel für einmal sein, dann wäre es ratsam, ihn in mehreren Etappen zu bewältigen, aber es sollte auf jedenfall vollständig verstanden werden, bevor man sich ernsthaft mit OpenGL auseinandersetzen will.&lt;br /&gt;
&lt;br /&gt;
=Trigonometrie=&lt;br /&gt;
Da später in der Linearen Algebra auf die Trigonometrie zurückgegriffen wird, sollen als erstes die notwendigen Grundlagen in diesem Bereich beleuchtet werden.&lt;br /&gt;
&lt;br /&gt;
==Bogenmaß und Gradmaß==&lt;br /&gt;
Man unterscheidet bei der Darstellung eines Winkels zwischen Bogenmaß(rad) und Gradmaß(deg).&lt;br /&gt;
Das Bogenmaß wird durch die Konstante Pi beschrieben, wobei der Wertebereich von 0 bis 2*Pi geht.&lt;br /&gt;
Das Gradmaß ist eine Einteilung, welche von 0 bis 360° abgebildet wird.&lt;br /&gt;
0° sind 0, 90° sind 0.5*Pi, 180° sind Pi, 270° sind 2/3*Pi und 360° sind 2*Pi oder auch 0° und 0.&lt;br /&gt;
&lt;br /&gt;
Um vom Bogenmaß ins Gradmaß umzurechnen, kann man folgende Formel verwenden:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Lineare_Algebra_rad2deg.png]]&lt;br /&gt;
&lt;br /&gt;
Für die Umwandlung vom Bogenmaß ins Gradmaß gilt diese Formel:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
==Trigonometrische Funktionen==&lt;br /&gt;
Für das sinnvolle Arbeiten mit Winkelfunktionen benötigen wir einen Einheitskreis.&lt;br /&gt;
Dies ist ein Kreis, dessen Radius 1 ist und somit eine Reihe von Funktionen zulässt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:einheitsvektor.png]] &lt;br /&gt;
&lt;br /&gt;
Der Einheitskreis ist wie folgt beschriftet. In Blau sind die Bogenmaß Werte angegeben, in dunkelgrün die äquivalenten Werte der Kosinusfunktion und Orange ist der Winkel. Wenn man den Kosinus und Sinus von dem Winkel errechnet, dann erhält man den hellgrünen x- und roten y-Wert. Egal welchen Winkel man in der Sinus- und Kosinusfunktion einsetzt, der Wert wird nie größer 1 oder kleiner -1 werden. Aber halt, wieso?&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie im allgemeinen Dreieck==&lt;br /&gt;
Man unterscheidet in der Trigonometrie zwischen rechtwinkligen Dreiecken und allgemeinen Dreiecken.&lt;br /&gt;
Die allgemeinen Dreiecke sind allerdings für den weiteren Verlauf des Artikels wichtig und werden deswegen behandelt.&lt;br /&gt;
&lt;br /&gt;
===Sinus- und Kosinussatz===&lt;br /&gt;
Ein wichtige Gleichung, welche später wieder aufgegriffen werden wird, ist der Kosinussatz. &lt;br /&gt;
Doch zuvor sollte der Sinussatz genauer betrachtet werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:sinussatz.png]]&lt;br /&gt;
&lt;br /&gt;
Durch das Umstellen der Gleichungen kann man die einzelnen Winkel oder Seiten eines Dreiecks erhalten. Hierzu werden entweder zwei Seiten und ein Winkel oder zwei Winkel und eine Seite benötigt.&lt;br /&gt;
&lt;br /&gt;
Der Kosinussatz&lt;br /&gt;
&lt;br /&gt;
[[Datei:kosinussatz.png]]&lt;br /&gt;
&lt;br /&gt;
ermöglicht es, entweder aus drei gegebenen Seiten die Winkel auszurechnen oder aus zwei Seiten und ihrem Zwischenwinkel die gegenüberliegende Seite zu berechnen.&lt;br /&gt;
&lt;br /&gt;
===Eigenschaften und Formeln===&lt;br /&gt;
Es kann hilfreich sein, eine Sinusfunktion in eine Kosinusfunktion umzuwandeln oder umgekehrt. Hierzu benötigt man die Komplementärformeln, welche wie folgt aussehen:&lt;br /&gt;
&lt;br /&gt;
[[Datei:costosin_sintocos.png]]&lt;br /&gt;
&lt;br /&gt;
Um den Rückgabewert der Sinus- oder Kosinusfunktion in den Bogenmaß umzuwandeln, gibt es folgende Umkehrfunktionen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:umkehrfunktion_sin_cos_tan.png]]&lt;br /&gt;
&lt;br /&gt;
Es ist zu beachten, dass diese Werte im Bogenmaß zurückgeben und diese für das Gradmaß entsprechend umgerechnet werden müssen.&lt;br /&gt;
&lt;br /&gt;
=Vektor=&lt;br /&gt;
Ein Vektor kann mit einem Array oder einer Liste vergleicht werden, wenn man z.B. einen 3-dimensionalen Vektor meint, dann wäre es ein Array mit 3 Elementen.&lt;br /&gt;
Die übliche Schreibweise eines Vektors sieht wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:generischer_vektor.png]]&lt;br /&gt;
&lt;br /&gt;
Eine entsprechende Representation in C++ wäre z.B. folgende:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
  public:&lt;br /&gt;
    float m_Vec[4];&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenGL verwendet auf der Grafikkarte immer 4-dimensionale Vektoren, auch wenn nur 1 oder 3 Elemente benötigt werden. Die restlichen Elemente des Vektors werden dann mit 0 aufgefüllt. Vektoren werden in OpenGL in zwei Arten verwendet, als absoluter und als relativer Wert. Absolute Werte wären z.B. Positionen und Farbwerte, während relative Werte z.B. eine Transformation wäre. Der OpenGL-Vektor sieht wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
==Einheitsvektor==&lt;br /&gt;
Eine besondere Form eines Vektors ist der Einheitsvektor, welcher immer eine Länge von 1 hat. Der Einheitsvektor wird normalerweise als klein e gekennzeichnet.&lt;br /&gt;
&lt;br /&gt;
Die Berechnung eines Einheitsvektors wird später in der der Magnitude und Normalisierung Funktion näher erläutert. Einheitsvektoren sind als Normalen oder Richtungsvektoren in OpenGL im Einsatz und bilden die Basis für Rotationen.&lt;br /&gt;
&lt;br /&gt;
==Addition==&lt;br /&gt;
[[Datei:addition_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:addition_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Die Addition wird komponentenweise ausgeführt, was bedeutet, man kann sich eine Addition von Vektoren als eine Addition von jeden einzelnen Element mit dem entsprechenden Element im anderem Vektor vorstellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:addition_vektor_visual.png]]&lt;br /&gt;
&lt;br /&gt;
Die Addition von Vektoren kann man sich sehr einfach vorstellen, indem man die einzelnen Vektoren als Bewegungsbefehle sieht. Wenn man also 2 Schritte vorwärts, einen Schritt seitwärts laufen soll und danach ein halben Schritt vorwärts und ein Schritt seitwärts, dann kann man diese beiden Befehle auch zu einem Befehl zusammen fassen. Laufe 2 1/2 Schritte vorwärts und 2 Schritte seitwärts und wir stehen am gleichen Punkt und dieser Befehl wäre dann unser Ergebnis Vektor c.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Addition(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]+b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Subtraktion==&lt;br /&gt;
[[Datei:subtraktion_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:subtraktion_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Hier gilt gleiches wie bei der Addition, nur dass komponentenweise subtrahiert wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Subtraktion_vektor_visual.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Subtraktion eines Vektors wendet man den ersten Befehl an und läuft z.B. 2 Schritte nach vorne und einen seitwärts, dann wendet man den 2. Schritt an aber wechselt das Vorzeichen jeder einzelnen Komponente. Also wird eine positive Komponente zu einer negativen und eine negative zu einer positiven. Wenn man also einen Schritt seitwärts, nach links, laufen soll, dann läuft man einen Schritt seitwärts, nach rechts, sowie vorwärts statt rückwärts. Man kann eine Subtraktion über eine Addition realisieren, wenn man jede Subtraktion, den rechten Vektor zuvor invertiert und dann addiert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Subtraktion(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]-b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Betrag==&lt;br /&gt;
[[Datei:magnitude_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Magnitude ist der Englische Begriff für die Berechnung des Betrags eines Vektors oder auch die Länge.&lt;br /&gt;
Die Länge des Vektors wird benötigt, wenn man einen Vektor normalisieren will oder feststellen möchte, ob ein Vektor ein Einheitsvektor ist. &lt;br /&gt;
&lt;br /&gt;
[[Datei:betrag_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Der Betrag eines Vektors kann über den Satz des Pythagoras ermittelt werden, welcher die Wurzel der Summe der Quadrate aller Komponenten ist.&lt;br /&gt;
Dies ist natürlich für wenige gut vorstellbar und daher hier mal eine bessere Erklärung. Ein Vektor kann in n Komponenten zerlegt werden, der 4 Komponenten Vektor von OpenGL in 4 Komponenten. Jede Komponente stellt eine Dimension dar, welche x,y,z und w sind. Pythagoras lernt man in der Schule im zweidimensionalen Raum kennen, also wie es im Abbild über diesen Text dargestellt ist. Die Regel besagt, das der Flächeninhalt einer Seite der Summe der anderen entspricht, also l²=x²+y².&lt;br /&gt;
Diese Flächen sind quadratisch, also hat jede Seite der Fläche die gleiche Kantenlänge. Wenn man die Quadratwurzel von der Fläche zieht, bekommt man also die Kantenlänge. Wenn man nun die Flächen von x,y,z und w summiert erhält man die Fläche l². Zieht man von l² die Quadratwurzel, dann hat man die Kantenlänge l von dem 4Komponenten Vektor, welche als Betrag oder Länge bezeichnet wird. Da bei einem Vektor w=0.0 gesetzt wird, hat diese keinen Einfluss auf diese Operation und wird in den Formeln und auch in der Regel nicht mit hingeschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
float Betrag(){&lt;br /&gt;
  float len=0.0;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    len+=this-&amp;gt;m_Vec[i]*this-&amp;gt;m_Vec[i];&lt;br /&gt;
  return sqrt(len);&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Skalarprodukt==&lt;br /&gt;
[[Datei:skalarprodukt_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Das Skalarprodukt erlaubt uns die Berechnung des Winkels zwischen 2 Vektoren. Hierfür müssen allerdings beide Vektoren normalisiert sein, also jeweils einen Betrag von 1 haben. Andernfalls muss dies noch nachträglich getan werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:skalarprodukt_vektor1.png]]&lt;br /&gt;
&lt;br /&gt;
Wenn die zwei Vektoren a und b vorliegen, sollte man davon ausgehen, dass der Betrag beider Vektoren jeweils 1 ist. Sollte es nicht der Fall sein, so wie im Bild über diesen Text, dann muss dies durch die Normalisierung nachgeholt werden. Dies passiert, indem man den Betrag beider Vektoren errechnet und dann diesen Komponentenweise mit dem Vektor dividiert. Die oben stehende Formel wird aus dem Kosinussatz abgeleitet und umgestellt. Daraus ergibt sich am Ende, dass die Summe der komponentenweise multiplizierten Vektoren a und b den Kosinus des Winkels ergibt. Es ist wichtig zu beachten, dass nicht der Winkel sondern der Kosinus des Winkels in c wieder zu finden ist. Wenn man den Winkel haben möchte, dann muss man den Arkuskosinus von c berechnen und das Ergebnis vom Bogenmaß ins Gradmaß umwandeln, um den Winkel (als Delta markiert) zu bekommen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
float Skalarprodukt(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  float alpha=0.0;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    alpha+=this-&amp;gt;m_Vec[i]*b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Kreuzprodukt==&lt;br /&gt;
[[Datei:kreuzprodukt_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Das Kreuzprodukt errechnet einen Vektor, der senkrecht zu den Vektoren a und b steht, wenn a und b den selben Ursprung haben. Dieses Verhalten wird genutzt, um die Normale einer Fläche zu errechnen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:kreuzprodukt_vektor1.png]]&lt;br /&gt;
&lt;br /&gt;
Der berechnete Vektor hat wie schon erwähnt die Eigenschaft, dass er senkrecht zu den Vektoren a und b ausgerichtet ist. Dies bedeutet, dass der Winkel zwischen dem berechnetem Vektor und a oder b immer 90° beträgt. Wenn a und b zwei von den drei Eckpunkten eines Dreiecks sind, dann zeigt der Vektor c senkrecht zum Dreieck und bildet den Richtungsvektor des Dreiecks. Wenn man nun noch diesen Vektor normalisiert, dann erhält man die Flächenormale. Diese hat den Betrag 1 und wird für verschiedene Rendertechniken, sowie Physikberechnungen benötigt.&lt;br /&gt;
Wenn z.B. ein Lichtstrahl solch ein Dreieck schneidet, dann kann man mit Hilfe des Vektors (vom Lichstrahl) und der Normale (der Fläche) den Reflektionsvektor berechnen und somit sagen, in welche Richtung sich das Licht weiter bewegen würde.&lt;br /&gt;
Es ist zu beachten, dass die Reihenfolge, in der man beide Vektoren multipliziert, einen Einfluss auf die Richtung, in die c zeigt, hat.&lt;br /&gt;
Wenn man a und b tauscht, dann wechseln die Vorzeichen aller Komponenten von c.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
TVector4Float Kreuzprodukt(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  unsigned int next,nextnext;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
  {&lt;br /&gt;
    next=(i+1) % 4;//i+1 Modulo 4&lt;br /&gt;
    nextnext=(i+2) % 4;&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[next]*b.m_Vec[nextnext]-this-&amp;gt;m_Vec[nextnext]*b.m_Vec[next];&lt;br /&gt;
  }&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Normalisieren==&lt;br /&gt;
[[Datei:normalisieren_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Normalisierung wird der Betrag eines Vektors mit dem Vektor dividiert und man erhält einen Vektor, der in die gleiche Richtung zeigt, aber auf Länge 1 skaliert ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Normalisieren(){&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  c=(*this)/this-&amp;gt;Betrag();&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Matrix=&lt;br /&gt;
Eine Matrix kann man sich als 2-dimensionalen Array mit n und m Länge vorstellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:generische_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
OpenGL verwendet 4x4 große Matrizen und kann aus 4 Vektoren mit einer Länge von 4 konstruiert werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
  protected: &lt;br /&gt;
    TVector4Float m_Matrix[4]; //Erlaubt uns das Nutzen von der eigenen Vektorklasse.&lt;br /&gt;
    float m_Array[16]; //für die LoadMatrix Funktion von OpenGL&lt;br /&gt;
  public:&lt;br /&gt;
    TVector4Float&amp;amp; Vektor(int Index)//Gibt eine Referenz vom Vektor zurück, was wie ein Pointer ist, aber 100% auf ein Speicher zeigt, der existiert.&lt;br /&gt;
    { &lt;br /&gt;
      return m_Matrix[Index]; &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    T* GetMatrix1DArray()//Liefert den Pointer von der m_Array variable zurück.&lt;br /&gt;
    { &lt;br /&gt;
      //Überträgt die Daten von den einzelnen Vektoren in die OpenGL-kompatible Matrix(m_Array).&lt;br /&gt;
      for (int i=0;i&amp;lt;4;i++)&lt;br /&gt;
        memcpy(&amp;amp;m_Array[i*4],&amp;amp;m_Matrix[i][0],16);&lt;br /&gt;
      return &amp;amp;m_Array[0];//Gibt den Pointer auf m_Array zurück.&lt;br /&gt;
    }&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für Matrizen brauchen wir nicht so viele Funktionen wie bei Vektoren, um genau zu sein brauchen wir nur zwei Operationen. Diese Operationen sind das Transponieren und die Multiplikation.&lt;br /&gt;
Bei der Matrix benötigen wir einige Konstruktionsfunktionen und zwar Identity, Translate, Rotate  und Scale Matrix. Diese Matrizen machen die ganze Arbeit für uns, wenn man sich in einem 3D-Raum bewegen möchte, welcher als Modelview Matrix abgebildet wird.&lt;br /&gt;
&lt;br /&gt;
==Transponieren==&lt;br /&gt;
[[Datei:transponieren_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
Transponieren wird durch ein großes T über der Matrix dargestellt. Diese Funktion tauscht die Werte einer Matrix miteinander aus, so das aus einer Spalten konstruierten Matrix eine zeilenweise konstruierte Matrix wird. Diese Funktion kann hilfreich sein, wenn man zwischen Direct3D und OpenGL Daten austauschen will, denn nicht jeder nutzt spaltenorientierte Matrizen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_matrix.png‎]][[Datei:d3d_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Transponieren()&lt;br /&gt;
{ &lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[1],m_Matrix.Vektor(1).m_Vec[0]); //swap kopiert b in tmp, kopiert a in b und tmp in a&lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[2],m_Matrix.Vektor(2).m_Vec[0]); &lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[3],m_Matrix.Vektor(3).m_Vec[0]); &lt;br /&gt;
&lt;br /&gt;
  swap(m_Matrix.Vektor(1).m_Vec[2],m_Matrix.Vektor(2).m_Vec[1]); &lt;br /&gt;
  swap(m_Matrix.Vektor(1).m_Vec[3],m_Matrix.Vektor(3).m_Vec[1]); &lt;br /&gt;
&lt;br /&gt;
  swap(m_Matrix.Vektor(2).m_Vec[3],m_Matrix.Vektor(3).m_Vec[2]); &lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Multiplikation==&lt;br /&gt;
Multiplikation ist die wichtigste Operation bei Matrizen, wenn wir uns mit OpenGL beschäftigen.&lt;br /&gt;
Dies liegt daran, dass OpenGL zwei verschiedene Matrizen verwendet, um Vektoren in Bildschirmkoordinaten umzuwandeln. Damit dies funktioniert muss jeder Vektor mit diesen Matrizen jeweils multipliziert werden. Um eine Matrix zu manipulieren, wird diese mit einer konstruierten Matrix multipliziert. Diese Operation die ist meistausgeführte Operation sowohl in der OpenGL-Pipeline als auch in einem Spiel. Seit OpenGL3 gibt es kein Matrizensupport mehr, was bedeutet, dass man diese selber implementieren muss und dann die fertigen Matrizen an OpenGL übergibt. Die lässt viel Raum für Optimierung und kann somit ein OpenGL3-Programm schneller machen als ein OpenGL2-Programm, wenn man zuvor die glTranslate,glRotate und weiteren Funktionen verwendet hat. Es ist also ratsam sich eine sehr performante Bibliothek zu laden oder mit einem Performance Analyzer bewaffnet den eigenen Code zu optimieren.&lt;br /&gt;
&lt;br /&gt;
===Multiplikation mit einem Vektor===&lt;br /&gt;
[[Datei:multiplikation_matrix_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:multiplikation_matrix_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Um eine Matrix mit einem Vektor zu multiplizieren, braucht man man nur den Vektor[n] von der Matrix mit der Komponente[n] von dem Vektor multiplizieren und die resultierenden Vektoren anschließend addieren. Hierbei wird also ein Vektor mit einer einzelnen Komponente multipliziert, was weiter oben bei den Vektoren erklärt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Multipliziere(TVector4Float V) &lt;br /&gt;
{ &lt;br /&gt;
  TVector4Float v=m_Matrix.Vektor(0)*V.m_Vec[0]+m_Matrix.Vektor(1)*V.m_Vec[1]+m_Matrix.Vektor(2)*V.m_Vec[2]+m_Matrix.Vektor(3)*V.m_Vec[3];&lt;br /&gt;
  return v; &lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Multiplikation mit einer Matrix===&lt;br /&gt;
[[Datei:multiplikation_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:multiplikation_matrix1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Es sieht recht aufwändig aus, allerdings kann man es dank der vorigen Matrix-Vektor-Multiplikation auf ein recht übersichtliches Maß runterstreichen. Man braucht dann nur noch die Matrix a jeweils mit einem der Vektoren von Matrix b multiplizieren und hat die Matrix-Matrix-Multiplikation erledigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
TMatrix4x4Float Multiplikation(TMatrix4x4Float M) &lt;br /&gt;
{ &lt;br /&gt;
  TMatrix4x4Float M1((*this)*M.Vektor(0)), (*this)*M.Vektor(1), (*this)*M.Vektor(2), (*this)*M.Vektor(3)); &lt;br /&gt;
  return M1;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Konstruieren von Matrizen=&lt;br /&gt;
&lt;br /&gt;
==Einheitsmatrix==&lt;br /&gt;
Die Einheitsmatrix (engl. ''identity matrix'') ist die Initialisierungsmatrix, mit der alle Matrizen belegt werden.&lt;br /&gt;
Diese ist recht einfach und hat denn Sinn, dass bei einer Multiplikation immer der Wert herauskommt, mit dem diese multipliziert wurde.&lt;br /&gt;
Wer aufmerksam gelesen hat, der wird nun an Einheitsvektoren denken und liegt richtig.&lt;br /&gt;
Aufgrund der Beschaffenheit einer Matrix benötigen wir in jeder Reihe und Spalte jeweils ein Element, welches den Wert 1 annimmt und die restlichen nehmen den Wert 0 an. Die sieht dann wie folgt aus:&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
static const TVector4Float Identity[4];//Statische Variable, welche nur einmal existiert.&lt;br /&gt;
&lt;br /&gt;
void LadeIdentity()&lt;br /&gt;
{&lt;br /&gt;
  for (int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    m_Matrix.Vektor(i)=Identity.m_Vec[i];&lt;br /&gt;
}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
TVector4Float TMatrix4x4Float::Identity[4]={TVector4Float(1.0,0.0,0.0,0.0),TVector4Float(0.0,1.0,0.0,0.0),TVector4Float(0.0,0.0,1.0,0.0),TVector4Float(0.0,0.0,0.0,1.0)};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Translation==&lt;br /&gt;
Wenn man einen Vektor oder eine Matrix in x,y,z bewegen möchte, dann kann man dies mit einer Transformationsmatrix erreichen.&lt;br /&gt;
Dazu erstellt man eine Matrix, füllt sie mit der Einheitsmatrix und setzt dann x,y,z in der Matrix mit den zu x,y,z Werten, um die man etwas verschieben möchte.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Translate(float x,float y,float z)&lt;br /&gt;
{&lt;br /&gt;
  TKar_Matrix&amp;lt;KAR_MATH_TYPE&amp;gt; m;&lt;br /&gt;
  m.Vektor(3).m_Vec[0]=x;&lt;br /&gt;
  m.Vektor(3).m_Vec[1]=y;&lt;br /&gt;
  m.Vektor(3).m_Vec[2]=z;&lt;br /&gt;
  (*this)*=m;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
==Rotation==&lt;br /&gt;
Das Bewegen auf den drei Achsen ist allerdings oft nicht ausreichend und deswegen gibt es auch eine Rotationsmatrix.&lt;br /&gt;
Die Rotationsmatrix wird durch drei Vektoren beschrieben, welche jeweils für die x-, y- und z-Achse zuständig sind.&lt;br /&gt;
Man kann die Rotation der einzelnen Achsen in einem Schritt erledigen oder in 3 einzelne aufteilen. Um die Rotationsmatrix besser zu verstehen, werden erst einmal alle Achsen einzeln betrachtet.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die Z-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_rotz.gif]][[Datei:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen-Einheitsvektor(3. Spalte=0.0, 0.0, 1.0, 0.0) bleibt bei der Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? Damit entspricht Z-Achsen-Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen-Einheitsvektor(1. Spalte=1.0, 0.0, 0.0 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen-Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;x = cos(ß)&lt;br /&gt;
y = sin(ß)&amp;lt;/source&amp;gt;&lt;br /&gt;
womit der Inhalt der ersten Spalte der Matrix kennen: (cos(ß), sin(ß), 0.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Dies kann man auch auf den Y-Achsen-Einheitsvektor(2. Spalte=0.0, 1.0, 0.0, 0.0) übertragen, man muss nur beachten, in welcher Weise man dafür x und y vertauschen muss:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;x = -sin(ß)&lt;br /&gt;
y = cos(ß)&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß), cos(ß), 0.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Nun kann man die Rotationsmatrix für die Rotation auf der Z-Achse beschreiben, die Matrix findet man am Anfang des Abschnittes.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die Y-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_roty.gif]][[Datei:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Die Berechnung der Matrix wird auf die gleiche Weise ermittelt wie bei der Berechnung der Rotationsmatrix für die Drehung um die Z-Achse.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die X-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_rotx.gif]][[Datei:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Rotation um alle Achsen mit einer Matrix===&lt;br /&gt;
&lt;br /&gt;
Es ist recht aufwändig für die CPU und für den Programmierer, immer drei Rotationen auszuführen, deswegen hat man diese auch zu einer einzigen Operation zusammengefasst. Die Matrizen werden einfach miteinander multipliziert und es kommt eine Rotationsmatrix heraus, welche drei Eingabeparameter benötigt, alpha, beta und gamma sind dabei die Winkel für X-,Y- und Z-Achse.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rotationsmatrix_3angle.png]]&lt;br /&gt;
&lt;br /&gt;
Eine weitere Möglichkeit, um eine Rotationsmatrix zu erstellen, wäre das Nutzen eines Richtungsvektors und eines Winkels. Hierbei wird der Winkel auf den Richtungsvektor angewendet, wenn man also als Vektor (1,0,0) verwendet, dann hat man eine Rotation auf der X-Achse, (0,1,0) Y-Achse und (0,0,1) für die Z-Achse. Man kann nun auch Vektoren wie (1,1,1) angeben, wobei die Funktion diesen Vektor dann normalisieren wird, damit er noch auf das Einheitskreis System funktioniert. Dieser Vektor ist nicht äquivalent mit dem Rotieren von X-,Y- und Z-Achse nacheinander. Der Vorteil hierbei liegt in der Kompaktheit des Codes und man kann auf Algorithmen zurückgreifen, die vor OpenGL3 entwickelt wurden, da der OpenGL-Treiber früher die Rotation über diese Variante implementiert hatte.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rotationsmatrix.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Rotiere(float w,float x,float y,float z)&lt;br /&gt;
{&lt;br /&gt;
  TMatrix4Float m;&lt;br /&gt;
  float rad=DegToRad(w);&lt;br /&gt;
  float c=cos(rad);&lt;br /&gt;
  float ic=1.0-c;&lt;br /&gt;
  float s=sin(rad);&lt;br /&gt;
  TVector4Float v(x,y,z,0.0);&lt;br /&gt;
  float mag=sqrt((v*v).Summe());&lt;br /&gt;
&lt;br /&gt;
  if (mag&amp;lt;=1.0e-4)&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  v.m_Vec[0]=x/mag;&lt;br /&gt;
  v.m_Vec[1]=y/mag;&lt;br /&gt;
  v.m_Vec[2]=z/mag;&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(0).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[0]*ic)+c;&lt;br /&gt;
  m.Vektor(0).m_Vec[1]=(v.m_Vec[0]*v.m_Vec[1]*ic)+(v.m_Vec[2]*s);&lt;br /&gt;
  m.Vektor(0).m_Vec[2]=(v.m_Vec[0]*v.m_Vec[2]*ic)-(v.m_Vec[1]*s);&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(1).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[1]*ic)-(v.m_Vec[2]*s);&lt;br /&gt;
  m.Vektor(1).m_Vec[1]=(v.m_Vec[1]*v.m_Vec[1]*ic)+c;&lt;br /&gt;
  m.Vektor(1).m_Vec[2]=(v.m_Vec[1]*v.m_Vec[2]*ic)+(v.m_Vec[0]*s);&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(2).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[2]*ic)+(v.m_Vec[1]*s);&lt;br /&gt;
  m.Vektor(2).m_Vec[1]=(v.m_Vec[1]*v.m_Vec[2]*ic)-(v.m_Vec[0]*s);&lt;br /&gt;
  m.Vektor(2).m_Vec[2]=(v.m_Vec[2]*v.m_Vec[2]*ic)+c;&lt;br /&gt;
&lt;br /&gt;
  *this*=m;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Skalieren==&lt;br /&gt;
[[Bild:skalierungsmatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Die Skalierung ist eine sehr einfache Matrix, in der für die 1 des Einheitsvektors der entsprechende Skalierungsfaktor angegeben wird. Wenn man die Matrix mit einem Vektor multipliziert, dann werden X, Y und Z des Vektors mit den x- ,y- und z-Werten in der Skalierungsmatrix multipliziert und damit skaliert. Wenn man etwas größer machen will, dann wird der Wert entsprechend über 1.0 gewählt (z.B. 2.0 wäre doppelte Größe), und für eine Verkleinerung würde man ein Wert zwischen 1.0 und 0.0 wählen. Der Wert 0.5 würde z.B. eine Division durch 2 bedeuten, also 3*0.5=1.5. Der 4. Einheitsvektor wird so belassen, da wir diesen nur aus Kompatibilitätsgründen zu den 4-Komponenten-Vektoren benötigen.&lt;br /&gt;
&lt;br /&gt;
=Vom Vektor zur Bildschirmkoordinate=&lt;br /&gt;
Auf in den Endspurt!&lt;br /&gt;
Alle mathematischen Formeln und Funktionen benötigen wir, um die letzten zwei Punkte behandeln zu können.&lt;br /&gt;
Die Rede ist von der Umwandlung eines Vektors im 3D-Raum in den 2D-Raum, auf dem Bildschirm.&lt;br /&gt;
In Rahmen dieses Artikel wird nur auf die Transformation der Vektoren eingegangen und in einem späterem Artikel dann die weiteren Zwischenschritte zum Zeichnen einer Geometrie.&lt;br /&gt;
&lt;br /&gt;
==Modelview==&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Die Modelview kann man sich wie ein 3D-Unterraum vorstellen oder einer Transformation des Raumes. Die Modelview sorgt dafür, dass alle Vektoren, die mit dieser multipliziert werden, zu dieser Modelview ausgerichtet werden und die Modelview ist relativ zur Welt ausgerichtet. Dies bedeutet, wenn man für jedes Objekt eine Modelview erzeugt, dann kann dieses Objekt relativ zur Welt ausgerichtet werden, sobald man die Vektoren des Objektes mit der Modelview multipliziert. Wieso richtet man die Vektoren nicht gleich zur Welt aus, statt den Umweg über die Modelview Matrix zu gehen? Die Antwort ist schlicht &amp;quot;Optimierung&amp;quot;. Es wäre zu langsam, wenn man jeden Renderdurchgang jedes einzelne Vertex im Speicher lesen müsste, die neue Position berechnen, im Speicher updaten und in der Pipeline weiter zu arbeiten. Es ist auch speichereffizienter, da z.B. gleiche Objekte nur einmal in den Speicher abgelegt werden müssen und nur zwei unterschiedliche Modelview-Matrizen benötigt werden.&lt;br /&gt;
&lt;br /&gt;
Im rechten Bild kann man zwei aufeinanderfolgende Befehlsketten sehen, die Transformationen auf ein Objekt anwenden. Dieses Bild soll noch einmal verdeutlichen, dass das Anwenden von Befehlen auf eine Modelview-Matrix ''nicht'' kommutativ ist (a*b ist im Allgemeinen nicht das gleiche wie b*a).&lt;br /&gt;
&lt;br /&gt;
Während vor OpenGL3 die Modelview-Matrix von den OpenGL-Treibern verwaltet wurde, muss dies ab OpenGL3 vom Nutzer gemacht werden und auch das Aktualisieren in der Renderpipeline muss nun vom Entwickler übernommen werden. Wie dies funktioniert, wird in einem späteren Artikel erklärt. Es ist nur noch wichtig zu sagen, dass die GPU diese Matrix mit jeden Vertex multipliziert, der durch die Renderpipeline geschickt wird.&lt;br /&gt;
&lt;br /&gt;
==Normal-Matrix==&lt;br /&gt;
Die Normal-Matrix wurde vor OpenGL3 als [[gl_NormalMatrix]] automatisch berechnet, aber mit OpenGL3 ist auch diese aus dem Treiber entfernt worden.&lt;br /&gt;
Dies hat zur Folge, dass man diesen Schritt selber vollziehen muss, und aufgrund der Wichtigkeit dieser Matrix sollte man versuchen, diesen auch zu verinnerlichen.&lt;br /&gt;
Mit der gl_NormalMatrix kann man ein Normale von dem Texture-Space in den World-Space transformieren. &lt;br /&gt;
Dies ist wie bei der Multiplikation eines Vertex mit der [[gl_ModelViewMatrix]], nur dass die Konstruktion der gl_NormalMatrix andere Anforderungen hat und deswegen zusätzlich generiert wird.&lt;br /&gt;
&lt;br /&gt;
Eine Normale ist ein Vektor, welcher die Länge 1 hat, und repräsentiert die Flächenausrichtung.&lt;br /&gt;
Wenn man ein Dreieck auf der X,Y,Z Achse bewegt, dann hat dies keinen Einfluss auf die Werte einer Normale.&lt;br /&gt;
Sollte man ein Dreieck aber Rotieren oder Skalieren, dann verändern sich die Werte einer Normale, welcher den Unterschied zwischen gl_NormalMatrix und gl_ModelviewMatrix aus macht.&lt;br /&gt;
Es gibt einen Spezialfall beim Skalieren: sollte die Skalierung aller Dimensionen mit dem gleichen Wert durchgeführt werden, dann ändert sich die Normale nicht.&lt;br /&gt;
Die gl_NormalMatrix wird errechnet, indem man den Rotationsanteil der Modelview-Matrix in eine 3x3-Matrix kopiert, die Inverse errechnet und anschließend die Matrix transponiert.&lt;br /&gt;
&lt;br /&gt;
Um nun die Normale in den World-Space zu transformieren, kann man folgende Berechnung anwenden.&lt;br /&gt;
 Normal=normalize(gl_NormalMatrix*gl_Normal);&lt;br /&gt;
Nach der Multiplikation wird das Ergebnis normalisiert, da eine Normale immer die Länge 1.0 haben muss und durch die Möglichkeit, dass eine Skalierung mit unterschiedlichen Werte auf jeder Achse, dies sonst nicht gewährleistet wäre.&lt;br /&gt;
Aufgrund der Normalisierung entsteht der vorher erwähnte Sonderfall, bei dem eine Skalierung mit ein und dem selben Skalar keine Änderungen zur Folge hat.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
    protected:&lt;br /&gt;
        TMatrix3x3Float m_NormalMatrix;&lt;br /&gt;
    public:&lt;br /&gt;
        TMatrix3x3Float&amp;amp; NormalMatrix()&lt;br /&gt;
        {&lt;br /&gt;
          TMatrix3x3Float tnmat;&lt;br /&gt;
          float d;&lt;br /&gt;
          //Kopiere den Rotations- und Skalierungsanteil aus der Modelview-Matrix.&lt;br /&gt;
          for (unsigned int i=0;i&amp;lt;3;i++)&lt;br /&gt;
            for (unsigned int j=0;j&amp;lt;3;j++)&lt;br /&gt;
              m_NormalMatrix.Value[i*3+j]=this-&amp;gt;Value[i*4+j];&lt;br /&gt;
&lt;br /&gt;
          //Inverse mit Hilfe der Determinante berechnen und Transponieren in einem Schritt(im Fall der Rotationsmatrix&lt;br /&gt;
          //ist es nicht wichtig, in welcher Reihenfolge Transponieren und Determinieren geschehen.)&lt;br /&gt;
&lt;br /&gt;
          d=Determinant(m_NormalMatrix);&lt;br /&gt;
          tnmat[0]=m_NormalMatrix[4]*m_NormalMatrix[8]-m_NormalMatrix[5]*m_NormalMatrix[7];&lt;br /&gt;
          tnmat[3]=m_NormalMatrix[5]*m_NormalMatrix[6]-m_NormalMatrix[3]*m_NormalMatrix[8];&lt;br /&gt;
          tnmat[6]=m_NormalMatrix[3]*m_NormalMatrix[7]-m_NormalMatrix[4]*m_NormalMatrix[6];&lt;br /&gt;
&lt;br /&gt;
          tnmat[1]=m_NormalMatrix[2]*m_NormalMatrix[7]-m_NormalMatrix[5]*m_NormalMatrix[8];&lt;br /&gt;
          tnmat[4]=m_NormalMatrix[0]*m_NormalMatrix[8]-m_NormalMatrix[2]*m_NormalMatrix[6];&lt;br /&gt;
          tnmat[7]=m_NormalMatrix[1]*m_NormalMatrix[6]-m_NormalMatrix[1]*m_NormalMatrix[7];&lt;br /&gt;
&lt;br /&gt;
          tnmat[2]=m_NormalMatrix[1]*m_NormalMatrix[5]-m_NormalMatrix[2]*m_NormalMatrix[4];&lt;br /&gt;
          tnmat[5]=m_NormalMatrix[2]*m_NormalMatrix[3]-m_NormalMatrix[0]*m_NormalMatrix[5];&lt;br /&gt;
          tnmat[8]=m_NormalMatrix[0]*m_NormalMatrix[4]-m_NormalMatrix[1]*m_NormalMatrix[3];&lt;br /&gt;
&lt;br /&gt;
          for (unsigned int i=0;i&amp;lt;3;i++)&lt;br /&gt;
            for (unsigned int j=0;j&amp;lt;3;j++)&lt;br /&gt;
              m_NormalMatrix[i*3+j]=tnmat[i*3+j]/d;&lt;br /&gt;
          return tnmat;&lt;br /&gt;
        }&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Projectionview==&lt;br /&gt;
Die Projektionsmatrix, auch Projectionview genannt, ist die zweite wichtige Matrix in der Renderpipeline.&lt;br /&gt;
Diese Matrix macht den ganzen Zauber der Umwandlung von 3D in 2D erst möglich.&lt;br /&gt;
Wenn die Vertices mit der Modelview-Matrix multipliziert wurden, wird nun das Ergebnis mit der Projektionsmatrix multipliziert und wir erhalten Vektoren, dessen X- und Y-Komponente den Bildischrmpunkten entsprechen. Die zwei am häufigsten genutzten Matrizen sind die für die perspektivische und die orthogonale Ansicht.&lt;br /&gt;
&lt;br /&gt;
===Perspektive===&lt;br /&gt;
&lt;br /&gt;
[[Bild:GluPerspective_Quads_X.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die perspektivische Ansicht ist eine dreidimensional wirkende Ansicht, welche durch mehrere Faktoren beeinflusst wird.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GluPerspective.png]]&lt;br /&gt;
&lt;br /&gt;
''aspect'' steht für aspect ratio und beschreibt das Bildverhältnis von Höhe und Breite.&lt;br /&gt;
Diese ist sehr leicht herauszufinden: man dividiert einfach die Breite durch die Höhe, wenn man die Renderausgabe von der Bildschirmbreite abhängig machen möchte, oder umgekehrt für die Bildschirmhöhe.&lt;br /&gt;
f kann durch folgende Formel berechnet werden und bestimmt den Blickwinkel, welcher alle x- und y-Koordinaten zusammenstaucht oder auseinanderzieht. Dies erkennt man recht schnell, wenn man sich an die Skalierungsmatrix erinnert und das eine Multiplikation mit einem Vektor die x- und y-Komponenten skaliert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:sichtwinkel.png]]&lt;br /&gt;
&lt;br /&gt;
''zNear'' und ''zFar'' sind die Abstände der Near- und Far-Clipping Plane zur Kamera. Alle Objekte, die den Raum zwischen beiden Ebenen nicht schneiden, werden verworfen und der Rest durchläuft die restliche Renderpipeline. Die Thematik wird in einem späterem Artikel näher erläutet.&lt;br /&gt;
&lt;br /&gt;
===Orthogonal===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Orthomode_Quads.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die orthogonale Ansicht ist eine zweidimensionale Ansicht, welche wie die gewöhnlichen Desktopsysteme wirkt.&lt;br /&gt;
Hierbei werden die Z-Koordinaten nicht zur Verschiebung der Bildpunkte in der Tiefe verwendet.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GlOrtho_Matrix.png]]&lt;br /&gt;
&lt;br /&gt;
Mit r, l, b, t, f und n sind der rechte, linke, untere und obere Rand, sowie Distanz der far und near clipping plane des Bildschirmausschnittes gemeint. Die far und near clipping plane sind parallel zum Betrachter ausgerichtete Ebenen. Alles, was zwischen diesen beiden Ebenen liegt, wird gezeichnet und alles außerhalb wird in der Pipeline verworfen.&lt;br /&gt;
&lt;br /&gt;
=Exkurs in die Optimierung=&lt;br /&gt;
&lt;br /&gt;
==Vektoren==&lt;br /&gt;
Man hat oft den Fall, dass man auf der CPU mehrere Werte multiplizieren, dividieren, addieren, subtrahieren muss z.B. bei Bildbearbeitung.&lt;br /&gt;
&lt;br /&gt;
Dieses kann man optimieren, indem man Vektoren verwendet. Dabei wird ein Pixel als Vektor interpretiert und nun kann man alle Farbkanäle mit einen einzigen Aufruf verarbeiten lassen, indem man die Vektoroperationen verwendet. Wenn die Vektoren mit einer CPU-Extension wie SSE oder MMX implementiert wurden, dann werden die vier Komponenten eines Vektors sogar gleichzeitig verarbeitet. Sollte man nur zwei oder drei Komponenten verwenden, dann füllt man die restlichen Komponenten mit 0 auf bzw. ignoriert sie einfach beim Auslesen der Komponenten.&lt;br /&gt;
&lt;br /&gt;
===Multiplikation===&lt;br /&gt;
[[Datei:multiplikation_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Die Multiplikation von zwei Vektoren miteinander ist eigentlich nicht definiert, da es wenig Sinn macht, aber wir haben nun einen Verwendungszweck gefunden und definieren ihn. Bei dieser Operation gilt das gleiche wie bei der Addition und Subtraktion, nur mit einem Mulltiplikationsoperator. Die Bildverarbeitung wird sich mit mehr Geschwindigkeit bedanken.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Multiplikation(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]*b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Division===&lt;br /&gt;
[[Datei:division_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Division muss man aufpassen, dass keines der Elemente im Divisor 0 ist, da sonst eine Division mit 0 entsteht. Eine Division mit 0 hat ein Interrupt zufolge, welcher das Programm zum beendet. Also sollte man dies vorher überprüfen oder bei einer Division den Aufruf mit einer entsprechenden Routine den Fehler abfangen. Sonst verhält es sich wie bei der Multiplikation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Division(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]/b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Programmiersprache, Compiler und CPU-Extension==&lt;br /&gt;
Die Optimierung ist stark von Programmiersprache und Compiler abhängig. Wärend man mit Delphi, Freepascal und MS VSC++ Compiler nur aufwändig SSE, MMX und weitere CPU Extension implementieren kann, hat der GCC eine Vektorextension und seit Version 4.x auch eine Funktionsoptimierung. Die Vektorextension von GCC ist eine Parsererweiterung, welche einen Typ als ein bestimmten Vektortyp(z.B. Float Länge 4) bestimmt und dann entsprechend alle Operationen in SSE1-4 oder MMX-Code umwandelt. Seit Version 4.x gibt es eine Funktionsoptimierung, welche erlaubt, im Quellcode mehrere Optimierungen gleichzeitig zu nutzen. Die bedeutet, dass man eine Funktion wie Vektor.Magnitude() mehrfach implementiert und dann jeweils eine andere Optimierung aktiviert. Also Vektor.Magnitude_sse(), Vektor.Magnitude_mmx(),... und dann die jeweilige Funktion mit SSE, MMX oder ohne Optimierung markiert. Der Compiler optimiert dann diese Funktion für die jeweilige CPU Extension und man kann dann im Programmcode entsprechend der gegebenen Hardware auf die bestmögliche Funktion umlenken. Dies hat den Vorteil, dass man nur noch eine Binary hat und alle CPUs (mehr Kern, ein Kern, Intel Petium1-4, AMD Athlon und so weiter) der gleichen Architektur optimiert unterstützen kann. Dies ist nützlich, wenn man alte CPUs unterstützen will. Es würde sich also lohnen, wenn man sich viel Ärger und Code sparen will, den Code in GCC als Bibliothek zu implementieren und statisch oder dynamisch zu linken.&lt;br /&gt;
&lt;br /&gt;
==Templates und Generics==&lt;br /&gt;
Eine Optimierung, die sich bei C++ stark auswirkt, sind Templates, da diese die Eigenschaft aufweisen, vom Compiler generiert zu werden. Dies bedeutet je nach Qualität des Compilers kann dieser Code starke Performanceschübe bekommen, wenn man die Operationen in Templates verpackt, da der Compiler oft Optimierungen machen kann, die man selber nicht kennt oder gar nicht machen will (Kompatibilität und Übersichtlichkeit). Templates entrollen z.B. konstante Zählschleifen und wie schon vorher in den Codeschnipseln zu sehen war, haben wir davon einige in den Vektoroperationen. Das Entrollen von Schleifen entfernt eine Menge Balast (Counter,Prüfung,...), welche sich auf die Performance auswirkt. Templates reduzieren den Codeaufwand, da man viele weitere Implementierungen einspart (Vektor von Typ float, int, unsigned short, unsigned int, double, ...).&lt;br /&gt;
&lt;br /&gt;
==Testen, testen, testen==&lt;br /&gt;
Wenn man Performancetests macht, dann sollte man verschiedene Tests machen und einer, der teilweise oft unterschätzt wird, ist der Create und Free Test. Sobald man eine Klasse benutzt, wird beim Erstellen des Objektes immer ein Speicher alloziert und dann der Konstruktor aufgerufen, was  Zeit kostet. Man sollte also einmal einen Test durchführen, der Vektoren und Matrizen erstellt und zerstört. Die Operation Test sollten die Vektoren und Matrizen vorher erstellen und in der Schleife wiederverwendet werden und nach Beenden des Performance Trackings erst zerstört werden.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Lineare Algebra]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Lineare_Algebra&amp;diff=24952</id>
		<title>Tutorial OpenGL3 Lineare Algebra</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Lineare_Algebra&amp;diff=24952"/>
				<updated>2010-09-19T17:09:17Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Kreuzprodukt */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Vorwort=&lt;br /&gt;
Lineare Algebra ist ein Teilgebiet der Mathematik und beschäftigt sich mit Vektorräumen.&lt;br /&gt;
Die für OpenGL wichtigen Unterbereiche sind Vektoren und Matrizen.&lt;br /&gt;
Der größte Teil der 3D Programmierung beschäftigt sich mit Linearer Algebra, daher sollte auch diese Grundlage eine besondere Aufmerksamkeit gewidmet werden.&lt;br /&gt;
Sollte der Inhalt vieleicht zu viel für einmal sein, dann wäre es ratsam in mehreren Etappen zu bewältigen aber es sollte auf jedenfall vollständig verstanden werden, bevor man sich ernsthaft mit OpenGL auseinander setzen will.&lt;br /&gt;
=Trigonometrie=&lt;br /&gt;
Da später in der Linearen Algebra auf die Trigonometrie zurück gegriffen werden wird, soll als erstes die notwendigen Grundlagen in diesem Bereich beleuchtet werden.&lt;br /&gt;
==Bogenmaß und Gradmaß==&lt;br /&gt;
Man unterscheidet bei der Darstellung eines Winkels zwischen Bogenmaß(rad) und Gradmaß(deg).&lt;br /&gt;
Das Bogenmaß wird durch die Konstante Pi beschrieben, wobei der Wertebereich von 0 bis 2*Pi geht.&lt;br /&gt;
Das Gradmaß ist eine Einteilung, welche von 0 bis 360° abgebildet wird.&lt;br /&gt;
0° sind 0, 90° sind 0.5*Pi, 180° sind Pi, 270° sind 2/3*Pi und 360° sind 2*Pi oder auch 0° und 0.&lt;br /&gt;
&lt;br /&gt;
Um vom Bogenmaß in Gradmaß um zu rechnen, kann man folgende Formel verwenden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Lineare_Algebra_rad2deg.png]]&lt;br /&gt;
&lt;br /&gt;
Für die Umwandlung von Bogenmaß in Gradmaß gilt diese Formel.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
==Trigonometrische Funktionen==&lt;br /&gt;
Für das sinnvolle arbeiten mit Winkelfunktionen benötigen wir einen Einheitskreis.&lt;br /&gt;
Dieser ist ein Kreis, dessen Radius 1 ist und somit eine Reihe von Funktionen zu lässt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:einheitsvektor.png]] &lt;br /&gt;
&lt;br /&gt;
Der Einheitskreis ist wie folgt Beschriftet. In Blau sind die Bogenmaß Werte angegeben, in dunkelgrün die äquivalenten Werte der Kosinusfunktion und Orang ist der Winkel. Wenn man den Kosinus und Sinus von dem Winkel errechnet, dann erhält man den Hellgrünen x und Roten y Wert. Egal welchen Winkel man in der Sinus- und Kosinus-Funktion einsetzt, der Wert wird nie größer 1 oder kleiner -1 werden. Aber halt, wieso &lt;br /&gt;
==Trigonometrie im allgemeinen Dreieck==&lt;br /&gt;
Man unterscheidet in der Trigonometrie zwischen rechtwinkligen Dreiecken und allgemeinen Dreiecken.&lt;br /&gt;
Die allgemeinen Dreiecke sind allerdings für den weiteren Verlauf des Artikels wichtig und werden deswegen behandelt.&lt;br /&gt;
&lt;br /&gt;
===Sinus- und Kosinussatz===&lt;br /&gt;
Ein wichtige Gleichung, welche später wieder aufgegriffen werden wird, ist der Kosinussatz. &lt;br /&gt;
Doch zuvor sollte der Sinussatz genauer betrachtet werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:sinussatz.png]]&lt;br /&gt;
&lt;br /&gt;
Durch das Umstellen der Gleichungen kann man die einzelnen Winkel oder Seiten, eines Dreiecks, erhalten. Hierzu werden entweder 2 Seiten und ein Winkel oder 2 Winkel und eine Seite benötigt.&lt;br /&gt;
&lt;br /&gt;
Der Kosinussatz&lt;br /&gt;
&lt;br /&gt;
[[Datei:kosinussatz.png]]&lt;br /&gt;
&lt;br /&gt;
ermöglicht es, entweder aus drei gegebenen Seiten die Winkel auszurechnen oder aus zwei Seiten und ihrem Zwischenwinkel die gegenüber liegende Seite.&lt;br /&gt;
&lt;br /&gt;
===Eigenschaften und Formeln===&lt;br /&gt;
Es kann hilfreich sein, eine Sinus Funktion in eine Kosinus Funktion umzuwandeln oder umgekehrt. Hierzu benötigt man die Komplementärformeln, welche wie folgt aussehen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:costosin_sintocos.png]]&lt;br /&gt;
&lt;br /&gt;
Um den Rückgabewert, der Sinus- oder Kosinus-Funktion in den Bogenmaß um zu wandeln, gibt es folgende Umkehrfunktionen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:umkehrfunktion_sin_cos_tan.png]]&lt;br /&gt;
&lt;br /&gt;
Es ist zu beachten, dass diese den Bogenmaß zurück geben und diese für Gradmaß entsprechend umgerechnet werden müssen.&lt;br /&gt;
&lt;br /&gt;
=Vektor=&lt;br /&gt;
Ein Vektor kann mit einem Array oder einer Liste vergleicht werden, wenn man z.B. einen 3-dimensionalen Vektor meint, dann wäre es ein Array mit 3 Elementen.&lt;br /&gt;
Die übliche Schreibweise eines Vektors sieht wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:generischer_vektor.png]]&lt;br /&gt;
&lt;br /&gt;
Eine entsprechende C++ Representation wäre z.B. folgende&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
  public:&lt;br /&gt;
    float m_Vec[4];&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenGL verwendet auf der Grafikkarte immer 4-dimensionale Vektoren, auch wenn nur 1 oder 3 benötigt werden. Die restlichen Elemente des Vektors werden dann mit 0 aufgefüllt. Vektoren werden in OpenGL in 2 Arten verwendet, als absoluter und als relativer Wert. Absolute Werte wären z.B. Positionen und Farbwerte wärend relative Werte z.B. eine Transformation wäre. Der OpenGL Vektor sieht wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
==Einheitsvektor==&lt;br /&gt;
Ein besondere Form eines Vektors ist der Einheitsvektor, welcher immer eine Länge von 1 ergibt. Der Einheitsvektor wird normalerweise als klein e gekennzeichnet.&lt;br /&gt;
&lt;br /&gt;
Die Berechnung eines Einheitsvektors wird später in der der Magnitude und Normalisierung Funktion näher erläutert. Einheitsvektoren sind als Normalen/Richtungsvektoren in OpenGL im Einsatz und ist die Basis für Rotationen.&lt;br /&gt;
&lt;br /&gt;
==Addition==&lt;br /&gt;
[[Datei:addition_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:addition_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Die Addition wird Komponentenweise ausgeführt, was bedeutet, man kann sich eine Addition von Vektoren als eine Addition von jeden einzelnen Element mit dem entsprechenden Element im anderem Vektor Vorstellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:addition_vektor_visual.png]]&lt;br /&gt;
&lt;br /&gt;
Die Addition von Vektoren kann man sich sehr einfach Vorstellen, in dem man die einzelnen Vektoren als Bewegungsbefehle sieht. Wenn man also 2 schritte vorwärts,einen schritt seitwärts laufen soll und danach ein halben Schritt vorwärts und ein Schritt seitwärts, dann kann man diese beiden Befehle auch zu einem Befehl zusammen fassen. Laufe 2 1/2 Schritte vorwärts und 2 Schritte Seitwärts und wir stehen am gleichen Punkt und dieser Befehl wäre dann unser Ergebnis Vektor c.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Addition(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]+b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Subtraktion==&lt;br /&gt;
[[Datei:subtraktion_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:subtraktion_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Hier gilt gleiches, wie bei der Addition, nur das Komponentenweise Subtrahiert wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Subtraktion_vektor_visual.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Subtraktion eines Vektors wendet man den ersten Befehl an und läuft z.B. 2 Schritte nach vorne und einen Seitwärts, dann wendet man den 2. Schritt an aber wechselt das Vorzeichen jeder einzelnen Komponente. Also wird ein positive Komponente zu einer negativen und eine negative zu einer Positiven. Wenn man also einen schritt seitwärts,nach links, laufen soll, dann läuft man ein Schritt seitwärts, nach rechts, sowie vorwärts statt rückwärts. Man kann eine Subtraktion über eine Addition realisieren, wenn man jede Subtraktion, den rechten Vektor zuvor invertiert und dann addiert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Subtraktion(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]-b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Betrag==&lt;br /&gt;
[[Datei:magnitude_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Magnitude ist der Englische Begriff für die Berechnung des Betrags eines Vektors oder auch die Länge.&lt;br /&gt;
Die Länge des Vektors wird benötigt, wenn man einen Vektor Normalisieren will oder fest stellen möchte ob ein Vektor ein Einheitsvektor ist. &lt;br /&gt;
&lt;br /&gt;
[[Datei:betrag_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Der Betrag eines Vektors kann über den Satz des Pytagoras ermittelt werden, welcher die Wurzel der Summe, der Quadrate, aller Komponenten ist.&lt;br /&gt;
Dies ist natürlich für wenige gut Vorstellbar und daher hier mal eine bessere Erklärung. Ein Vektor kann in n Komponenten zerlegt werden, der 4 Komponenten Vektor von OpenGL in 4 Komponenten. Jede Komponente stellt eine Dimension dar, welche x,y,z und w sind. Pytagoras lernt man in der Schule im 2 Dimensionalen Raum kennen, also wie es im Abbild über diesen Text dargestellt ist. Die Regel besagt, das der Flächeninhalt einer Seite der Summe der anderen entspricht, also l²=x²+y².&lt;br /&gt;
Diese Flächen sind Quadratisch also hat jede Seite der Fläche die gleiche Kantenlänge. Wenn man die Quadratwurzel von der Fläche zieht, bekommt man also die Kantenlänge. Wenn man nun die Flächen von x,y,z und w summiert erhält man die Fläche l². Zieht man von l² die Quadratwurzel, dann hat man die Kantenlänge l von dem 4Komponenten Vektor, welche als Betrag oder Länge bezeichnet wird. Da bei einem Vektor w=0.0 gesetzt wird, hat diese keinen Einfluss auf diese Operation und wird in den Formeln auch in der Regel nicht mit hin geschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
float Betrag(){&lt;br /&gt;
  float len=0.0;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    len+=this-&amp;gt;m_Vec[i]*this-&amp;gt;m_Vec[i];&lt;br /&gt;
  return sqrt(len);&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Skalarprodukt==&lt;br /&gt;
[[Datei:skalarprodukt_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Das Skalarprodukt erlaubt uns die Berechnung, des Winkels, zwischen 2 Vektoren. Hierfür müssen allerdings beide Vektoren Normalisiert sein, also jeweils einen Betrag von 1 ergeben. Sonnst muss dies noch nachträglich getan werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:skalarprodukt_vektor1.png]]&lt;br /&gt;
&lt;br /&gt;
Wenn die 2 Vektoren a und b vorliegen, sollte man davon ausgehen, dass der Betrag beider Vektoren jeweils 1 ist. Sollte es nicht der Fall sein, so wie im Bild über diesen Text, dann muss dies durch die Normalisierung nachgeholt werden. Dies passiert, indem man den Betrag beider Vektoren errechnet und dann diesen Komponentenweise mit dem Vektor dividiert. Die oben stehende Formel wird aus dem Kosinussatz abgeleitet und Umgestellt. Darraus ergibt sich am Ende, dass die Summe, der Komponentenweise multiplizierten Vektoren a und b den Kosinus des Winkels ergibt. Es ist wichtig zu beachten, dass nicht der Winkel sondern der Kosinus des Winkels in c wieder zu finden ist. Wenn man den Winkel haben möchte, dann muss man den Arkuskosinus von c berechnen und das Ergebnis von Bogenmaß in Gradmaß umwandeln um den Winkel(als Delta makiert) zu bekommen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
float Skalarprodukt(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  float alpha=0.0;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    alpha+=this-&amp;gt;m_Vec[i]*b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Kreuzprodukt==&lt;br /&gt;
[[Datei:kreuzprodukt_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Das Kreuzprodukt errechnet einen Vektor, der senkrecht zu den Vektoren a und b steht, wenn a und b den selben Ursprung haben. Dieses Verhalten wird genutz, um die Normale einer Fläche zu errechnen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:kreuzprodukt_vektor1.png]]&lt;br /&gt;
&lt;br /&gt;
Der berechnete Vektor hat wie schon erwähnt die Eigenschaft, dass er senkrecht zu den Vektoren a und b ausgerichtet ist. Dies bedeutet, dass der Winkel zwischen dem Berechnetem Winkel und a oder b immer 90° beträgt. Wenn a und b 2 von den 3 Eckpunkten, eines Dreiecks ist, dann zeigt der Vektor c senkrecht zum Dreieck und bildet den Richtungsvektor des Dreiecks. Wenn man nun noch diesen Vektor normalisiert, dann erhält man die Flächenormale. Diese hat den Betrag 1 und wird für verschiedene Rendertechniken, sowie Physikberechnungen benötigt.&lt;br /&gt;
Wenn z.B. ein Lichtstrahl solch ein Dreieck schneidet, dann kann man mit Hilfe des Vektors(vom Lichstrahl) und der Normale(der Fläche) den Reflektionsvektor berechnen und somit sagen, in welche Richtung sich das Licht weiter bewegen würde.&lt;br /&gt;
Es ist zu beachten, dass die Reihenfolge, in der man beide Vektoren Multipliziert einen Einfluss auf die Richtung, in die c zeigt.&lt;br /&gt;
Wenn man a und b tauscht, dann wechseln die Vorzeichen aller Komponenten von c.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
TVector4Float Kreuzprodukt(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  unsigned int next,nextnext;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
  {&lt;br /&gt;
    next=(i+1) % 4;//i+1 Modulog 4&lt;br /&gt;
    nextnext=(i+2) % 4;&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[next]*b.m_Vec[nextnext]-this-&amp;gt;m_Vec[nextnext]*b.m_Vec[next];&lt;br /&gt;
  }&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Normalisieren==&lt;br /&gt;
[[Datei:normalisieren_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Normalisierung wird der Betrag eines Vektors mit dem Vektor dividiert und man erhält ein Vektor, der in die Gleiche Richtung zeigt aber auf eine Länge 1 skaliert ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Normalisieren(){&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  c=(*this)/this-&amp;gt;Betrag();&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Matrix=&lt;br /&gt;
Eine Matrix kann man sich als 2-dimensionalen Array mit n und m Länge vorstellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:generische_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
OpenGL verwendet 4x4 große Matrizen und kann aus 4 Vektoren mit einer Länge von 4 konstruiert werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
  protected: &lt;br /&gt;
    TVector4Float m_Matrix[4]; //Erlaubt uns das nutzen von der eigenen Vektorklarsse.&lt;br /&gt;
    float m_Array[16]; //für die LoadMatrix Funktion von OpenGL&lt;br /&gt;
  public:&lt;br /&gt;
    TVector4Float&amp;amp; Vektor(int Index)//Gibt eine Referenz vom Vektor zurück, was wie ein Pointer ist aber 100% auf ein Speicher zeigt, der existiert.&lt;br /&gt;
    { &lt;br /&gt;
      return m_Matrix[Index]; &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    T* GetMatrix1DArray()//Liefert den Pointer von der m_Array variable zurück.&lt;br /&gt;
    { &lt;br /&gt;
      //Überträgt die Daten von den einzelnen Vektoren in die OpenGL kompatible Matrix(m_Array).&lt;br /&gt;
      for (int i=0;i&amp;lt;4;i++)&lt;br /&gt;
        memcpy(&amp;amp;m_Array[i*4],&amp;amp;m_Matrix[i][0],16);&lt;br /&gt;
      return &amp;amp;m_Array[0];//Gibt den Pointer auf m_Array zurück.&lt;br /&gt;
    }&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für Matrizen brauchen wir nicht so viele Funktionen wie bei Vektoren, um genau zu sagen brauchen wir 2 Operationen. Diese Operationen lauten Transponieren und Multiplikation.&lt;br /&gt;
Bei der Matrix benötigen wir einige Konstruktionsfunktionen und zwar Identity, Translate, Rotate  und Scale Matrix. Diese Matrizen machen die ganze Arbeit für uns, wenn man sich in einem 3D Raum bewegen möchte, welcher als Modelview Matrix abgebildet wird.&lt;br /&gt;
&lt;br /&gt;
==Transponieren==&lt;br /&gt;
[[Datei:transponieren_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
Transponieren wird durch ein großes T über der Matrix dargestellt. Diese Funktion tauscht die Werte einer Matrix miteinander aus, so das aus einer Spalten konstruierten Matrix eine Zeilenweise konstruierte Matrix wird. Diese Funktion kann Hilfreich sein, wenn man zwischen Direct3D und OpenGL Daten austauschen will, denn nicht jeder nutzt spalten orientierte Matrizen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_matrix.png‎]][[Datei:d3d_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Transponieren()&lt;br /&gt;
{ &lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[1],m_Matrix.Vektor(1).m_Vec[0]); //swap kopiert b in tmp, kopiert a in b und tmp in a&lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[2],m_Matrix.Vektor(2).m_Vec[0]); &lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[3],m_Matrix.Vektor(3).m_Vec[0]); &lt;br /&gt;
&lt;br /&gt;
  swap(m_Matrix.Vektor(1).m_Vec[2],m_Matrix.Vektor(2).m_Vec[1]); &lt;br /&gt;
  swap(m_Matrix.Vektor(1).m_Vec[3],m_Matrix.Vektor(3).m_Vec[1]); &lt;br /&gt;
&lt;br /&gt;
  swap(m_Matrix.Vektor(2).m_Vec[3],m_Matrix.Vektor(3).m_Vec[2]); &lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Multiplikation==&lt;br /&gt;
Multiplikation ist die wichtigste Operation bei Matrizen, wenn wir uns mit OpenGL beschäftigen.&lt;br /&gt;
Dies liegt daran, dass OpenGL 2 verschiedene Matrizen verwendet, um Vektoren in Bildschirmkoordinaten um zu wandeln. Damit dies Funktioniert muss jeder Vektor mit diesen Matrizen jeweils multipliziert werden. Um eine Matrix zu manipulieren wird diese mit einer Konstruierten Matrix multipliziert. Diese Operation die ist meist ausgeführte Operation sowohl in der OpenGL Pipeline als auch in einem Spiel. Seit OpenGL3 gibt es kein Matrizen support mehr, was bedeutet, dass man diese selber implementieren muss und dann die fertigen Matrizen an OpenGL übergibt. Die lässt viel Raum für Optimierung und kann somit ein OpenGL3 Programm schneller machen als ein OpenGL2 Programm, wenn man zuvor die glTranslate,glRotate und weiteren Funktionen verwendet hat. Es ist also ratsam sich eine sehr Performance Bibliothek zu laden oder mit einem Performance Analyzer bewaffnet den eigenen Code zu optimieren.&lt;br /&gt;
===Multiplikation mit einem Vektor===&lt;br /&gt;
[[Datei:multiplikation_matrix_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:multiplikation_matrix_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Um eine Matrix mit einem Vektor zu multiplizieren, braucht man man nur den Vektor[n] von der Matrix mit der Komponente[n] von dem Vektor multiplizieren und die resultierenden Vektoren anschließend addieren. Hierbei wird also ein Vektor mit einer einzelnen Komponente multipliziert, was weiter oben, bei den Vektoren, erklärt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Multipliziere(TVector4Float V) &lt;br /&gt;
{ &lt;br /&gt;
  TVector4Float v=m_Matrix.Vektor(0)*V.m_Vec[0]+m_Matrix.Vektor(1)*V.m_Vec[1]+m_Matrix.Vektor(2)*V.m_Vec[2]+m_Matrix.Vektor(3)*V.m_Vec[3];&lt;br /&gt;
  return v; &lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Multiplikation mit einer Matrix===&lt;br /&gt;
[[Datei:multiplikation_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:multiplikation_matrix1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Es sieht recht aufwändig aus allerdings kann man es dank der vorigen Matrix-Vektor Multiplikation auf eine recht übersichtliches Maß runter streichen. Man braucht dann nur noch die Matrix a jeweils mit einen der Vektoren von Matrix b multiplizieren und hat die Matrix-Matrix Multiplikation erledigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
TMatrix4x4Float Multiplikation(TMatrix4x4Float M) &lt;br /&gt;
{ &lt;br /&gt;
  TMatrix4x4Float M1((*this)*M.Vektor(0)), (*this)*M.Vektor(1), (*this)*M.Vektor(2), (*this)*M.Vektor(3)); &lt;br /&gt;
  return M1;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Konstruieren von Matrizen=&lt;br /&gt;
&lt;br /&gt;
==Identity==&lt;br /&gt;
Die Identity Matrix ist die Initialisierungsmatrix, mit der alle Matrizen belegt werden.&lt;br /&gt;
Diese ist recht einfach und hat denn Sinn, dass bei einer Multiplikation immer der Wert herraus kommt, mit dem diese Multipliziert wurde.&lt;br /&gt;
Wer aufmerksam gelsen hat, der wird nun an Einheitsvektoren denken und liegt richtig.&lt;br /&gt;
Aufgrund der beschaffenheit einer Matrix benötigen wir in jeder Reihe und Spalte jeweils ein Element, welche den Wert 1 an nimmt und die restlichen nehmen den Wert 0 an. Die sieht dann wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Es ist nicht zwingend notwendig die Einheitsvektoren in dieser Reihenfolge zu verwenden, man könnte auch den ersten und dritten Vektor tauschen und es würde trotzdem das gleiche Ergebnis geben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
static TVector4Float Identity[4];//Statische Variable, welche nur einmal existiert.&lt;br /&gt;
&lt;br /&gt;
void LadeIdentity()&lt;br /&gt;
{&lt;br /&gt;
  for (int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    m_Matrix.Vektor(i)=Identity.m_Vec[i];&lt;br /&gt;
}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
TVector4Float TMatrix4x4Float::Identity[4]={TVector4Float(1.0,0.0,0.0,0.0),TVector4Float(0.0,1.0,0.0,0.0),TVector4Float(0.0,0.0,1.0,0.0),TVector4Float(0.0,0.0,0.0,1.0)};&amp;lt;/source&amp;gt;&lt;br /&gt;
==Translate==&lt;br /&gt;
Wenn man ein Vektor oder Matrix in x,y,z bewegen möchte, dann kann man dies mit einer Transformationsmatrix erreichen.&lt;br /&gt;
Dazu erstellt man eine Matrix, füllt sie mit der Identity Matrix und setzt dann x,y,z in der Matrix mit den zu x,y,z Werten, um die man etwas verschieben möchte.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Translate(float x,float y,float z)&lt;br /&gt;
{&lt;br /&gt;
  TKar_Matrix&amp;lt;KAR_MATH_TYPE&amp;gt; m;&lt;br /&gt;
  m.Vektor(3).m_Vec[0]=x;&lt;br /&gt;
  m.Vektor(3).m_Vec[1]=y;&lt;br /&gt;
  m.Vektor(3).m_Vec[2]=z;&lt;br /&gt;
  (*this)*=m;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
==Rotate==&lt;br /&gt;
Das Bewegen auf den 3 Achsen ist allerdings oft nicht ausreichend und deswegen gibt es auch eine Rortations-Matrix.&lt;br /&gt;
Die Rotations-Matrix wird durch 3 Vektoren beschrieben, welche jeweils für die x,y und z Achse zuständig sind.&lt;br /&gt;
Man kann die Rotation, der einzelnen Achsen in einem Schritt oder in 3 einzelne Aufteilen. Um die Rotationsmatrix besser zu verstehen werden erst einmal alle Achsen einzeln betrachtet.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die Z-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_rotz.gif]][[Datei:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(3. Spalte=0.0, 0.0, 1.0, 0.0) bleibt bei der Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1. Spalte=1.0, 0.0, 0.0 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;x = cos(ß)&lt;br /&gt;
y = sin(ß)&amp;lt;/source&amp;gt;&lt;br /&gt;
womit der Inhalt der ersten Spalte der Matrix kennen: (cos(ß), sin(ß), 0.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Dies kann man auch auf den Y-Achsen Einheitsvektor(2. Spalte=0.0, 1.0, 0.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;x = -sin(ß)&lt;br /&gt;
y = cos(ß)&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß), cos(ß), 0.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Nun kann man die Rotationsmatrix für die Rotation auf der Z-Achse beschreiben, die Matrix findet man am Anfang des Abschnittes.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die Y-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_roty.gif]][[Datei:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Die Berechnung der Matrix wird auf die gleiche weise ermittelt, wie bei der Berechnung der Z-Achsen Rotationsmatrix.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die X-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_rotx.gif]][[Datei:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Rotation um alle Achsen mit einer Matrix===&lt;br /&gt;
&lt;br /&gt;
Es ist recht aufwändig für die CPU und für den Programmierer immer 3 Rotationen aus zu führen, deswegen hat man diese auch zu einer einzigen Operation zusammen gefasst. Die Matrizen werden einfach miteinander multipliziert und es kommt eine Rotationsmatrix herraus, welche 3 Eingabeparameter benötigt, alpha, beta und gamma sind dabei die Winkel für X-,Y- und Z-Achse.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rotationsmatrix_3angle.png]]&lt;br /&gt;
&lt;br /&gt;
Eine weitere Möglichkeit, um eine Rotationsmatrix zu erstellen, wäre das nutzen eines Richtungsvektors und einem Winkel. Hierbei wird der Winkel auf den Richtungsvektor angewendet, wenn also man als Vektor (1,0,0) verwendet dann hat man eine Rotation auf der X-Achse, (0,1,0) Y-Achse und (0,0,1) für die Z-Achse. Man kann nun auch Vektoren wie (1,1,1) angeben, wobei die Funktion diesen Vektor dann normalisieren wird, damit er noch auf das Einheitskreis System funktioniert. Dieser Vektor ist nicht equivalent mit dem Rotieren von X-,Y- und Z-Achse nacheinander. Der Vorteil hierbei liegt in der Kompaktheitund des Codes und man kann auf Algorithmen zurück greifen, die vor OpenGL3 entwickelt wurden, da der OpenGL Treiber früher die Rotation über diese Variante Implementiert hatte.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rotationsmatrix.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Rotiere(float w,float x,float y,float z)&lt;br /&gt;
{&lt;br /&gt;
  TMatrix4Float m;&lt;br /&gt;
  float rad=DegToRad(w);&lt;br /&gt;
  float c=cos(rad);&lt;br /&gt;
  float ic=1.0-c;&lt;br /&gt;
  float s=sin(rad);&lt;br /&gt;
  TVector4Float v(x,y,z,0.0);&lt;br /&gt;
  float mag=sqrt((v*v).Summe());&lt;br /&gt;
&lt;br /&gt;
  if (mag&amp;lt;=1.0e-4)&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  v.m_Vec[0]=x/mag;&lt;br /&gt;
  v.m_Vec[1]=y/mag;&lt;br /&gt;
  v.m_Vec[2]=z/mag;&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(0).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[0]*ic)+c;&lt;br /&gt;
  m.Vektor(0).m_Vec[1]=(v.m_Vec[0]*v.m_Vec[1]*ic)+(v.m_Vec[2]*s);&lt;br /&gt;
  m.Vektor(0).m_Vec[2]=(v.m_Vec[0]*v.m_Vec[2]*ic)-(v.m_Vec[1]*s);&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(1).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[1]*ic)-(v.m_Vec[2]*s);&lt;br /&gt;
  m.Vektor(1).m_Vec[1]=(v.m_Vec[1]*v.m_Vec[1]*ic)+c;&lt;br /&gt;
  m.Vektor(1).m_Vec[2]=(v.m_Vec[1]*v.m_Vec[2]*ic)+(v.m_Vec[0]*s);&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(2).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[2]*ic)+(v.m_Vec[1]*s);&lt;br /&gt;
  m.Vektor(2).m_Vec[1]=(v.m_Vec[1]*v.m_Vec[2]*ic)-(v.m_Vec[0]*s);&lt;br /&gt;
  m.Vektor(2).m_Vec[2]=(v.m_Vec[2]*v.m_Vec[2]*ic)+c;&lt;br /&gt;
&lt;br /&gt;
  *this*=m;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Scale==&lt;br /&gt;
[[Bild:skalierungsmatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Die Skalierung ist eine sehr einfache Matrix, in der für die 1, des Einheitsvektors, der entsprechende Skalierungsfaktor angegeben wird. Wenn man die Matrix mit einem Vektor multipliziert, dann werden X,Y und Z des Vektors mit den x,y und z Werten in der Skalierungsmatrix multipliziert und damit skaliert. Wenn man etwas größer machen will, dann wird der Wert entsprechend über 1.0 gewählt, z.B. 2.0 wäre doppelte größe und für verkleinern würde man ein Wert zwischen 1.0 und 0.0 wählen. Der Wert 0.5 würde z.B. eine Division durch 2 bedeuten, also 3*0.5=1.5. Der 4. Einheitsvektor wird belassen, da wir diesen nur als Kompatibilität zu den 4Komponenten Vektoren benötigen.&lt;br /&gt;
&lt;br /&gt;
=Vom Vektor zur Bildschirmkoordinate=&lt;br /&gt;
Auf in den Endspurt!&lt;br /&gt;
Alle Mathematischen Formeln und Funktionen benötigen wir um die letzten 2 Punkte behandeln zu können.&lt;br /&gt;
Die Rede ist von der Umwandlung eines Vektors im 3D Raum in den 2D Raum, auf dem Bildschirm.&lt;br /&gt;
In Rahmen dieses Artikel wird nur auf die Transformation der Vektoren eingegangen und in einem späterem Artikel dann die weiteren Zwischenschritte zum Zeichnen einer Geometrie.&lt;br /&gt;
==Modelview==&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Die Modelview kann man sich wie ein 3D Unterraum vorstellen oder einer Transformation des Raumes. Die Modelview sorgt dafür, dass alle Vektoren, die mit dieser Multipliziert werden zu dieser Modelview ausgerichtet werden und die Modelview ist relativ zur Welt ausgerichtet. Dies bedeutet, wenn man für jedes Objekt eine Modelview erzeugt, dann kann dieses Objekt relativ zur Welt ausgerichtet werden, sobald man die Vektoren des Objektes mit der Modelview multipliziert. Wieso richtet man die Vektoren nicht gleich zur Welt aus, statt den Umweg über die Modelview Matrix zu gehen ? Die Antwort ist schlicht &amp;quot;Optimierung&amp;quot;. Es wäre zu langsam, wenn man jeden Renderdurchgang jedes einzelne Vertex im Speicher lesen müsste, die neue Position berechnen, im Speicher updaten und in der Pipeline weiter zu arbeiten. Es ist auch Speichereffizienter, da z.B. gleiche Objekte nur einmal in den Speicher abgelegt werden müssen und nur 2 unterschiedliche Modelview Matrizen benötigt werden.&lt;br /&gt;
&lt;br /&gt;
Im rechten Bild kann man 2 aufeinander folgende Befehlsketten sehen, die Transformationen auf ein Objekt ausführen. Dieses Bild soll nocheinmal verdeutlichen, dass das Anwenden von Befehlen, auf eine Modelview Matrix nicht Kommultativ(a*b ist nicht das gleiche wie b*a) ist.&lt;br /&gt;
&lt;br /&gt;
Während vor OpenGL3 die Modelview Matrix von den OpenGL Treibern verwaltet wurde, muss dies ab OpenGL3 vom User gemacht werden und auch das aktualisieren in der Renderpipeline muss nun vom Entwickler übernommen werden, wie dies funktioniert wird in einem späteren Artikel erklärt. Es ist nur noch wichtig zu sagen, dass die GPU diese Matrix mit jeden Vertex multipliziert, der durch dir Renderpipeline geschickt wird.&lt;br /&gt;
&lt;br /&gt;
==Normal-Matrix==&lt;br /&gt;
Die Normal-Matrix wurde vor OpenGL3 als [[gl_NormalMatrix]] automatisch berechnet aber mit OpenGL3 ist auch diese aus dem Treiber entfernt worden.&lt;br /&gt;
Dies hat zufolge, dass man diesen Schritt selber vollziehen muss und aufgrund der Wichtigkeit dieser Matrix sollte man versuchen diese auch zu verinnerlichen.&lt;br /&gt;
Mit der gl_NormalMatrix kann man ein Normale von dem Texture-Space in den World-Space transformieren. &lt;br /&gt;
Dies ist wie bei der Multiplikation eines Vertex mit der [[gl_ModelViewMatrix]], nur das die Konstruktion der gl_NormalMatrix andere Anforderungen hat und deswegen zusätzlich generiert wird.&lt;br /&gt;
&lt;br /&gt;
Eine Normale ist ein Vektor, welcher die Länge 1 hat und repräsentiert die Flächenausrichtung.&lt;br /&gt;
Wenn man ein Dreieck auf der X,Y,Z Achse bewegt, dann hat dies keinen Einfluss auf die Werte einer Normale.&lt;br /&gt;
Sollte man ein Dreieck aber Rotieren oder Skalieren, dann verändern sich die Werte einer Normale, welcher den Unterschied zwischen gl_NormalMatrix und gl_ModelviewMatrix aus macht.&lt;br /&gt;
Es gibt einen Spezialfall beim skalieren, sollte die Skalierung aller Dimensionen mit dem gleichen Wert durchgeführt werden, dann ändert sich die Normale nicht.&lt;br /&gt;
Die gl_NormalMatrix wird errechnet, indem man den Rotationsanteil der Modelview Matrix in eine 3x3 Matrix kopiert, die Inverse errechnet und anschließend die Matrix transponiert.&lt;br /&gt;
&lt;br /&gt;
Um nun die Normale in den World-Space zu transformieren kann man folgende Berechnung anwenden.&lt;br /&gt;
Normal=normalize(gl_NormalMatrix*gl_Normal);&lt;br /&gt;
Nach der Multiplikation wird das Ergebnis normalisiert, da eine Normale immer die Länge 1.0 haben muss und durch die Möglichkeit, dass eine Skalierung mit unterschiedlichen Werte auf jeder Achse, dies sonnst nicht gewährleistet wäre.&lt;br /&gt;
Aufgrund der Normalisierung entsteht der vorher erwähnte Sonderfall, bei dem eine Skalierung mit ein und dem selben Skalar keinen Änderungen zufolge hat.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
    protected:&lt;br /&gt;
        TMatrix3x3Float m_NormalMatrix;&lt;br /&gt;
    public:&lt;br /&gt;
        TMatrix3x3Float&amp;amp; NormalMatrix()&lt;br /&gt;
        {&lt;br /&gt;
          TMatrix3x3Float tnmat;&lt;br /&gt;
          float d;&lt;br /&gt;
          //Kopiere den Rotations- und Skalierungsanteil aus der Modelview Matrix.&lt;br /&gt;
          for (unsigned int i=0;i&amp;lt;3;i++)&lt;br /&gt;
            for (unsigned int j=0;j&amp;lt;3;j++)&lt;br /&gt;
              m_NormalMatrix.Value[i*3+j]=this-&amp;gt;Value[i*4+j];&lt;br /&gt;
&lt;br /&gt;
          //Inverse mit Hilfe der Determinante berechnen und Transponieren in einem Schritt(im Fall der Rotationsmatrix&lt;br /&gt;
          //ist es nicht wichtig in welcher Reihenfolge Transponieren und Determinieren geschehen.)&lt;br /&gt;
&lt;br /&gt;
          d=Determinant(m_NormalMatrix);&lt;br /&gt;
          tnmat[0]=m_NormalMatrix[4]*m_NormalMatrix[8]-m_NormalMatrix[5]*m_NormalMatrix[7];&lt;br /&gt;
          tnmat[3]=m_NormalMatrix[5]*m_NormalMatrix[6]-m_NormalMatrix[3]*m_NormalMatrix[8];&lt;br /&gt;
          tnmat[6]=m_NormalMatrix[3]*m_NormalMatrix[7]-m_NormalMatrix[4]*m_NormalMatrix[6];&lt;br /&gt;
&lt;br /&gt;
          tnmat[1]=m_NormalMatrix[2]*m_NormalMatrix[7]-m_NormalMatrix[5]*m_NormalMatrix[8];&lt;br /&gt;
          tnmat[4]=m_NormalMatrix[0]*m_NormalMatrix[8]-m_NormalMatrix[2]*m_NormalMatrix[6];&lt;br /&gt;
          tnmat[7]=m_NormalMatrix[1]*m_NormalMatrix[6]-m_NormalMatrix[1]*m_NormalMatrix[7];&lt;br /&gt;
&lt;br /&gt;
          tnmat[2]=m_NormalMatrix[1]*m_NormalMatrix[5]-m_NormalMatrix[2]*m_NormalMatrix[4];&lt;br /&gt;
          tnmat[5]=m_NormalMatrix[2]*m_NormalMatrix[3]-m_NormalMatrix[0]*m_NormalMatrix[5];&lt;br /&gt;
          tnmat[8]=m_NormalMatrix[0]*m_NormalMatrix[4]-m_NormalMatrix[1]*m_NormalMatrix[3];&lt;br /&gt;
&lt;br /&gt;
          for (unsigned int i=0;i&amp;lt;3;i++)&lt;br /&gt;
            for (unsigned int j=0;j&amp;lt;3;j++)&lt;br /&gt;
              m_NormalMatrix[i*3+j]=tnmat[i*3+j]/d;&lt;br /&gt;
          return tnmat;&lt;br /&gt;
        }&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Projectionview==&lt;br /&gt;
Die Projektions Matrix oder auch Projectionview genannt ist die 2. wichtige Matrix in der Renderpipeline.&lt;br /&gt;
Diese Matrix macht den ganzen Zauber, der Umwandlung von 3D in 2D erst möglich.&lt;br /&gt;
Wenn die Vertice mit der Modelview Matrix multipliziert wurden, wird nun das Ergebnis mit der Projektions Matrix multipliziert und wir erhalten Vektoren, dessen X und Y Komponente den Bildischrmpunkten entsprechen. Die 2 am häufigsten genutzten Matrizen sind die Perspektivische- und die Orthogonale Ansicht.&lt;br /&gt;
&lt;br /&gt;
===Perspektive===&lt;br /&gt;
&lt;br /&gt;
[[Bild:GluPerspective_Quads_X.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die Perspektivische Ansicht ist eine drei Dimmensional wirkende Ansicht, welche durch mehrere Faktoren beeinflusst wird.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GluPerspective.png]]&lt;br /&gt;
&lt;br /&gt;
aspect steht für aspect ratio und beschreibt das Bildverhältnis von Höhe und Breite.&lt;br /&gt;
Diese ist sehr leicht herraus zu finden, man dividiert einfach die Breite durch die Höhe, wenn man die Renderausgabe von der Bildschirmbreite abhängig machen möchte oder umgekerht, für die Bildschirmhöhe.&lt;br /&gt;
f kann durch folgende Formel berechnet werden und bestimmt den Blickwinkel, welcher alle x und y Koordinaten zusammen staucht oder auseinander zieht. Dies erkennt man recht schnell, wenn man sich an die Skalierungsmatrix erinnert und das eine Multiplikation mit einem Vektor die x und y Komponenten skaliert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:sichtwinkel.png]]&lt;br /&gt;
&lt;br /&gt;
zNear und zFar sind die Abstände, der Near- und Far-Clipping Plane, zur Kamera. Alle Objekte, die den Raum, zwischen beiden Ebenen nicht schneidet, wird verworfen und der rest durchläuft die restliche Renderpipeline. Die Thematik wird in einem späterem Artikel näher erläutet.&lt;br /&gt;
&lt;br /&gt;
===Orthogonal===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Orthomode_Quads.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die Orthogonale Ansicht ist eine zwei Dimmensionale Ansicht, welche wie die gewöhnlichen Desktopsysteme wirkt.&lt;br /&gt;
Hierbei werden die Z Koordinaten nicht zur Verschiebung der Bildpunkte, in der Tiefe verwendet.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GlOrtho_Matrix.png]]&lt;br /&gt;
&lt;br /&gt;
Mit r, l, b, t, f und n sind der rechte, linke, untere und obere Rand, sowie Distanz der far und near clipping plane, des Bildschirmausschnittes, gemeint. Die far und near clipping plane sind parallel, zum Betrachter, ausgerichtete Ebenen. Alles was zwischen diesen beiden Ebenen liegt wird gezeichnet und alles außerhalb wird in der Pipeline verworfen.&lt;br /&gt;
&lt;br /&gt;
=Exkurs in die Optimierung=&lt;br /&gt;
==Vektoren==&lt;br /&gt;
Man hat oft den Fall, dass man auf der CPU mehrere Werte multiplizieren, dividieren, addieren, subtrahieren muss z.B. bei Bildbearbeitung.&lt;br /&gt;
&lt;br /&gt;
Dieses kann man Optimieren, indem man Vektoren verwendet, dabei wird ein Pixel als Vektor interpretiert und nun kann man alle Farbkanäle mit einen einzigen Aufruf verarbeiten lassen, indem man die Vektoroperationen verwendet. Wenn die Vektoren mit einer CPU Extension wie SSE oder MMX implementiert wurden, dann werden die 4 Komponenten eines Vektors sogar gleichzeitig verarbeitet. Sollte man nur 2 oder 3 Komponenten verwenden, dann füllt man die restlichen Komponenten mit 0 auf bzw. ignoriert sie einfach beim auslesen der Komponenten.&lt;br /&gt;
===Multiplikation===&lt;br /&gt;
[[Datei:multiplikation_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Die Multiplikation von 2 Vektoren miteinander ist eigentlich nicht definiert, da es wenig Sinn macht aber wir haben nun einen Verwendungszweck gefunden und definieren ihn. Bei dieser Operation gilt das gleiches, wie bei der Addition und Subtraktion, nur mit einem Mulltiplikations Operator. Die Bildverarbeitung wird sich mit mehr Geschwindigkeit bedanken.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Multiplikation(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]*b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Division===&lt;br /&gt;
[[Datei:division_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Division muss man aufpassen, dass keiner der Element im Divisor 0 ist, da sonnst eine Division mit 0 entsteht. Eine Division mit 0 hat ein Interrupt zufolge, welcher das Programm zum beenden bittet. Also sollte man dies Vorher überprüfen oder bei einer Division den Aufruf mit einer entsprechenden Routine den Fehler abfangen. Sonnst verhält es wie bei der Multiplikation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Division(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]/b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Programmiersprache,Compiler und CPU Extension==&lt;br /&gt;
Die Optimierung ist von Programmiersprache und Compiler stark abhängig. Wärend Delphi, Freepascal und MS VSC++ Compiler man nur aufwändig SSE,MMX und weitere CPU Extension implementieren kann, hat der GCC eine Vektorextension und seit Version 4.x auch eine Funktionsoptimierung. Die Vektorextension von GCC ist ein Parser Erweiterung, welche einen Typ als ein bestimmten Vektortyp(z.B. Float Länge 4) bestimmt und dann entsprechend alle Operationen in SSE1-4 oder MMX Code umwandelt. Seit Version 4.x gibt es eine Funktionsoptimierung, welche erlaubt im Quellcode mehrere Optimierungen gleichzeitig zu nutzen. Die bedeutet, dass man eine Funktion, wie Vektor.Magnitude() mehrfach implementiert und dann jeweils eine andere Optimierungs Aktiviert. Also Vektor.Magnitude_sse(), Vektor.Magnitude_mmx(),... und dann die jeweilige Funktion mit SSE,MMX oder ohne Optimierung markiert. Der Compiler optimiert dann diese Funktion für die jeweilige CPU Extension und man kann dann im Programmcode entsprechend der gegebenen Hardware auf die beste Mögliche Funktion umlenken. Dies hat den Vorteil, dass man nur noch eine Binary hat und alle CPUs(mehr Kern, ein Kern, Intel Petium1-4, AMD Athlon und so weiter) der gleichen Architektur Optimiert  Unterstützen kann. Dies ist ist nützlich, wenn man alte CPUs unterstützen will. Es würde sich also lohnen, wenn man sich viel Ärger und Code sparen will, den Code in GCC als Bibliothek zu implementieren und statisch oder dynamisch zu linken.&lt;br /&gt;
&lt;br /&gt;
==Templates und Generics==&lt;br /&gt;
Eine Optimierung die sich bei C++ stark auswirkt sind Templates, da diese die Eigenschaft aufweisen vom Compiler generiert zu werden. Dies bedeutet je nach Qualität des Compilers kann dieser Code starke Performanceschübe bekommen, wenn man die Operationen in Templates verpackt, da der Compiler oft Optimierungen machen kann, die man selber nicht kennt oder gar nicht machen will(Kompatibilität und Übersichtlichkeit). Templates entrollen z.B. konstante For Schleifen und wie schon vorher in den Codeschnipseln zu sehen war, haben wir davon einige in den Vektor Operationen. Das Entrollen von Schleifen entfernt eine menge Balast(Counter,Prüfung,..) welche sich auf die Performance auswirkt. Templates reduziert den Codeaufwand, da man viele weitere Implementierungen einspart(Vektor von Typ float, int, unsigned short, unsigned int, double, ...).&lt;br /&gt;
&lt;br /&gt;
==Testen testen testen==&lt;br /&gt;
Wenn man Performance Test macht, dann sollte man verschiedene Test machen und einer der teilweise oft unterschätzt wird ist der Create und Free Test. Sobald man eine Klasse benutzt wird beim erstellen des Objektes immer ein Speicher alloziert und dann der Konstruktor aufgerufen, was  Zeit kostet. Man sollte also einmal ein Test durchführen, der Vektoren und Matrizen erstellt und zerstört. Die Operation Test sollten die Vektoren und Matrizen vorher erstellen und in der Schleife wiederverwendet werden und nach beenden des Performance Trackings erst zerstört werden.&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Lineare_Algebra&amp;diff=24334</id>
		<title>Tutorial OpenGL3 Lineare Algebra</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Lineare_Algebra&amp;diff=24334"/>
				<updated>2009-11-24T18:46:34Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Vom Vektor zur Bildschirmkoordinate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Vorwort=&lt;br /&gt;
Lineare Algebra ist ein Teilgebiet der Mathematik und beschäftigt sich mit Vektorräumen.&lt;br /&gt;
Die für OpenGL wichtigen Unterbereiche sind Vektoren und Matrizen.&lt;br /&gt;
Der größte Teil der 3D Programmierung beschäftigt sich mit Linearer Algebra, daher sollte auch diese Grundlage eine besondere Aufmerksamkeit gewidmet werden.&lt;br /&gt;
Sollte der Inhalt vieleicht zu viel für einmal sein, dann wäre es ratsam in mehreren Etappen zu bewältigen aber es sollte auf jedenfall vollständig verstanden werden, bevor man sich ernsthaft mit OpenGL auseinander setzen will.&lt;br /&gt;
=Trigonometrie=&lt;br /&gt;
Da später in der Linearen Algebra auf die Trigonometrie zurück gegriffen werden wird, soll als erstes die notwendigen Grundlagen in diesem Bereich beleuchtet werden.&lt;br /&gt;
==Bogenmaß und Gradmaß==&lt;br /&gt;
Man unterscheidet bei der Darstellung eines Winkels zwischen Bogenmaß(rad) und Gradmaß(deg).&lt;br /&gt;
Das Bogenmaß wird durch die Konstante Pi beschrieben, wobei der Wertebereich von 0 bis 2*Pi geht.&lt;br /&gt;
Das Gradmaß ist eine Einteilung, welche von 0 bis 360° abgebildet wird.&lt;br /&gt;
0° sind 0, 90° sind 0.5*Pi, 180° sind Pi, 270° sind 2/3*Pi und 360° sind 2*Pi oder auch 0° und 0.&lt;br /&gt;
&lt;br /&gt;
Um vom Bogenmaß in Gradmaß um zu rechnen, kann man folgende Formel verwenden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Lineare_Algebra_rad2deg.png]]&lt;br /&gt;
&lt;br /&gt;
Für die Umwandlung von Bogenmaß in Gradmaß gilt diese Formel.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
==Trigonometrische Funktionen==&lt;br /&gt;
Für das sinnvolle arbeiten mit Winkelfunktionen benötigen wir einen Einheitskreis.&lt;br /&gt;
Dieser ist ein Kreis, dessen Radius 1 ist und somit eine Reihe von Funktionen zu lässt.&lt;br /&gt;
&lt;br /&gt;
[[Datei:einheitsvektor.png]] &lt;br /&gt;
&lt;br /&gt;
Der Einheitskreis ist wie folgt Beschriftet. In Blau sind die Bogenmaß Werte angegeben, in dunkelgrün die äquivalenten Werte der Kosinusfunktion und Orang ist der Winkel. Wenn man den Kosinus und Sinus von dem Winkel errechnet, dann erhält man den Hellgrünen x und Roten y Wert. Egal welchen Winkel man in der Sinus- und Kosinus-Funktion einsetzt, der Wert wird nie größer 1 oder kleiner -1 werden. Aber halt, wieso &lt;br /&gt;
==Trigonometrie im allgemeinen Dreieck==&lt;br /&gt;
Man unterscheidet in der Trigonometrie zwischen rechtwinkligen Dreiecken und allgemeinen Dreiecken.&lt;br /&gt;
Die allgemeinen Dreiecke sind allerdings für den weiteren Verlauf des Artikels wichtig und werden deswegen behandelt.&lt;br /&gt;
&lt;br /&gt;
===Sinus- und Kosinussatz===&lt;br /&gt;
Ein wichtige Gleichung, welche später wieder aufgegriffen werden wird, ist der Kosinutzsatz.&lt;br /&gt;
Doch zuvor sollte der Sinussatz genauer betrachtet werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:sinussatz.png]]&lt;br /&gt;
&lt;br /&gt;
Durch das Umstellen der Gleichungen kann man die einzelnen Winkel oder Seiten, eines Dreiecks, erhalten. Hierzu werden entweder 2 Seiten und ein Winkel oder 2 Winkel und eine Seite benötigt.&lt;br /&gt;
&lt;br /&gt;
Der Kosinussatz&lt;br /&gt;
&lt;br /&gt;
[[Datei:kosinussatz.png]]&lt;br /&gt;
&lt;br /&gt;
ermöglicht es, entweder aus drei gegebenen Seiten die Winkel auszurechnen oder aus zwei Seiten und ihrem Zwischenwinkel die gegenüber liegende Seite.&lt;br /&gt;
&lt;br /&gt;
===Eigenschaften und Formeln===&lt;br /&gt;
Es kann hilfreich sein, eine Sinus Funktion in eine Kosinus Funktion umzuwandeln oder umgekehrt. Hierzu benötigt man die Komplementärformeln, welche wie folgt aussehen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:costosin_sintocos.png]]&lt;br /&gt;
&lt;br /&gt;
Um den Rückgabewert, der Sinus- oder Kosinus-Funktion in den Bogenmaß um zu wandeln, gibt es folgende Umkehrfunktionen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:umkehrfunktion_sin_cos_tan.png]]&lt;br /&gt;
&lt;br /&gt;
Es ist zu beachten, dass diese den Bogenmaß zurück geben und diese für Gradmaß entsprechend umgerechnet werden müssen.&lt;br /&gt;
&lt;br /&gt;
=Vektor=&lt;br /&gt;
Ein Vektor kann mit einem Array oder einer Liste vergleicht werden, wenn man z.B. einen 3-dimensionalen Vektor meint, dann wäre es ein Array mit 3 Elementen.&lt;br /&gt;
Die übliche Schreibweise eines Vektors sieht wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:generischer_vektor.png]]&lt;br /&gt;
&lt;br /&gt;
Eine entsprechende C++ Representation wäre z.B. folgende&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
  public:&lt;br /&gt;
    float m_Vec[4];&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
OpenGL verwendet auf der Grafikkarte immer 4-dimensionale Vektoren, auch wenn nur 1 oder 3 benötigt werden. Die restlichen Elemente des Vektors werden dann mit 0 aufgefüllt. Vektoren werden in OpenGL in 2 Arten verwendet, als absoluter und als relativer Wert. Absolute Werte wären z.B. Positionen und Farbwerte wärend relative Werte z.B. eine Transformation wäre. Der OpenGL Vektor sieht wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
==Einheitsvektor==&lt;br /&gt;
Ein besondere Form eines Vektors ist der Einheitsvektor, welcher immer eine Länge von 1 ergibt. Der Einheitsvektor wird normalerweise als klein e gekennzeichnet.&lt;br /&gt;
&lt;br /&gt;
Die Berechnung eines Einheitsvektors wird später in der der Magnitude und Normalisierung Funktion näher erläutert. Einheitsvektoren sind als Normalen/Richtungsvektoren in OpenGL im Einsatz und ist die Basis für Rotationen.&lt;br /&gt;
&lt;br /&gt;
==Addition==&lt;br /&gt;
[[Datei:addition_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:addition_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Die Addition wird Komponentenweise ausgeführt, was bedeutet, man kann sich eine Addition von Vektoren als eine Addition von jeden einzelnen Element mit dem entsprechenden Element im anderem Vektor Vorstellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:addition_vektor_visual.png]]&lt;br /&gt;
&lt;br /&gt;
Die Addition von Vektoren kann man sich sehr einfach Vorstellen, in dem man die einzelnen Vektoren als Bewegungsbefehle sieht. Wenn man also 2 schritte vorwärts,einen schritt seitwärts laufen soll und danach ein halben Schritt vorwärts und ein Schritt seitwärts, dann kann man diese beiden Befehle auch zu einem Befehl zusammen fassen. Laufe 2 1/2 Schritte vorwärts und 2 Schritte Seitwärts und wir stehen am gleichen Punkt und dieser Befehl wäre dann unser Ergebnis Vektor c.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Addition(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]+b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Subtraktion==&lt;br /&gt;
[[Datei:subtraktion_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:subtraktion_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Hier gilt gleiches, wie bei der Addition, nur das Komponentenweise Subtrahiert wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Datei:Subtraktion_vektor_visual.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Subtraktion eines Vektors wendet man den ersten Befehl an und läuft z.B. 2 Schritte nach vorne und einen Seitwärts, dann wendet man den 2. Schritt an aber wechselt das Vorzeichen jeder einzelnen Komponente. Also wird ein positive Komponente zu einer negativen und eine negative zu einer Positiven. Wenn man also einen schritt seitwärts,nach links, laufen soll, dann läuft man ein Schritt seitwärts, nach rechts, sowie vorwärts statt rückwärts. Man kann eine Subtraktion über eine Addition realisieren, wenn man jede Subtraktion, den rechten Vektor zuvor invertiert und dann addiert.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Subtraktion(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]-b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Betrag==&lt;br /&gt;
[[Datei:magnitude_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Magnitude ist der Englische Begriff für die Berechnung des Betrags eines Vektors oder auch die Länge.&lt;br /&gt;
Die Länge des Vektors wird benötigt, wenn man einen Vektor Normalisieren will oder fest stellen möchte ob ein Vektor ein Einheitsvektor ist. &lt;br /&gt;
&lt;br /&gt;
[[Datei:betrag_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Der Betrag eines Vektors kann über den Satz des Pytagoras ermittelt werden, welcher die Wurzel der Summe, der Quadrate, aller Komponenten ist.&lt;br /&gt;
Dies ist natürlich für wenige gut Vorstellbar und daher hier mal eine bessere Erklärung. Ein Vektor kann in n Komponenten zerlegt werden, der 4 Komponenten Vektor von OpenGL in 4 Komponenten. Jede Komponente stellt eine Dimension dar, welche x,y,z und w sind. Pytagoras lernt man in der Schule im 2 Dimensionalen Raum kennen, also wie es im Abbild über diesen Text dargestellt ist. Die Regel besagt, das der Flächeninhalt einer Seite der Summe der anderen entspricht, also l²=x²+y².&lt;br /&gt;
Diese Flächen sind Quadratisch also hat jede Seite der Fläche die gleiche Kantenlänge. Wenn man die Quadratwurzel von der Fläche zieht, bekommt man also die Kantenlänge. Wenn man nun die Flächen von x,y,z und w summiert erhält man die Fläche l². Zieht man von l² die Quadratwurzel, dann hat man die Kantenlänge l von dem 4Komponenten Vektor, welche als Betrag oder Länge bezeichnet wird. Da bei einem Vektor w=0.0 gesetzt wird, hat diese keinen Einfluss auf diese Operation und wird in den Formeln auch in der Regel nicht mit hin geschrieben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
float Betrag(){&lt;br /&gt;
  float len=0.0;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    len+=this-&amp;gt;m_Vec[i]*this-&amp;gt;m_Vec[i];&lt;br /&gt;
  return sqrt(len);&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Skalarprodukt==&lt;br /&gt;
[[Datei:skalarprodukt_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Das Skalarprodukt erlaubt uns die Berechnung, des Winkels, zwischen 2 Vektoren. Hierfür müssen allerdings beide Vektoren Normalisiert sein, also jeweils einen Betrag von 1 ergeben. Sonnst muss dies noch nachträglich getan werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:skalarprodukt_vektor1.png]]&lt;br /&gt;
&lt;br /&gt;
Wenn die 2 Vektoren a und b vorliegen, sollte man davon ausgehen, dass der Betrag beider Vektoren jeweils 1 ist. Sollte es nicht der Fall sein, so wie im Bild über diesen Text, dann muss dies durch die Normalisierung nachgeholt werden. Dies passiert, indem man den Betrag beider Vektoren errechnet und dann diesen Komponentenweise mit dem Vektor dividiert. Die oben stehende Formel wird aus dem Kosinussatz abgeleitet und Umgestellt. Darraus ergibt sich am Ende, dass die Summe, der Komponentenweise multiplizierten Vektoren a und b den Kosinus des Winkels ergibt. Es ist wichtig zu beachten, dass nicht der Winkel sondern der Kosinus des Winkels in c wieder zu finden ist. Wenn man den Winkel haben möchte, dann muss man den Arkuskosinus von c berechnen und das Ergebnis von Bogenmaß in Gradmaß umwandeln um den Winkel(als Delta makiert) zu bekommen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
float Skalarprodukt(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  float alpha=0.0;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    alpha+=this-&amp;gt;m_Vec[i]*b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Kreuzprodukt==&lt;br /&gt;
[[Datei:kreuzprodukt_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Das Kreuzprodukt errechnet einen Vektor, der senkrecht zu den Vektoren a und b steht, wenn a und b den selben Ursprung haben. Dieses Verhalten wird genutz, um die Normale einer Fläche zu errechnen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:kreuzprodukt_vektor1.png]]&lt;br /&gt;
&lt;br /&gt;
Der berechnete Vektor hat wie schon erwähnt die Eigenschaft, dass er senkrecht zu den Vektoren a und b ausgerichtet ist. Dies bedeutet, dass der Winkel zwischen dem Berechnetem Winkel und a oder b immer 90° beträgt. Wenn a und b 2 von den 3 Eckpunkten, eines Dreiecks ist, dann zeigt der Vektor c senkrecht zum Dreieck und bildet den Richtungsvektor des Dreiecks. Wenn man nun noch diesen Vektor normalisiert, dann erhält man die Flächenormale. Diese hat den Betrag 1 und wird für verschiedene Rendertechniken, sowie Physikberechnungen benötigt.&lt;br /&gt;
Wenn z.B. ein Lichtstrahl solch ein Dreieck schneidet, dann kann man mit Hilfe des Vektors(vom Lichstrahl) und der Normale(der Fläche) den Reflektionsvektor berechnen und somit sagen, in welche Richtung sich das Licht weiter bewegen würde.&lt;br /&gt;
Es ist zu beachten, dass die Reihenfolge, in der man beide Vektoren Multipliziert einen Einfluss auf die Richtung, in die c zeigt.&lt;br /&gt;
Wenn man a und b tauscht, dann wechseln die Vorzeichen aller Komponenten von c.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
...&lt;br /&gt;
TVector4Float Kreuzprodukt(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  unsigned int prev,next;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
  {&lt;br /&gt;
    if (i==0)&lt;br /&gt;
      prev=3;&lt;br /&gt;
    else&lt;br /&gt;
      prev=i-1;&lt;br /&gt;
    next=i+1 % 4;//i+1 Modulog 4&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[next]*b.m_Vec[prev]-this-&amp;gt;m_Vec[prev]*b.m_Vec[next];&lt;br /&gt;
  }&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Normalisieren==&lt;br /&gt;
[[Datei:normalisieren_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Normalisierung wird der Betrag eines Vektors mit dem Vektor dividiert und man erhält ein Vektor, der in die Gleiche Richtung zeigt aber auf eine Länge 1 skaliert ist.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Normalisieren(){&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  c=(*this)/this-&amp;gt;Betrag();&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Matrix=&lt;br /&gt;
Eine Matrix kann man sich als 2-dimensionalen Array mit n und m Länge vorstellen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:generische_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
OpenGL verwendet 4x4 große Matrizen und kann aus 4 Vektoren mit einer Länge von 4 konstruiert werden.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
  protected: &lt;br /&gt;
    TVector4Float m_Matrix[4]; //Erlaubt uns das nutzen von der eigenen Vektorklarsse.&lt;br /&gt;
    float m_Array[16]; //für die LoadMatrix Funktion von OpenGL&lt;br /&gt;
  public:&lt;br /&gt;
    TVector4Float&amp;amp; Vektor(int Index)//Gibt eine Referenz vom Vektor zurück, was wie ein Pointer ist aber 100% auf ein Speicher zeigt, der existiert.&lt;br /&gt;
    { &lt;br /&gt;
      return m_Matrix[Index]; &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    T* GetMatrix1DArray()//Liefert den Pointer von der m_Array variable zurück.&lt;br /&gt;
    { &lt;br /&gt;
      //Überträgt die Daten von den einzelnen Vektoren in die OpenGL kompatible Matrix(m_Array).&lt;br /&gt;
      for (int i=0;i&amp;lt;4;i++)&lt;br /&gt;
        memcpy(&amp;amp;m_Array[i*4],&amp;amp;m_Matrix[i][0],16);&lt;br /&gt;
      return &amp;amp;m_Array[0];//Gibt den Pointer auf m_Array zurück.&lt;br /&gt;
    }&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Für Matrizen brauchen wir nicht so viele Funktionen wie bei Vektoren, um genau zu sagen brauchen wir 2 Operationen. Diese Operationen lauten Transponieren und Multiplikation.&lt;br /&gt;
Bei der Matrix benötigen wir einige Konstruktionsfunktionen und zwar Identity, Translate, Rotate  und Scale Matrix. Diese Matrizen machen die ganze Arbeit für uns, wenn man sich in einem 3D Raum bewegen möchte, welcher als Modelview Matrix abgebildet wird.&lt;br /&gt;
&lt;br /&gt;
==Transponieren==&lt;br /&gt;
[[Datei:transponieren_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
Transponieren wird durch ein großes T über der Matrix dargestellt. Diese Funktion tauscht die Werte einer Matrix miteinander aus, so das aus einer Spalten konstruierten Matrix eine Zeilenweise konstruierte Matrix wird. Diese Funktion kann Hilfreich sein, wenn man zwischen Direct3D und OpenGL Daten austauschen will, denn nicht jeder nutzt spalten orientierte Matrizen.&lt;br /&gt;
&lt;br /&gt;
[[Datei:opengl_matrix.png‎]][[Datei:d3d_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Transponieren()&lt;br /&gt;
{ &lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[1],m_Matrix.Vektor(1).m_Vec[0]); //swap kopiert b in tmp, kopiert a in b und tmp in a&lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[2],m_Matrix.Vektor(2).m_Vec[0]); &lt;br /&gt;
  swap(m_Matrix.Vektor(0).m_Vec[3],m_Matrix.Vektor(3).m_Vec[0]); &lt;br /&gt;
&lt;br /&gt;
  swap(m_Matrix.Vektor(1).m_Vec[2],m_Matrix.Vektor(2).m_Vec[1]); &lt;br /&gt;
  swap(m_Matrix.Vektor(1).m_Vec[3],m_Matrix.Vektor(3).m_Vec[1]); &lt;br /&gt;
&lt;br /&gt;
  swap(m_Matrix.Vektor(2).m_Vec[3],m_Matrix.Vektor(3).m_Vec[2]); &lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Multiplikation==&lt;br /&gt;
Multiplikation ist die wichtigste Operation bei Matrizen, wenn wir uns mit OpenGL beschäftigen.&lt;br /&gt;
Dies liegt daran, dass OpenGL 2 verschiedene Matrizen verwendet, um Vektoren in Bildschirmkoordinaten um zu wandeln. Damit dies Funktioniert muss jeder Vektor mit diesen Matrizen jeweils multipliziert werden. Um eine Matrix zu manipulieren wird diese mit einer Konstruierten Matrix multipliziert. Diese Operation die ist meist ausgeführte Operation sowohl in der OpenGL Pipeline als auch in einem Spiel. Seit OpenGL3 gibt es kein Matrizen support mehr, was bedeutet, dass man diese selber implementieren muss und dann die fertigen Matrizen an OpenGL übergibt. Die lässt viel Raum für Optimierung und kann somit ein OpenGL3 Programm schneller machen als ein OpenGL2 Programm, wenn man zuvor die glTranslate,glRotate und weiteren Funktionen verwendet hat. Es ist also ratsam sich eine sehr Performance Bibliothek zu laden oder mit einem Performance Analyzer bewaffnet den eigenen Code zu optimieren.&lt;br /&gt;
===Multiplikation mit einem Vektor===&lt;br /&gt;
[[Datei:multiplikation_matrix_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:multiplikation_matrix_vektor1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Um eine Matrix mit einem Vektor zu multiplizieren, braucht man man nur den Vektor[n] von der Matrix mit der Komponente[n] von dem Vektor multiplizieren und die resultierenden Vektoren anschließend addieren. Hierbei wird also ein Vektor mit einer einzelnen Komponente multipliziert, was weiter oben, bei den Vektoren, erklärt wurde.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Multipliziere(TVector4Float V) &lt;br /&gt;
{ &lt;br /&gt;
  TVector4Float v=m_Matrix.Vektor(0)*V.m_Vec[0]+m_Matrix.Vektor(1)*V.m_Vec[1]+m_Matrix.Vektor(2)*V.m_Vec[2]+m_Matrix.Vektor(3)*V.m_Vec[3];&lt;br /&gt;
  return v; &lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Multiplikation mit einer Matrix===&lt;br /&gt;
[[Datei:multiplikation_matrix.png‎]]&lt;br /&gt;
&lt;br /&gt;
[[Datei:multiplikation_matrix1.png‎]]&lt;br /&gt;
&lt;br /&gt;
Es sieht recht aufwändig aus allerdings kann man es dank der vorigen Matrix-Vektor Multiplikation auf eine recht übersichtliches Maß runter streichen. Man braucht dann nur noch die Matrix a jeweils mit einen der Vektoren von Matrix b multiplizieren und hat die Matrix-Matrix Multiplikation erledigt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
TMatrix4x4Float Multiplikation(TMatrix4x4Float M) &lt;br /&gt;
{ &lt;br /&gt;
  TMatrix4x4Float M1((*this)*M.Vektor(0)), (*this)*M.Vektor(1), (*this)*M.Vektor(2), (*this)*M.Vektor(3)); &lt;br /&gt;
  return M1;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Konstruieren von Matrizen=&lt;br /&gt;
&lt;br /&gt;
==Identity==&lt;br /&gt;
Die Identity Matrix ist die Initialisierungsmatrix, mit der alle Matrizen belegt werden.&lt;br /&gt;
Diese ist recht einfach und hat denn Sinn, dass bei einer Multiplikation immer der Wert herraus kommt, mit dem diese Multipliziert wurde.&lt;br /&gt;
Wer aufmerksam gelsen hat, der wird nun an Einheitsvektoren denken und liegt richtig.&lt;br /&gt;
Aufgrund der beschaffenheit einer Matrix benötigen wir in jeder Reihe und Spalte jeweils ein Element, welche den Wert 1 an nimmt und die restlichen nehmen den Wert 0 an. Die sieht dann wie folgt aus.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Es ist nicht zwingend notwendig die Einheitsvektoren in dieser Reihenfolge zu verwenden, man könnte auch den ersten und dritten Vektor tauschen und es würde trotzdem das gleiche Ergebnis geben.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
static TVector4Float Identity[4];//Statische Variable, welche nur einmal existiert.&lt;br /&gt;
&lt;br /&gt;
void LadeIdentity()&lt;br /&gt;
{&lt;br /&gt;
  for (int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    m_Matrix.Vektor(i)=Identity.m_Vec[i];&lt;br /&gt;
}&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
TVector4Float TMatrix4x4Float::Identity[4]={TVector4Float(1.0,0.0,0.0,0.0),TVector4Float(0.0,1.0,0.0,0.0),TVector4Float(0.0,0.0,1.0,0.0),TVector4Float(0.0,0.0,0.0,1.0)};&amp;lt;/source&amp;gt;&lt;br /&gt;
==Translate==&lt;br /&gt;
Wenn man ein Vektor oder Matrix in x,y,z bewegen möchte, dann kann man dies mit einer Transformationsmatrix erreichen.&lt;br /&gt;
Dazu erstellt man eine Matrix, füllt sie mit der Identity Matrix und setzt dann x,y,z in der Matrix mit den zu x,y,z Werten, um die man etwas verschieben möchte.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Translate(float x,float y,float z)&lt;br /&gt;
{&lt;br /&gt;
  TKar_Matrix&amp;lt;KAR_MATH_TYPE&amp;gt; m;&lt;br /&gt;
  m.Vektor(3).m_Vec[0]=x;&lt;br /&gt;
  m.Vektor(3).m_Vec[1]=y;&lt;br /&gt;
  m.Vektor(3).m_Vec[2]=z;&lt;br /&gt;
  (*this)*=m;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
==Rotate==&lt;br /&gt;
Das Bewegen auf den 3 Achsen ist allerdings oft nicht ausreichend und deswegen gibt es auch eine Rortations-Matrix.&lt;br /&gt;
Die Rotations-Matrix wird durch 3 Vektoren beschrieben, welche jeweils für die x,y und z Achse zuständig sind.&lt;br /&gt;
Man kann die Rotation, der einzelnen Achsen in einem Schritt oder in 3 einzelne Aufteilen. Um die Rotationsmatrix besser zu verstehen werden erst einmal alle Achsen einzeln betrachtet.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die Z-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_rotz.gif]][[Datei:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(3. Spalte=0.0, 0.0, 1.0, 0.0) bleibt bei der Rotation unverändert - man nehme einen Finger, deute damit nach vorne. Nun drehe man diesen Finger um seine eigene Achse, wohin zeigt er? In die selbe Richtung wie vor der Drehung? Damit entspricht Z-Achsen Einheitsvektor auch der vorletzen Spalte der Matrix: (0.0, 0.0, 1.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Der X-Achsen Einheitsvektor(1. Spalte=1.0, 0.0, 0.0 0.0) dreht sich hingegen mit. Trigonometrie findet der Lösung Spur. Ein Blick auf das Bild zum Einheitskreis zeigt, dass wir gerade das gleiche Problem für X und Y zu bewältigen haben: Die Rotationsachse ist in beiden Fällen die Z-Achse. Der Einheitsvektor, der gedreht wird, ist der X-Achsen Einheitsvektor also:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;x = cos(ß)&lt;br /&gt;
y = sin(ß)&amp;lt;/source&amp;gt;&lt;br /&gt;
womit der Inhalt der ersten Spalte der Matrix kennen: (cos(ß), sin(ß), 0.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Dies kann man auch auf den Y-Achsen Einheitsvektor(2. Spalte=0.0, 1.0, 0.0, 0.0) übertragen, man muss nur bedenken in welcher weise sich x und y vertauschen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;x = -sin(ß)&lt;br /&gt;
y = cos(ß)&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß), cos(ß), 0.0, 0.0)&lt;br /&gt;
&lt;br /&gt;
Nun kann man die Rotationsmatrix für die Rotation auf der Z-Achse beschreiben, die Matrix findet man am Anfang des Abschnittes.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die Y-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_roty.gif]][[Datei:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Die Berechnung der Matrix wird auf die gleiche weise ermittelt, wie bei der Berechnung der Z-Achsen Rotationsmatrix.&lt;br /&gt;
&lt;br /&gt;
===Drehen um die X-Achse===&lt;br /&gt;
&lt;br /&gt;
[[Datei:Tutorial_Nachsitzen_rotx.gif]][[Datei:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Rotation um alle Achsen mit einer Matrix===&lt;br /&gt;
&lt;br /&gt;
Es ist recht aufwändig für die CPU und für den Programmierer immer 3 Rotationen aus zu führen, deswegen hat man diese auch zu einer einzigen Operation zusammen gefasst. Die Matrizen werden einfach miteinander multipliziert und es kommt eine Rotationsmatrix herraus, welche 3 Eingabeparameter benötigt, alpha, beta und gamma sind dabei die Winkel für X-,Y- und Z-Achse.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rotationsmatrix_3angle.png]]&lt;br /&gt;
&lt;br /&gt;
Eine weitere Möglichkeit, um eine Rotationsmatrix zu erstellen, wäre das nutzen eines Richtungsvektors und einem Winkel. Hierbei wird der Winkel auf den Richtungsvektor angewendet, wenn also man als Vektor (1,0,0) verwendet dann hat man eine Rotation auf der X-Achse, (0,1,0) Y-Achse und (0,0,1) für die Z-Achse. Man kann nun auch Vektoren wie (1,1,1) angeben, wobei die Funktion diesen Vektor dann normalisieren wird, damit er noch auf das Einheitskreis System funktioniert. Dieser Vektor ist nicht equivalent mit dem Rotieren von X-,Y- und Z-Achse nacheinander. Der Vorteil hierbei liegt in der Kompaktheitund des Codes und man kann auf Algorithmen zurück greifen, die vor OpenGL3 entwickelt wurden, da der OpenGL Treiber früher die Rotation über diese Variante Implementiert hatte.&lt;br /&gt;
&lt;br /&gt;
[[Bild:rotationsmatrix.png]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{ &lt;br /&gt;
//...&lt;br /&gt;
void Rotiere(float w,float x,float y,float z)&lt;br /&gt;
{&lt;br /&gt;
  TMatrix4Float m;&lt;br /&gt;
  float rad=DegToRad(w);&lt;br /&gt;
  float c=cos(rad);&lt;br /&gt;
  float ic=1.0-c;&lt;br /&gt;
  float s=sin(rad);&lt;br /&gt;
  TVector4Float v(x,y,z,0.0);&lt;br /&gt;
  float mag=sqrt((v*v).Summe());&lt;br /&gt;
&lt;br /&gt;
  if (mag&amp;lt;=1.0e-4)&lt;br /&gt;
    return;&lt;br /&gt;
&lt;br /&gt;
  v.m_Vec[0]=x/mag;&lt;br /&gt;
  v.m_Vec[1]=y/mag;&lt;br /&gt;
  v.m_Vec[2]=z/mag;&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(0).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[0]*ic)+c;&lt;br /&gt;
  m.Vektor(0).m_Vec[1]=(v.m_Vec[0]*v.m_Vec[1]*ic)+(v.m_Vec[2]*s);&lt;br /&gt;
  m.Vektor(0).m_Vec[2]=(v.m_Vec[0]*v.m_Vec[2]*ic)-(v.m_Vec[1]*s);&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(1).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[1]*ic)-(v.m_Vec[2]*s);&lt;br /&gt;
  m.Vektor(1).m_Vec[1]=(v.m_Vec[1]*v.m_Vec[1]*ic)+c;&lt;br /&gt;
  m.Vektor(1).m_Vec[2]=(v.m_Vec[1]*v.m_Vec[2]*ic)+(v.m_Vec[0]*s);&lt;br /&gt;
&lt;br /&gt;
  m.Vektor(2).m_Vec[0]=(v.m_Vec[0]*v.m_Vec[2]*ic)+(v.m_Vec[1]*s);&lt;br /&gt;
  m.Vektor(2).m_Vec[1]=(v.m_Vec[1]*v.m_Vec[2]*ic)-(v.m_Vec[0]*s);&lt;br /&gt;
  m.Vektor(2).m_Vec[2]=(v.m_Vec[2]*v.m_Vec[2]*ic)+c;&lt;br /&gt;
&lt;br /&gt;
  *this*=m;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Scale==&lt;br /&gt;
[[Bild:skalierungsmatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Die Skalierung ist eine sehr einfache Matrix, in der für die 1, des Einheitsvektors, der entsprechende Skalierungsfaktor angegeben wird. Wenn man die Matrix mit einem Vektor multipliziert, dann werden X,Y und Z des Vektors mit den x,y und z Werten in der Skalierungsmatrix multipliziert und damit skaliert. Wenn man etwas größer machen will, dann wird der Wert entsprechend über 1.0 gewählt, z.B. 2.0 wäre doppelte größe und für verkleinern würde man ein Wert zwischen 1.0 und 0.0 wählen. Der Wert 0.5 würde z.B. eine Division durch 2 bedeuten, also 3*0.5=1.5. Der 4. Einheitsvektor wird belassen, da wir diesen nur als Kompatibilität zu den 4Komponenten Vektoren benötigen.&lt;br /&gt;
&lt;br /&gt;
=Vom Vektor zur Bildschirmkoordinate=&lt;br /&gt;
Auf in den Endspurt!&lt;br /&gt;
Alle Mathematischen Formeln und Funktionen benötigen wir um die letzten 2 Punkte behandeln zu können.&lt;br /&gt;
Die Rede ist von der Umwandlung eines Vektors im 3D Raum in den 2D Raum, auf dem Bildschirm.&lt;br /&gt;
In Rahmen dieses Artikel wird nur auf die Transformation der Vektoren eingegangen und in einem späterem Artikel dann die weiteren Zwischenschritte zum Zeichnen einer Geometrie.&lt;br /&gt;
==Modelview==&lt;br /&gt;
[[Bild:weltkoordinatensystem-vs-modellkoordinatensystem.png]]&lt;br /&gt;
[[Bild:translation-vs-rotation.png]]&lt;br /&gt;
&lt;br /&gt;
Die Modelview kann man sich wie ein 3D Unterraum vorstellen oder einer Transformation des Raumes. Die Modelview sorgt dafür, dass alle Vektoren, die mit dieser Multipliziert werden zu dieser Modelview ausgerichtet werden und die Modelview ist relativ zur Welt ausgerichtet. Dies bedeutet, wenn man für jedes Objekt eine Modelview erzeugt, dann kann dieses Objekt relativ zur Welt ausgerichtet werden, sobald man die Vektoren des Objektes mit der Modelview multipliziert. Wieso richtet man die Vektoren nicht gleich zur Welt aus, statt den Umweg über die Modelview Matrix zu gehen ? Die Antwort ist schlicht &amp;quot;Optimierung&amp;quot;. Es wäre zu langsam, wenn man jeden Renderdurchgang jedes einzelne Vertex im Speicher lesen müsste, die neue Position berechnen, im Speicher updaten und in der Pipeline weiter zu arbeiten. Es ist auch Speichereffizienter, da z.B. gleiche Objekte nur einmal in den Speicher abgelegt werden müssen und nur 2 unterschiedliche Modelview Matrizen benötigt werden.&lt;br /&gt;
&lt;br /&gt;
Im rechten Bild kann man 2 aufeinander folgende Befehlsketten sehen, die Transformationen auf ein Objekt ausführen. Dieses Bild soll nocheinmal verdeutlichen, dass das Anwenden von Befehlen, auf eine Modelview Matrix nicht Kommultativ(a*b ist nicht das gleiche wie b*a) ist.&lt;br /&gt;
&lt;br /&gt;
Während vor OpenGL3 die Modelview Matrix von den OpenGL Treibern verwaltet wurde, muss dies ab OpenGL3 vom User gemacht werden und auch das aktualisieren in der Renderpipeline muss nun vom Entwickler übernommen werden, wie dies funktioniert wird in einem späteren Artikel erklärt. Es ist nur noch wichtig zu sagen, dass die GPU diese Matrix mit jeden Vertex multipliziert, der durch dir Renderpipeline geschickt wird.&lt;br /&gt;
&lt;br /&gt;
==Normal-Matrix==&lt;br /&gt;
Die Normal-Matrix wurde vor OpenGL3 als [[gl_NormalMatrix]] automatisch berechnet aber mit OpenGL3 ist auch diese aus dem Treiber entfernt worden.&lt;br /&gt;
Dies hat zufolge, dass man diesen Schritt selber vollziehen muss und aufgrund der Wichtigkeit dieser Matrix sollte man versuchen diese auch zu verinnerlichen.&lt;br /&gt;
Mit der gl_NormalMatrix kann man ein Normale von dem Texture-Space in den World-Space transformieren. &lt;br /&gt;
Dies ist wie bei der Multiplikation eines Vertex mit der [[gl_ModelViewMatrix]], nur das die Konstruktion der gl_NormalMatrix andere Anforderungen hat und deswegen zusätzlich generiert wird.&lt;br /&gt;
&lt;br /&gt;
Eine Normale ist ein Vektor, welcher die Länge 1 hat und repräsentiert die Flächenausrichtung.&lt;br /&gt;
Wenn man ein Dreieck auf der X,Y,Z Achse bewegt, dann hat dies keinen Einfluss auf die Werte einer Normale.&lt;br /&gt;
Sollte man ein Dreieck aber Rotieren oder Skalieren, dann verändern sich die Werte einer Normale, welcher den Unterschied zwischen gl_NormalMatrix und gl_ModelviewMatrix aus macht.&lt;br /&gt;
Es gibt einen Spezialfall beim skalieren, sollte die Skalierung aller Dimensionen mit dem gleichen Wert durchgeführt werden, dann ändert sich die Normale nicht.&lt;br /&gt;
Die gl_NormalMatrix wird errechnet, indem man die Determinante von gl_ModelviewMatrix Transponiert.&lt;br /&gt;
Erreichen kann man dies, indem man den Rotationsanteil der Modelview Matrix in eine 3x3 Matrix kopiert, die Determinante errechnet und anschließend die Matrix transponiert.&lt;br /&gt;
&lt;br /&gt;
Um nun die Normale in den World-Space zu transformieren kann man folgende Berechnung anwenden.&lt;br /&gt;
Normal=normalize(gl_NormalMatrix*gl_Normal);&lt;br /&gt;
Nach der Multiplikation wird das Ergebnis normalisiert, da eine Normale immer die Länge 1.0 haben muss und durch die Möglichkeit, dass eine Skalierung mit unterschiedlichen Werte auf jeder Achse, dies sonnst nicht gewährleistet wäre.&lt;br /&gt;
Aufgrund der Normalisierung entsteht der vorher erwähnte Sonderfall, bei dem eine Skalierung mit ein und dem selben Skalar keinen Änderungen zufolge hat.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TMatrix4x4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
    protected:&lt;br /&gt;
        TMatrix3x3Float m_NormalMatrix;&lt;br /&gt;
    public:&lt;br /&gt;
        TMatrix3x3Float&amp;amp; NormalMatrix()&lt;br /&gt;
        {&lt;br /&gt;
          TMatrix3x3Float tnmat;&lt;br /&gt;
          float d;&lt;br /&gt;
          //Kopiere den Rotations- und Skalierungsanteil aus der Modelview Matrix.&lt;br /&gt;
          for (unsigned int i=0;i&amp;lt;3;i++)&lt;br /&gt;
            for (unsigned int j=0;j&amp;lt;3;j++)&lt;br /&gt;
              m_NormalMatrix.Value[i*3+j]=this-&amp;gt;Value[i*4+j];&lt;br /&gt;
&lt;br /&gt;
          //Determinante berechnen und Transponieren in einem Schritt(im Fall der Rotationsmatrix&lt;br /&gt;
          //ist es nicht wichtig in welcher Reihenfolge Transponieren und Determinieren geschehen.)&lt;br /&gt;
&lt;br /&gt;
          d=Determinant(m_NormalMatrix);&lt;br /&gt;
          tnmat[0]=m_NormalMatrix[4]*m_NormalMatrix[8]-m_NormalMatrix[5]*m_NormalMatrix[7];&lt;br /&gt;
          tnmat[3]=m_NormalMatrix[5]*m_NormalMatrix[6]-m_NormalMatrix[3]*m_NormalMatrix[8];&lt;br /&gt;
          tnmat[6]=m_NormalMatrix[3]*m_NormalMatrix[7]-m_NormalMatrix[4]*m_NormalMatrix[6];&lt;br /&gt;
&lt;br /&gt;
          tnmat[1]=m_NormalMatrix[2]*m_NormalMatrix[7]-m_NormalMatrix[5]*m_NormalMatrix[8];&lt;br /&gt;
          tnmat[4]=m_NormalMatrix[0]*m_NormalMatrix[8]-m_NormalMatrix[2]*m_NormalMatrix[6];&lt;br /&gt;
          tnmat[7]=m_NormalMatrix[1]*m_NormalMatrix[6]-m_NormalMatrix[1]*m_NormalMatrix[7];&lt;br /&gt;
&lt;br /&gt;
          tnmat[2]=m_NormalMatrix[1]*m_NormalMatrix[5]-m_NormalMatrix[2]*m_NormalMatrix[4];&lt;br /&gt;
          tnmat[5]=m_NormalMatrix[2]*m_NormalMatrix[3]-m_NormalMatrix[0]*m_NormalMatrix[5];&lt;br /&gt;
          tnmat[8]=m_NormalMatrix[0]*m_NormalMatrix[4]-m_NormalMatrix[1]*m_NormalMatrix[3];&lt;br /&gt;
&lt;br /&gt;
          for (unsigned int i=0;i&amp;lt;3;i++)&lt;br /&gt;
            for (unsigned int j=0;j&amp;lt;3;j++)&lt;br /&gt;
              m_NormalMatrix[i*3+j]=tnmat[i*3+j]/d;&lt;br /&gt;
          return tnmat;&lt;br /&gt;
        }&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Projectionview==&lt;br /&gt;
Die Projektions Matrix oder auch Projectionview genannt ist die 2. wichtige Matrix in der Renderpipeline.&lt;br /&gt;
Diese Matrix macht den ganzen Zauber, der Umwandlung von 3D in 2D erst möglich.&lt;br /&gt;
Wenn die Vertice mit der Modelview Matrix multipliziert wurden, wird nun das Ergebnis mit der Projektions Matrix multipliziert und wir erhalten Vektoren, dessen X und Y Komponente den Bildischrmpunkten entsprechen. Die 2 am häufigsten genutzten Matrizen sind die Perspektivische- und die Orthogonale Ansicht.&lt;br /&gt;
&lt;br /&gt;
===Perspektive===&lt;br /&gt;
&lt;br /&gt;
[[Bild:GluPerspective_Quads_X.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die Perspektivische Ansicht ist eine drei Dimmensional wirkende Ansicht, welche durch mehrere Faktoren beeinflusst wird.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GluPerspective.png]]&lt;br /&gt;
&lt;br /&gt;
aspect steht für aspect ratio und beschreibt das Bildverhältnis von Höhe und Breite.&lt;br /&gt;
Diese ist sehr leicht herraus zu finden, man dividiert einfach die Breite durch die Höhe, wenn man die Renderausgabe von der Bildschirmbreite abhängig machen möchte oder umgekerht, für die Bildschirmhöhe.&lt;br /&gt;
f kann durch folgende Formel berechnet werden und bestimmt den Blickwinkel, welcher alle x und y Koordinaten zusammen staucht oder auseinander zieht. Dies erkennt man recht schnell, wenn man sich an die Skalierungsmatrix erinnert und das eine Multiplikation mit einem Vektor die x und y Komponenten skaliert.&lt;br /&gt;
&lt;br /&gt;
[[Bild:sichtwinkel.png]]&lt;br /&gt;
&lt;br /&gt;
zNear und zFar sind die Abstände, der Near- und Far-Clipping Plane, zur Kamera. Alle Objekte, die den Raum, zwischen beiden Ebenen nicht schneidet, wird verworfen und der rest durchläuft die restliche Renderpipeline. Die Thematik wird in einem späterem Artikel näher erläutet.&lt;br /&gt;
&lt;br /&gt;
===Orthogonal===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Orthomode_Quads.jpg]]&lt;br /&gt;
&lt;br /&gt;
Die Orthogonale Ansicht ist eine zwei Dimmensionale Ansicht, welche wie die gewöhnlichen Desktopsysteme wirkt.&lt;br /&gt;
Hierbei werden die Z Koordinaten nicht zur Verschiebung der Bildpunkte, in der Tiefe verwendet.&lt;br /&gt;
&lt;br /&gt;
[[Bild:GlOrtho_Matrix.png]]&lt;br /&gt;
&lt;br /&gt;
Mit r, l, b, t, f und n sind der rechte, linke, untere und obere Rand, sowie Distanz der far und near clipping plane, des Bildschirmausschnittes, gemeint. Die far und near clipping plane sind parallel, zum Betrachter, ausgerichtete Ebenen. Alles was zwischen diesen beiden Ebenen liegt wird gezeichnet und alles außerhalb wird in der Pipeline verworfen.&lt;br /&gt;
&lt;br /&gt;
=Exkurs in die Optimierung=&lt;br /&gt;
==Vektoren==&lt;br /&gt;
Man hat oft den Fall, dass man auf der CPU mehrere Werte multiplizieren, dividieren, addieren, subtrahieren muss z.B. bei Bildbearbeitung.&lt;br /&gt;
&lt;br /&gt;
Dieses kann man Optimieren, indem man Vektoren verwendet, dabei wird ein Pixel als Vektor interpretiert und nun kann man alle Farbkanäle mit einen einzigen Aufruf verarbeiten lassen, indem man die Vektoroperationen verwendet. Wenn die Vektoren mit einer CPU Extension wie SSE oder MMX implementiert wurden, dann werden die 4 Komponenten eines Vektors sogar gleichzeitig verarbeitet. Sollte man nur 2 oder 3 Komponenten verwenden, dann füllt man die restlichen Komponenten mit 0 auf bzw. ignoriert sie einfach beim auslesen der Komponenten.&lt;br /&gt;
===Multiplikation===&lt;br /&gt;
[[Datei:multiplikation_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Die Multiplikation von 2 Vektoren miteinander ist eigentlich nicht definiert, da es wenig Sinn macht aber wir haben nun einen Verwendungszweck gefunden und definieren ihn. Bei dieser Operation gilt das gleiches, wie bei der Addition und Subtraktion, nur mit einem Mulltiplikations Operator. Die Bildverarbeitung wird sich mit mehr Geschwindigkeit bedanken.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Multiplikation(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]*b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Division===&lt;br /&gt;
[[Datei:division_vektor.png‎]]&lt;br /&gt;
&lt;br /&gt;
Bei der Division muss man aufpassen, dass keiner der Element im Divisor 0 ist, da sonnst eine Division mit 0 entsteht. Eine Division mit 0 hat ein Interrupt zufolge, welcher das Programm zum beenden bittet. Also sollte man dies Vorher überprüfen oder bei einer Division den Aufruf mit einer entsprechenden Routine den Fehler abfangen. Sonnst verhält es wie bei der Multiplikation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;class TVector4Float&lt;br /&gt;
{&lt;br /&gt;
//...&lt;br /&gt;
TVector4Float Division(TVector4Float b)&lt;br /&gt;
{&lt;br /&gt;
  TVector4Float c;&lt;br /&gt;
  for (unsigned int i=0;i&amp;lt;4;i++)&lt;br /&gt;
    c.m_Vec[i]=this-&amp;gt;m_Vec[i]/b.m_Vec[i];&lt;br /&gt;
  return c;&lt;br /&gt;
}&lt;br /&gt;
};&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Programmiersprache,Compiler und CPU Extension==&lt;br /&gt;
Die Optimierung ist von Programmiersprache und Compiler stark abhängig. Wärend Delphi, Freepascal und MS VSC++ Compiler man nur aufwändig SSE,MMX und weitere CPU Extension implementieren kann, hat der GCC eine Vektorextension und seit Version 4.x auch eine Funktionsoptimierung. Die Vektorextension von GCC ist ein Parser Erweiterung, welche einen Typ als ein bestimmten Vektortyp(z.B. Float Länge 4) bestimmt und dann entsprechend alle Operationen in SSE1-4 oder MMX Code umwandelt. Seit Version 4.x gibt es eine Funktionsoptimierung, welche erlaubt im Quellcode mehrere Optimierungen gleichzeitig zu nutzen. Die bedeutet, dass man eine Funktion, wie Vektor.Magnitude() mehrfach implementiert und dann jeweils eine andere Optimierungs Aktiviert. Also Vektor.Magnitude_sse(), Vektor.Magnitude_mmx(),... und dann die jeweilige Funktion mit SSE,MMX oder ohne Optimierung markiert. Der Compiler optimiert dann diese Funktion für die jeweilige CPU Extension und man kann dann im Programmcode entsprechend der gegebenen Hardware auf die beste Mögliche Funktion umlenken. Dies hat den Vorteil, dass man nur noch eine Binary hat und alle CPUs(mehr Kern, ein Kern, Intel Petium1-4, AMD Athlon und so weiter) der gleichen Architektur Optimiert  Unterstützen kann. Dies ist ist nützlich, wenn man alte CPUs unterstützen will. Es würde sich also lohnen, wenn man sich viel Ärger und Code sparen will, den Code in GCC als Bibliothek zu implementieren und statisch oder dynamisch zu linken.&lt;br /&gt;
&lt;br /&gt;
==Templates und Generics==&lt;br /&gt;
Eine Optimierung die sich bei C++ stark auswirkt sind Templates, da diese die Eigenschaft aufweisen vom Compiler generiert zu werden. Dies bedeutet je nach Qualität des Compilers kann dieser Code starke Performanceschübe bekommen, wenn man die Operationen in Templates verpackt, da der Compiler oft Optimierungen machen kann, die man selber nicht kennt oder gar nicht machen will(Kompatibilität und Übersichtlichkeit). Templates entrollen z.B. konstante For Schleifen und wie schon vorher in den Codeschnipseln zu sehen war, haben wir davon einige in den Vektor Operationen. Das Entrollen von Schleifen entfernt eine menge Balast(Counter,Prüfung,..) welche sich auf die Performance auswirkt. Templates reduziert den Codeaufwand, da man viele weitere Implementierungen einspart(Vektor von Typ float, int, unsigned short, unsigned int, double, ...).&lt;br /&gt;
&lt;br /&gt;
==Testen testen testen==&lt;br /&gt;
Wenn man Performance Test macht, dann sollte man verschiedene Test machen und einer der teilweise oft unterschätzt wird ist der Create und Free Test. Sobald man eine Klasse benutzt wird beim erstellen des Objektes immer ein Speicher alloziert und dann der Konstruktor aufgerufen, was  Zeit kostet. Man sollte also einmal ein Test durchführen, der Vektoren und Matrizen erstellt und zerstört. Die Operation Test sollten die Vektoren und Matrizen vorher erstellen und in der Schleife wiederverwendet werden und nach beenden des Performance Trackings erst zerstört werden.&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3&amp;diff=24282</id>
		<title>Tutorial OpenGL3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3&amp;diff=24282"/>
				<updated>2009-11-03T12:32:36Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: /* Artikelreihe */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Vorwort=&lt;br /&gt;
Willkommen zur Einführung in OpenGL3.x.&lt;br /&gt;
Im Rahmen, dieses Artikels, werde ich versuchen die Grundlagen für die Nutzung von OpenGL3 zu legen und durch Pseudo Code die Verwendung von der API aufzeigen. Mit OpenGL Version 3 hat sich vieles, im Vergleich zu den Vorversionen, verändert und entsprechend ist der Umstieg von OpenGL1-2 auf 3 sehr zeitaufwändig. Diese Artikel Reihe richtet sich mehr an Anfänger als an Programmierer, die von der Vorversion umsteigen wollen.&lt;br /&gt;
&lt;br /&gt;
==OpenGL3 und die Vorgeschichte==&lt;br /&gt;
OpenGL ist viele Jahre alt und entsprechend gab es immer wieder neue Versionen und Änderungen. Doch entfernte sich OpenGL mit der Zeit vom aktuellen Stand der Technik und veraltete immer mehr. Die API wurde größer und größer, alte nicht mehr gebrauchte Funktionen wurden aus Kompatibilitätsgründen nicht entfernt und die Treiber wuchsen zu riesigen und komplexen Codewerken. Darunter hat entsprechend die Leistung und Qualität stark gelitten. Es musste ein radikaler Schnitt gemacht werden und man beschloss dies mit OpenGL Version 3 zu tun. So hat man sämtlichen Balast von früher raus gestrichen und eine Hand voll neuer Funktionen hinzugefügt. &lt;br /&gt;
&lt;br /&gt;
Um die Umstellung für Software leichter zu machen, beschloss man 2 verschiedene Profile zu unterstützen. Das erste Profil ist ein OpenGL3 fähiger Grafik Context, welcher auch die alten Befehle ausführen kann und somit die Umstellung schrittweise ermöglicht. Das zweite Profil ist ein OpenGL3 fähiger Grafik Context, welcher nur die als nicht veraltet(deprecated) makierten Funktionen ausführen kann und für neue Software gedacht ist. Sollte man mit dem 2ten Profil arbeiten und ruft dennoch eine alte Funktion auf, dann wirft diese ein Fehler und wird nicht ausgeführt. &lt;br /&gt;
&lt;br /&gt;
Mit den neuen Fähigkeiten der Grafikkarten entstanden parallel zu den OpenGL Versionen auch neue Shader Update. OpenGL verwendet Shader, um die Darstellung von 3D Modelle manipulieren zu können. So hat man anfangs mit Assembler ähnlichen Code und später mit C ähnlichen Code mini Programme geschrieben, welche auf dem Grafikprozessor lauffähig waren. Man hatte zwischen Vertice- und Fragment-Shadern/Programmen unterschieden. Mit dem Shader Modell 4 kam eine weitere Shader Kategorie hinzu, und zwar der Geometrie Shader. Wärend Vertice-Shader einzelne Punkte eines Drahtgitters manipulieren konnte, hat der Fragment-Shader das ausfüllen des Drahtgitters übernommen(shading) und die Geometrie-Shader erlauben die Manipulation des Drahtgitters. Während Shader in OpenGL1-2 nicht notwendig waren, kann man in OpenGL3 nicht ohne auskommen, da ein Vertex-/Fragment-Shader zum zeichnen benötigt wird. &lt;br /&gt;
&lt;br /&gt;
Ein sehr beliebtes Werkzeug, in OpenGL1-2, war der immidate mode, welcher das einfache zeichnen von 3D Daten erlaubte. Dieser wurde durch ein glBegin eingeleitet, ein glEnd beendet und alles was dazwischen stand wurde gezeichnet. Dies hatte allerdings auch seinen Preis, so war der Treibercode dadurch enorm komplexer geworden und es mussten aufgrund der vielen möglichen Variationen(gesetzte Flags) viele Prüfungen durchgeführt werden, um einen gültigen Rendercode zu erzeugen. Dieser wurde ebenfalls in OpenGL3 gestrichen und man muss nun sogenannte Vertex Buffer Objects(untermenge von Buffer Objects) verwenden. Diese haben den Vorteil, dass sie wesentlich schneller und recht einfach zu bedienen sind.&lt;br /&gt;
&lt;br /&gt;
In OpenGL1-2 war es möglich die Modelview und Projectionview Matrizen durch bestimmte API Befehle zu manipulieren. Die Modelview Matrix hat die Position eines Objektes so manipuliert, dass es den gewollten Platz in der 3D Welt eingenommen hat und die Projectionview Matrix hat dann die 3D Weltkoordinaten auf 2D Bildschirmkoordinaten transformiert. Mit OpenGL3 sind ist diese Möglichkeit entfernt worden, da nun der Vertexshader diese Arbeit übernommen hat und diese Funktionalität mehr in den Anwendercode als in die Bibliothek gehört.&lt;br /&gt;
&lt;br /&gt;
Die letzten 3 angesprochenen Punkte (Shader,immedate mode und Matrizen) haben großen Einfluss auf den Basis Code einer OpenGL3 Anwendung. Dieser fällt größer und umfangreicher aus als ein Basis Code für OpenGL1-2 aber wird später kaum größer, aufgrund der Schlankheit der neuen API.&lt;br /&gt;
&lt;br /&gt;
==Inhaltsverzeichnis==&lt;br /&gt;
===Grundlagen===&lt;br /&gt;
Artikel in diesem Bereich sind für OpenGL wichtig aber haben nicht direkt mit OpenGL zu tun.&lt;br /&gt;
&lt;br /&gt;
Man kann diese Artikel überspringen und später bei aufkommenden Fragen in diese hinein lesen.&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_Lineare_Algebra|Lineare Algebra]]&lt;br /&gt;
===Artikelreihe===&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Vorschau auf das kommende]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_Zeichenkontext|Erstellen eines Grafik Kontext]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_Das_Objekt_System_von_OpenGL3|Das Objekt System von OpenGL3]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Vertex Buffer Object]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Verfügbare Geometrie]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|GLSLang]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Geometryshader]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Transform Feedback]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Texturen]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Frame Buffer Object]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_Scissor_Clipping_DepthTest|Clipping/Scissor/Tiefen-Test]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Instancing]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Oclussion Query]]&lt;br /&gt;
&lt;br /&gt;
[[Tutorial_OpenGL3_dead|Conditional Rendering]]&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Scissor_Clipping_DepthTest&amp;diff=24281</id>
		<title>Tutorial OpenGL3 Scissor Clipping DepthTest</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Scissor_Clipping_DepthTest&amp;diff=24281"/>
				<updated>2009-11-03T12:30:47Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Clipping, Scissor und Tiefen-Test=&lt;br /&gt;
Clipping, Scissor und Tiefen-Test sind Optimierungsprozesse welche dafür sorgen, dass der Datenpool minimiert wird. Dabei ist die Clipping Funktion dafür zuständig Vertice und damit verbundene Daten aus der Renderpipeline zu werfen. Die Scissor Funktion soll den Shading-Prozess beschleunigen, also das errechnen der Pixelfarben für ein Dreieck reduzieren.&lt;br /&gt;
Der Tiefen-Test hat die gleiche Aufgabe wie der Scissor-Test aber reduziert die Datenmenge auf Basis anderer Informationen und soll zugleich das korrekte Zeichnen von sich überschneidender Geometry ermöglichen.&lt;br /&gt;
&lt;br /&gt;
==Clipping==&lt;br /&gt;
Der Clipping-Prozess wird nach dem errechnen der Vertexpositionen auf dem Monitor durch geführt. Diese erhält man durch das Multiplizieren der Projektionsmatrix mit der Modelviewmatrix und dem anschliessenden multiplizieren mit der Vertexposition. Die neue Vertexposition hat zwar noch 4 Komponenten aber beim Clipping werden nur X und Y betrachtet.&lt;br /&gt;
Man muss in allen OpenGL Versionen den Viewport einstellen, indem man [[glViewport]] verwendet.&lt;br /&gt;
Als Parameter übergibt man X,Y,Width und Height, welche zusammen ein Rechteck ergeben.&lt;br /&gt;
Dieses Rechteck ist nun der gültige Sichtebereich und alles ausserhalb von diesen ist nicht sichtbar und wird damit nicht in der Renderpipeline benötigt. Wenn nun also ein Dreieck nicht das Rechteck schneidet, dann wird es aus der Renderpipeline entfernt. Dies reduziert die zu behandelnden Dreiecke in den Anschliessenden Prozessschritten und spart Zeit ein.&lt;br /&gt;
&lt;br /&gt;
==Scissor==&lt;br /&gt;
Der Scissor-Prozess wird vor dem Fragmentshader durch geführt, dieser Schritt muss nicht durchgeführt werden. Der Scissor-Test kann über [[glEnable#GL_SCISSOR_TEST]] aktiviert werden und mit Hilfe von [[glScissor]] konfiguriert werden. Genau wie beim Clipping wird die X und Y Koordinate des Bildschirmpixels als Eingabe genommen aber im gegensatz zum Clipping-Test wird im Scissor-Test nur ein X/Y Wertepaar benötigt und nicht 3. Der Test ist daher recht einfach und kann bei komplexeren Shadern immense Summen an Zeit herraus holen. Folgender Code zeigt ein einfachen InBound check.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;bool InBoundCheck(const int X, const int Y, const int RectX, const int RectY, const unsigned int RectWidth, const unsigned int RectHeight)&lt;br /&gt;
{&lt;br /&gt;
  if ((X&amp;lt;=RectX+RectWidth) &amp;amp;&amp;amp; (X&amp;gt;=RectX))&lt;br /&gt;
    if ((Y&amp;lt;=RectY+RectHeight) &amp;amp;&amp;amp; (Y&amp;gt;=RectY))&lt;br /&gt;
      return true;&lt;br /&gt;
  return false;&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
Alle Pixel, die den Test bestehen, werden dann an den Fragmentshader weiter gereicht und der rest wird einfach verworfen.&lt;br /&gt;
Wenn ein Shader sehr komplex ist und z.B. mehrere Texelzugriffe macht, AntiAliasing aktiviert ist und/oder komplexe Berechnungen im Fragmentshader getan werden, dann kann durch das Verwerfen von Pixeln viel Zeit eingespart werden.&lt;br /&gt;
&lt;br /&gt;
==Tiefen-Test==&lt;br /&gt;
Der Tiefen-Test wird nach dem Scissor-Test ausgeführt und soll die Anzahl der zu verarbeitenden Pixel reduzieren und Dreiecksüberschneidungen korrekt darstellen. &lt;br /&gt;
Wenn man in einen Artikel, Blog oder Forum von Overdraw redet, dann hat dies mit dem Tiefen-Test zu tun. Overdraw ist der Zustand, wenn ein Bildschirmpixel mehrfach gezeichnet wird, also mehrere Dreiecke die gleiche X-,Y-Koordinate auf dem Bildschirm haben.&lt;br /&gt;
Der Tiefen-Test betrachtet die Z-Koordinate von dem Bildschirmpixel und schaut in einen Tiefenpuffer nach, ob das Fragment(aktueller Pixel vom Dreieck) sichtbar wäre. Jedes Fragment, welches durch ein Dreieck in der Pipeline verarbeitet wird, besitzt einen Tiefenwert Z und dieser wird in dem Tiefenpuffer Hinterlegt. Wenn man mit [[glEnable#GL_DEPTH_TEST]] den Tiefen-Test aktiviert, dann wird jedes Fragment mit einer definierten Funktion verarbeitet. Diese Funktion kann über [[glDepthFunc]] fest gelegt werden. Wenn die Funktion erfolgreich ist und true zurück gibt, dann wird der Z Wert in den Tiefenpuffer eingetragen und wird anschliessend vom Fragmentshader verarbeitet. Sollte der Test negativ ausfallen, dann wird der Tiefenwert nicht geschrieben und das Fragment verworfen.&lt;br /&gt;
Es ist sinnvoll, die Tiefen-Test Funktion nur auf kleinere oder gleiche Z Werte, als im Tiefenpuffer, fest zu legen. Wenn man nun seine Dreiecke von vorne nach hinten sortiert und rendert, dann werden nur die vordersten Fragmente, der Dreiecke gezeichnet. Sollten man die Dreiecke von hinten nach vorne zeichnen, dann wird jedes Fragment in der Szene durch den Fragmentshader geschliffen und die Framerate bricht stark ein. &lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Nvidia und ATI empfehlen das Rendern in 2 Schritten zu vollziehen. Im ersten Schritt wird mit Hilfe von [[glColorMask]] alle Kanälle ab geschalten, mit [[glDepthMask]] der Tiefenpuffer schreibar gemacht, der Tiefen-Test aktiviert, der Tiefen- und Farbpuffer geleert, die Texturen deaktivert([[glDisable#GL_TEXTURE_2D]]) und die nicht Transparente Geometry gezeichnet. Dieser Schritt ist zum erfassen der Z-Koordinaten. Anschliessend aktiviert man wieder alle Farbkanälle, deaktiviert das schreiben im Tiefenpuffer, Texturen und zeichnet nun ganz normal seine nicht Transparente Geometry und dann die Transparente. Dieses 2 Schritt verfahren ist um ein vielfaches schneller und wird immer schneller, des so komplexer die Shader und Geometry wird.}}&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Scissor_Clipping_DepthTest&amp;diff=24280</id>
		<title>Tutorial OpenGL3 Scissor Clipping DepthTest</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_OpenGL3_Scissor_Clipping_DepthTest&amp;diff=24280"/>
				<updated>2009-11-03T12:20:09Z</updated>
		
		<summary type="html">&lt;p&gt;Tak2004: Die Seite wurde neu angelegt: „=Clipping, Scissor und Tiefen-Test= Clipping und Scissor sind Optimierungsprozesse, welche dafür sorgen, dass der Datenpool minimiert wird. Dabei ist die Clippin…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Clipping, Scissor und Tiefen-Test=&lt;br /&gt;
Clipping und Scissor sind Optimierungsprozesse, welche dafür sorgen, dass der Datenpool minimiert wird. Dabei ist die Clipping Funktion dafür zuständig Vertice und damit verbundene Daten aus der Renderpipeline zu werfen. Die Scissor Funktion soll den Shading-Prozess beschleunigen, also das errechnen der Pixelfarbe für ein Dreieck reduzieren.&lt;br /&gt;
&lt;br /&gt;
==Clipping==&lt;br /&gt;
Der Clipping-Prozess wird nach dem errechnen der Vertexpositionen auf dem Monitor durch geführt. Diese erhält man durch das Multiplizieren der Projektionsmatrix mit der Modelviewmatrix und dem anschliessenden multiplizieren mit der Vertexposition. Die neue Vertexposition hat zwar noch 4 Komponenten aber beim Clipping werden nur X und Y betrachtet.&lt;br /&gt;
Man muss in allen OpenGL Versionen den Viewport einstellen, indem man [[glViewport]] verwendet.&lt;br /&gt;
Als Parameter übergibt man X,Y,Width und Height, welche zusammen ein Rechteck ergeben.&lt;br /&gt;
Dieses Rechteck ist nun der gültige Sichtebereich und alles ausserhalb von diesen ist nicht sichtbar und wird damit nicht in der Renderpipeline benötigt. Wenn nun also ein Dreieck nicht das Rechteck schneidet, dann wird es aus der Renderpipeline entfernt. Dies reduziert die zu behandelnden Dreiecke in den Anschliessenden Prozessschritten und spart Zeit ein.&lt;br /&gt;
&lt;br /&gt;
==Scissor==&lt;br /&gt;
Der Scissor-Prozess wird vor dem Fragmentshader durch geführt, dieser Schritt muss nicht durchgeführt werden. Der Scissor-Test kann über [[glEnable#GL_SCISSOR_TEST]] aktiviert werden und mit Hilfe von [[glScissor]] konfiguriert werden. Genau wie beim Clipping wird die X und Y Koordinate des Bildschirmpixels als Eingabe genommen aber im gegensatz zum Clipping-Test wird im Scissor-Test nur ein X/Y Wertepaar benötigt und nicht 3. Der Test ist daher recht einfach und kann bei komplexeren Shadern immense Summen an Zeit herraus holen. Folgender Code zeigt ein einfachen InBound check.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;bool InBoundCheck(const int X, const int Y, const int RectX, const int RectY, const unsigned int RectWidth, const unsigned int RectHeight)&lt;br /&gt;
{&lt;br /&gt;
  if ((X&amp;lt;=RectX+RectWidth) &amp;amp;&amp;amp; (X&amp;gt;=RectX))&lt;br /&gt;
    if ((Y&amp;lt;=RectY+RectHeight) &amp;amp;&amp;amp; (Y&amp;gt;=RectY))&lt;br /&gt;
      return true;&lt;br /&gt;
  return false;&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
Alle Pixel, die den Test bestehen, werden dann an den Fragmentshader weiter gereicht und der rest wird einfach verworfen.&lt;br /&gt;
Wenn ein Shader sehr komplex ist und z.B. mehrere Texelzugriffe macht, AntiAliasing aktiviert ist und/oder komplexe Berechnungen im Fragmentshader getan werden, dann kann durch das Verwerfen von Pixeln viel Zeit eingespart werden.&lt;br /&gt;
&lt;br /&gt;
==Tiefen-Test==&lt;br /&gt;
Der Tiefen-Test wird nach dem Scissor-Test ausgeführt und soll die Anzahl der zu verarbeitenden Pixel reduzieren und Dreiecksüberschneidungen korrekt darstellen. &lt;br /&gt;
Wenn man in einen Artikel, Blog oder Forum von Overdraw redet, dann hat dies mit dem Tiefen-Test zu tun. Overdraw ist der Zustand, wenn ein Bildschirmpixel mehrfach gezeichnet wird, also mehrere Dreiecke die gleiche X-,Y-Koordinate auf dem Bildschirm haben.&lt;br /&gt;
Der Tiefen-Test betrachtet die Z-Koordinate von dem Bildschirmpixel und schaut in einen Tiefenpuffer nach, ob das Fragment(aktueller Pixel vom Dreieck) sichtbar wäre. Jedes Fragment, welches durch ein Dreieck in der Pipeline verarbeitet wird, besitzt einen Tiefenwert Z und dieser wird in dem Tiefenpuffer Hinterlegt. Wenn man mit [[glEnable#GL_DEPTH_TEST]] den Tiefen-Test aktiviert, dann wird jedes Fragment mit einer definierten Funktion verarbeitet. Diese Funktion kann über [[glDepthFunc]] fest gelegt werden. Wenn die Funktion erfolgreich ist und true zurück gibt, dann wird der Z Wert in den Tiefenpuffer eingetragen und wird anschliessend vom Fragmentshader verarbeitet. Sollte der Test negativ ausfallen, dann wird der Tiefenwert nicht geschrieben und das Fragment verworfen.&lt;br /&gt;
Es ist sinnvoll, die Tiefen-Test Funktion nur auf kleinere oder gleiche Z, als im Tiefenpuffer, fest zu legen. Wenn man nun seine Dreiecke von vorne nach hinten sortiert und rendert, dann werden nur die vordersten Fragmente, der Dreiecke gezeichnet. Sollten man die Dreiecke von hinten nach vorne zeichnen, dann wird jedes Fragment in der Szene durch den Fragmentshader geschliffen und die Framerate bricht stark ein. &lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Nvidia und ATI empfehlen das Rendern in 2 Schritten zu vollziehen. Im ersten Schritt wird mit Hilfe von [[glColorMask]] alle Kanälle ab geschalten, der Tiefentest aktiviert, der Tiefen- und Farbpuffer geleert, die Texturen deaktivert([[glDisable#GL_TEXTURE_2D]]) und die nicht Transparente Geometry gezeichnet. Dieser Schritt ist zum erfassen der Z-Koordinaten. Anschliessend aktiviert man wieder alle Farbkanälle, Texturen und zeichnet nun ganz normal seine nicht Transparente Geometry und dann die Transparente. Dieses 2 Schritt verfahren ist um ein vielfaches schneller und wird immer schneller, des so komplexer die Shader und Geometry wird.}}&lt;/div&gt;</summary>
		<author><name>Tak2004</name></author>	</entry>

	</feed>