<?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=Delphic</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=Delphic"/>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php/Spezial:Beitr%C3%A4ge/Delphic"/>
		<updated>2026-05-30T22:19:42Z</updated>
		<subtitle>Benutzerbeiträge</subtitle>
		<generator>MediaWiki 1.27.4</generator>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Software-Synthesizer&amp;diff=25494</id>
		<title>Tutorial Software-Synthesizer</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Software-Synthesizer&amp;diff=25494"/>
				<updated>2012-03-07T06:14:46Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: /* Abschluss */ Source files verlinkt&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Über Schall und Digitalisierung==&lt;br /&gt;
&lt;br /&gt;
Schall ist, wie sicherlich Jeder weis, nichts anderes als Druckschwankungen im uns umgebenden Medium: meist Luft. Aber er lässt sich auch gut durch Wasser oder Metall übertragen, nur vor dem Nichts, dem Vakuum, muss er kapitulieren. Die Druckschwankungen werden vom Trommelfell in unserem Ohr auf ein Knochensystem und von diesem auf das eigentliche Hörorgan übrtragen, welches über feine Haare die Druckschwankungen in Nervensignale übersetzt. Unser Gehirn bereitet die Daten auf, wobei ein subjektiver Eindruck entsteht - wir hören.&lt;br /&gt;
&lt;br /&gt;
Dabei ist unser Ohr im Stande, unterschiedliche Frequenzen als solche einzeln wahrzunehmen. Das ist insofern etwas besonderes, da unser Auge genau das nicht kann. Treffen auf die Netzhaut gleich intensiv und gemeinsam blaues und gelbes Licht, so entsteht ein grüner Farbeindruck. Unser Ohr, würde es nicht auf Schall, sondern auf elektromagnetische Wellen reagieren, würde das Blau und das Gelb als solche einzeln identifizieren können. Manche Menschen haben im übrigen eine andere Sehstäbchenzusammensetzung auf der Netzhaut, als der &amp;quot;normale&amp;quot; Mensch - so empfinden einige das gemischte Computergelb als eine andere Farbe, als das &amp;quot;echte&amp;quot; Gelb.&lt;br /&gt;
&lt;br /&gt;
Nun wollten wir uns aber nicht mit dem Sehen, sondern mit dem Hören beschäftigen. Um Schall zu digitalisieren und damit in Computertaugliche Form zu bringen, benutzt man Mikrofone. Diese besitzen eine Membran, die durch die Druckveränderungen der umgebenden Luft in Schwingung versetzt wird. An einer Stelle der Membran befindet sich eine Spule, in einem Magnetfeld. Wird die Membran durch Schall bewegt, wird die Spule im Magnetfeld bewegt: es entsteht ein Induktionsstrom, der nach Verstärkung ein elektrisches Signal liefert. Dieses Signal könnte man z.B. an einen Lautsprecher weiterleiten und so wieder vertonen.&lt;br /&gt;
&lt;br /&gt;
In unserem Falle wollen wir die Signaldaten jedoch digitalisieren. Dazu wird ein Analog/Digitalwandler verwendet, der die unterschiedlichen Spannungen in Zahlenwerte umwandelt (digitalisiert). Das analoge Signal ist durchgängig, während digitale Daten immer nur kleine Abschnitte des Signals darstellen können, weshalb das Signal gesampelt wird: In einer Sekunde werden gleichverteilt die Signalpegel des analogen Signals in eine Reihe Zahlenwerte umgewandelt. Die Anzahl der Zahlenwerte pro Sekunde wird als Samplingrate bezeichnet. Audio CDs werden mit 44,1 kHz gesampelt, d.h. pro Sekunde wird das analoge Signal des Mikrofons 44100 mal in einen digitalen Wert, ein Sampel, übersetzt.&lt;br /&gt;
&lt;br /&gt;
Wir wollen jedoch den umgekehrten Weg gehen: Wir wollen eine Reihe Sampels selbst erzeugen, um so wohlklingende Töne zu erzeugen, die wir dann als Sounds oder Musik in unseren Projekten einsetzen können. Bis dahin ist es ein längerer Weg. Lest das Tutorial nicht zu schnell, pausiert auch hin und wieder mal, damit ihr das gelernte ausprobieren könnt. Eigene Ideen können häufig auch sehr interessant klingendes hervorbringen. Probiert einfach mal ein wenig rum, aber denkt immer daran, dass, solltet ihr einmal nichts hören können, ein aufdrehen der Lautsprecher ungesund werden könnte. Bleibt mit dem Regler in den Bereichen, die ihr auch sonst nutzt.&lt;br /&gt;
&lt;br /&gt;
Für viele der hier gezeigten Experimente ist hochwertiges Equipment zu empfehlen. Es kann durchaus sein, dass durch billige Boxen euch einige Erkenntnisse verwehrt bleiben, weil die Sache einfach nicht so klingt, wie sie soll. Da klappert mal etwas mit und schon verändert sich der Ton oder es entstehen zusätzliche, andersfrequente Töne, die den klaren Eindruck trüben. Die 5 Euro Boxen, die zum üblichen Komplettsystem gehören sind in keinem Fall geeignet. Auch eine ordentliche Soundkarte wäre zu empfehlen, wobei diese noch nicht einmal neu sein muss - auch eine alte Soundblaster AWE-32 wäre vollkommen ausreichend: nur hochwertig muss sie sein. Ach ja, eine 16-Bit Soundkarte sollte es dann schon sein ;-) Viele Onboard Soundkarten tuns auch, nur leider nicht alle :-(.&lt;br /&gt;
&lt;br /&gt;
{{Warnung|Dieses Tutorial wird euch den Weg in die faszinierende Welt der Software Synthese ebnen. Dies kann jedoch zu gesundheitlichen und materiellen Schäden führen, wenn ihr nicht ein paar grundlegende Dinge beachtet. Euer Gehör ist empfindlich und eure Boxenmembranen sind teuer. Vor Versuchen sollte immer mit einem euch bekannten Programm, die Lautstärkepegel eurer Soundkarte und eures Boxensystems überprüft werden. Zu hohe Lautstärken schaden euch und euren Boxen/Verstärkern oder allem, was sonst dazwischen hängt. Geht die Sache verantwortungsvoll an und ihr werdet viel Spass haben.}}&lt;br /&gt;
&lt;br /&gt;
==Voreinstellungen==&lt;br /&gt;
&lt;br /&gt;
Um direkt Töne aus den Boxen zu zaubern, werden wir uns der FMOD Bibliothek bedienen. Ich habe hier nicht vor, diese Bibliothek bis ins Kleinste zu erklären. Es dürfte genügen, wenn ihr euch die zugehörigen Tutorials anschaut. Zum Abspielen werden wir uns der Callbackfunktionalität der Bibliothek bedienen, d.h. FMOD ruft eine von uns definierte Funktion immer wieder auf. Diese wird dann die nächsten, gesampelten Daten zurückgeben, so dass diese dann auf der Soundkarte ausgegeben werden.&lt;br /&gt;
&lt;br /&gt;
Da FMOD eine ganze Reihe Treiber für unterschiedliche Soundsysteme mitbringt, müssen ein paar Einstellungen getroffen werden. Damit das nicht bei jedem Programmstart geschieht, habe ich ein kleines Programm geschrieben, dass für alle der hier geschriebenen Programme entsprechende Voreinstellungen trifft und abspeichert. Bevor ihr weitermacht, startet einmal '''fmodconf''', stellt das ganze eurem System entsprechend ein und drückt auf Save:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_konfiguration.png]]&lt;br /&gt;
&lt;br /&gt;
==Der erste Ton==&lt;br /&gt;
&lt;br /&gt;
Der einfachste Ton, der von unserem Gehör als eindeutig nur zu einer Frequenz zugeordnet wird, lässt sich mit einer Sinuskurve beschreiben. Das gleiche erzeugen im übrigen auch gute Stimmgabeln, mit denen ihr sicherlich schon alle einmal im Physik- oder Musikunterricht Freundschaft schliessen konntet. Das ganze klingt sehr dünn, aber das ist genau das, was ich euch zeigen möchte.&lt;br /&gt;
&lt;br /&gt;
Zuerst sollten wir jedoch ein paar wesentliche Begriffe einer Welle klären:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_welle.png]]&lt;br /&gt;
&lt;br /&gt;
Dieses Diagramm zeigt den durch ein gutes Mikrofon erzeugten Verlauf der Spannung auf der Zeit an, wenn eine angeschlagene Stimmgabel einen Ton erzeugt.&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable}}&lt;br /&gt;
|'''Amplitude(A)''': Der Betrag des stärksten Ausschlags der Welle. Eine grössere Amplitude erzeugt einen lauteren Ton - und umgekehrt.&lt;br /&gt;
|-&lt;br /&gt;
|'''Periodendauer(T)''': Die Dauer einer vollständigen Schwingung.&lt;br /&gt;
|-&lt;br /&gt;
|'''Frequenz''': Die Zahl der vollständigen Schwingungen in einer Zeiteinheit. Sie wird üblicherweise pro Sekunde betrachtet:&lt;br /&gt;
&lt;br /&gt;
:f = 1 / T Einheit: 1/s=1Hz&lt;br /&gt;
 &lt;br /&gt;
:Die Frequenz eines Tones bestimmt indirekt auch die empfundene Lautstärke, da durch die mechanische Übertragung des Schalls in unserem Ohr bestimmte Frequenzbereiche besser, andere schlechter übertragen werden.&lt;br /&gt;
|-&lt;br /&gt;
|'''Schallgeschwindigkeit''': Die Geschwindigkeit, mit der sich der Schall vorwärtsbewegt: 331 m/s in der Luft.&lt;br /&gt;
|-&lt;br /&gt;
|'''Wellenlänge''': Ist die Länge einer Welle. Sie errechnet sich aus der Schallgeschwindigkeit geteilt durch die Frequenz.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Nun wollen wir also eine Stimmgabel mit dem Computer simulieren. Alles was wir dazu machen müssen, ist eine Sinuskurve an FMOD zu übergeben. Wie bereits erklärt, wird eine Sekunde in eine Reihe Sampels zerlegt. Wir wollen mit einer Scrollbar die Frequenz des Tones einstellen können:&lt;br /&gt;
&lt;br /&gt;
'''ssynth1:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  Pos : Integer;&lt;br /&gt;
  Freq : Integer;&lt;br /&gt;
&lt;br /&gt;
function StreamCallback(Stream: PFSoundStream; Buff: Pointer; Len, Param: Integer): ByteBool; stdcall;&lt;br /&gt;
var&lt;br /&gt;
  Count: Integer; &lt;br /&gt;
  Buffer: PChar;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  Freq := SinGenForm.FreqBar.Position;&lt;br /&gt;
  Buffer := PChar(Buff);&lt;br /&gt;
  Count := 0;&lt;br /&gt;
&lt;br /&gt;
  while Count &amp;lt; (Len div 4) do	{ div 4 = 16bit stereo (4 bytes per sample) }&lt;br /&gt;
  begin&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Sin(2*Pi/SamplingRate*Freq*Pos) * (32767.0/2.0));    { Left channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Sin(2*Pi/SamplingRate*Freq*Pos) * (32767.0/2.0));   { Right channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
&lt;br /&gt;
    Inc(Count);&lt;br /&gt;
    Inc(Pos);&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  Result := True;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Variable Pos dient dem linearen Voranschreiten in unserer Sinuskurve. Durch das Teilen durch die Sampling-Rate erreichen wir, dass jede Sekunde ein Bereich von '''k''' bis '''k+1''' durchlaufen wird, also ein Intervall der Länge '''1: [0..1]+k'''; Wenn durch unsere Zählvariable jede Sekunde ein Bereich der Länge '''1''' durchlaufen wird, wird die Sache für uns viel einfacher. Durch die Multiplikation mit der Frequenz, wird dann nämlich ein Intervall von '''[0..Freq]''' durchlaufen und wir sind nahe dran an dem, was wir haben wollen. Wir müssen nur bedenken, dass der Sinus eine volle Schwingung im Bereich '''[0..2*Pi]''' beschreibt, also multiplizieren wir mit '''2*Pi''' und erzeugen damit eine Sinus-Kurve, die in einer Sekunde '''Freq''' viele Schwingungen macht. Es wird Zeit zum Ausprobieren von synth1. Das Programm ist im im übrigen auf den Kammerton a: 440Hz voreingestellt - nur damit wir gleich mal den Bezug zur Musik herstellen. ;-)&lt;br /&gt;
&lt;br /&gt;
==Die Schwebung==&lt;br /&gt;
&lt;br /&gt;
Wir wollen unserer Stimmgabel eine weitere, gleichlaute Stimmgabel hinzufügen. Diese ist um wenige Frequenzteile verstimmt, so dass die Frequenzen wirklich sehr nahe beieinander liegen. Mit unserer Scrollbar wollen wir diesmal nicht einen großen Frequenzbereich abdecken, sondern nur eine Möglichkeit zum manipulieren des Anteils schaffen. Die Hauptfrequenz legen wir auf 880 Hz fest. Freundlicherweise genügt es, die zweite Stimmgabel durch Addition einer zweiten Sinuskurve hinzuzufügen - wir müssen nur darauf achten, dass wir dann in dem uns begrenzenden Werteintervall bleiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_schwebgen.png]]&lt;br /&gt;
&lt;br /&gt;
Bewegt man den Regler an den äusseren Rand, so nimmt man zwei erkennbar unterschiedliche Töne wahr. Kommt man der Mitte näher, verändert sich das Klangbild stark. Es entsteht eine art Pulsierender Ton. Dieser Effekt kommt häufig in Musikinstrumenten zum Einsatz, so hat jede Taste im Klavier drei zugehörige Saiten, die leicht gegeneinander verstimmt sind, so dass sie einen schwebungstypischen Klang erzeugen.&lt;br /&gt;
&lt;br /&gt;
Wer will, soll einmal einen typischen Audioeditor starten, etwa den kostenlosen Audacity, und betrachte damit einmal den Funktionsgraphen. Einen derartigen Audioeditor solltet ihr für eure Versuche immer parat halten, um bei bedarf mal genau hinzusehen, was ihr da eigentlich erzeugt und ob das dem entspricht, was ihr euch vorgestellt habt.&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|&lt;br /&gt;
Um die Ergebnisse der bislang gemachten Versuche bestaunen zu können, startet den jeweiligen Generator und nehmt einfach ein Stück mit einem Audioeditor auf. Vergesst dabei nicht, die Aufnahmeeinstellungen der Soundkarte entsprechend anzupassen.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
'''ssynth2:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function StreamCallback(Stream: PFSoundStream; Buff: Pointer; Len, Param: Integer): ByteBool; stdcall;&lt;br /&gt;
var&lt;br /&gt;
  Count: Integer;&lt;br /&gt;
  Buffer: PChar;&lt;br /&gt;
  Value : Single;&lt;br /&gt;
  Delta : Single;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  Freq := 880;&lt;br /&gt;
  Buffer := PChar(Buff);&lt;br /&gt;
  Count := 0;&lt;br /&gt;
&lt;br /&gt;
  Delta := 1.0 + (1/10000.0 * SchwebGenForm.PercentBar.Position);&lt;br /&gt;
&lt;br /&gt;
  while Count &amp;lt; (Len div 4) do		&lt;br /&gt;
  begin&lt;br /&gt;
    Value := (Sin(2*Pi/SamplingRate*Freq*Pos) + Sin(2*Pi/SamplingRate*Freq*Pos*Delta));&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Value * (32767.0/2.0));    { Left channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
    PSmallInt(Buffer)^ := Trunc(Value * (32767.0/2.0));   { Right channel }&lt;br /&gt;
    Inc(Buffer, 2);&lt;br /&gt;
&lt;br /&gt;
    Inc(Count);&lt;br /&gt;
    Inc(Pos);&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  Result := True;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Andere Wellenformen==&lt;br /&gt;
&lt;br /&gt;
Statt Sinusförmigen Wellen, bietet es sich an, pulsierende, dreieckige oder jegliche Arten anderer, (periodischer) Funktionen zu verwenden. Diese klingen dann teilweise etwas ungewöhnlich, aber wesentlich voller als der typische Sinuston. Dies liegt daran, dass, würde man die Graphen aus Sinuskurven nachbauen, so würde man die Sinus-Graphen aus ganzen Frequenzbändern benötigen, wodurch das gehörte Frequenzspektrum natürlich stark zunimmt. Der Effekt: Der Ton hört sich wesentlich voller an.&lt;br /&gt;
&lt;br /&gt;
Ein wertvolles Hilfsmittel zur Analyse der dadurch &amp;quot;betonten&amp;quot; Frequenzbereiche ist die Fourier Analyse. FMOD bietet eine leicht zugängliche API, um eine ganze Reihe Frequenzbänder zu untersuchen. Das bedeutet für uns: Ab sofort benötigt jeder unserer Synthesizer ein Display zur Frequenzanalyse. Leider sind diese Analysen nie so recht perfekt, aber um einen Eindruck der belegten Frequenzen zu erhalten, genügt es allemal.&lt;br /&gt;
&lt;br /&gt;
===Sinus===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_sinus.png]]&lt;br /&gt;
&lt;br /&gt;
Der altbekannte Sinus muss natürlich zum Vergleich wieder mit dabei sein:&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function SinWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := Sin(2*Pi*x);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Dreieck===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_dreieck.png]]&lt;br /&gt;
&lt;br /&gt;
Das Dreieck klingt ähnlich wie der Sinus, nur ein wenig voller. Dass beide sehr verwand sein müssen, lässt sich ja bereits am Graphen erkennen.&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function DreieckWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := Abs(frac(x) - 0.5) * 4 - 1;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Sägezahn===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_saegezahn.png]]&lt;br /&gt;
&lt;br /&gt;
Der Sägezahn klingt dann schon wesentlich voller und bissiger, aber macht euch am besten selbst ein Bild - man muss es gehört haben, um zu wissen wie es klingt ;-)&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function SaegezahnWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := (-1 + 2 * frac(x));&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Puls===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_puls.png]]&lt;br /&gt;
&lt;br /&gt;
Der Puls schlägt dann schon sehr aus der Reihe. Durch Veränderunge der Länge der gleichartigen Bereiche, kann man den klang sehr gut und einfach manipulieren.&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function PulseWave(x: Single): Single;&lt;br /&gt;
  function Sgn(x : Single) : Single;&lt;br /&gt;
  begin&lt;br /&gt;
    if x &amp;lt; 0 then&lt;br /&gt;
      Result := -1.0&lt;br /&gt;
    else&lt;br /&gt;
      Result := +1.0;&lt;br /&gt;
  end;&lt;br /&gt;
begin&lt;br /&gt;
  Result := Sgn(frac(x) - IrgendwasZwischen0undEinhalbes);&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Rauschen===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_rauschen.png]]&lt;br /&gt;
&lt;br /&gt;
Nun, dieser Klang ist sehr charakteristisch und ich vermute jeder kennt ihn längst ;-) Wers nicht erkennt, möge ihn sich anhören.&lt;br /&gt;
&lt;br /&gt;
'''ssynth3:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function RauschenWave(x: Single): Single;&lt;br /&gt;
begin&lt;br /&gt;
  Result := (Random -0.5)*2;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Hausgemachte Ober- und Untertöne==&lt;br /&gt;
&lt;br /&gt;
Durch unterschiedliche Wellenformen können wir nun unseren Tönen etwas mehr Fülle verleihen. Es bietet sich jedoch noch eine weitere Möglichkeit an: Obertöne. Statt einer einzelnen Sinuskurve werden hier eine ganze Reihe an Sinuskurven übereinandergelegt. Deren Amplitude ist immer etwas geringer, als die des Haupttones, deren Frequenz jedoch um den Faktor 2^n erhöht:&lt;br /&gt;
&lt;br /&gt;
'''ssyth4:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Ton :=       20 * SinWave(x);&lt;br /&gt;
Ton := Ton + 10 * SinWave(x*2); //1 Oktave  höher als der Grundton&lt;br /&gt;
Ton := Ton + 7  * SinWave(x*4); //2 Oktaven höher als der Grundton&lt;br /&gt;
Ton := Ton + 5  * SinWave(x*8); //3 Oktaven höher als der Grundton&lt;br /&gt;
...&lt;br /&gt;
Ton := 1.0/(20+10+7+5+...)*Ton;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Äquivalent kann man auch Untertöne erzeugen: Statt Oktavschritte nach oben, geht man Oktavschritte mit der Frequenz nach unten (teilen durch 2):&lt;br /&gt;
&lt;br /&gt;
'''ssyth4:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Ton :=       20 * SinWave(x);&lt;br /&gt;
Ton := Ton + 10 * SinWave(1/2*x); //1 Oktave  niedriger als der Grundton&lt;br /&gt;
Ton := Ton + 7  * SinWave(1/4*x); //2 Oktaven niedriger als der Grundton&lt;br /&gt;
Ton := Ton + 5  * SinWave(1/8*x); //3 Oktaven niedriger als der Grundton&lt;br /&gt;
...&lt;br /&gt;
Ton := 1.0/(20+10+7+5+...)*Ton;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Hüllkurven oder Attack, Decay, Sustain, Release Envelopes==&lt;br /&gt;
&lt;br /&gt;
Obwohl sich das alles noch sehr langweilig anhört und an sich nicht wesentlich mehr als ohrenbetäubendes quietschen ist, sind wir schon sehr weit fortgeschritten. Eigentlich fehlt uns gar nicht mehr viel, um wohlgeformte Klänge aus den Boxen zu zaubern. Bevor wir das jedoch tun können, benötigen wir noch ein kleines Hilfsmittel: eine Hüllkurve. Das ist an sich nicht mehr, als ein simulierter Lautstärkenverlauf des Anschlages eines Instrumentes, der sich bei vielen Instrumenten in 4 Teilbereiche aufspaltet:&lt;br /&gt;
&lt;br /&gt;
'''Attack''': Der Attack-Teil beschreibt den Lautstärkenverlauf direkt beim und nach dem Anschlag. Die Saite gibt vorerst keinen Ton von sich. Durch Zupfen oder Anschlagen schnellt der von ihr erzeugte Schalldruck in kurzer Zeit auf sein Maximum. Danach fällt die Lautstärke während der '''Decay-Phase''' auf einen mittleren Wert zurück, verweilt dann in der '''Sustainphase''' eine Zeit lang auf nahezu konstantem Niveau (für uns soll echt konstant genügen), worauf sich die '''Releasephase''' anschliesst, in der der Ton - häufig gedämpft - ausklingt:&lt;br /&gt;
&lt;br /&gt;
Prinzip einer ADSR_Hüllkurve:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_adsr-prinzip.png]]&lt;br /&gt;
&lt;br /&gt;
Zur Lautstärkenregulierung bietet sich die Amplitude unserer Wellenfunktionen an, die wir ganz einfach durch Multiplikation des Sampels mit einem Wert zwischen Null und Eins nach belieben manipulieren können. Daneben müssen wir jedoch beachten, dass unser Gehör auf exponentiell steigende &amp;quot;Werte&amp;quot; geeicht ist, der einfache Kurvenverlauf auf dem obigen Bild würde seltsam klingen. Wandeln wir den Graphen also ein wenig um:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_SoftSynth_adsr-huellfunktion.png]]&lt;br /&gt;
&lt;br /&gt;
Mithilfe der '''exp''' Funktion sollte ein Jeder imstande sein, eine entsprechende Funktion zusammenzustöpseln.&lt;br /&gt;
&lt;br /&gt;
'''Etwas ADSR-Hüllkurvenquellcode:'''&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
function ADSREnvelope(t, a, d, s, r, maxlevel, holdlevel : Single): Single;&lt;br /&gt;
const&lt;br /&gt;
  e = 2.71828182846;&lt;br /&gt;
&lt;br /&gt;
  Start = -4.65;&lt;br /&gt;
  Intervallaenge = 1.0 - Start;&lt;br /&gt;
&lt;br /&gt;
var&lt;br /&gt;
  Pos, x, delta : Single;&lt;br /&gt;
begin&lt;br /&gt;
  if t &amp;lt; 0 then&lt;br /&gt;
  begin&lt;br /&gt;
    Result := 0;&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Attack&lt;br /&gt;
  Pos := a;&lt;br /&gt;
  if t &amp;lt; Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    x := 1.0 - t/a; //x zwischen 0 und 1&lt;br /&gt;
    x := x * Intervallaenge + Start; //x auf das Intervall mappen&lt;br /&gt;
    Result := (1.0 - 1/e*(Power(e, x)))*maxlevel;&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Decay&lt;br /&gt;
  Pos := Pos + d;&lt;br /&gt;
  if t &amp;lt;= Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    delta := maxlevel - holdlevel;&lt;br /&gt;
    if delta &amp;lt;= 0.0 then&lt;br /&gt;
    begin&lt;br /&gt;
      Result := holdlevel;&lt;br /&gt;
      Exit&lt;br /&gt;
    end;&lt;br /&gt;
    x := 1.0 - (t - Pos + d)/d;&lt;br /&gt;
    x := x * Intervallaenge + Start;&lt;br /&gt;
    Result := Maxlevel - (1.0 - 1/e*(Power(e, x)))*delta;&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Sustain&lt;br /&gt;
  Pos := Pos + s;&lt;br /&gt;
  if t &amp;lt;= Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    Result := holdlevel;&lt;br /&gt;
    Exit&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  //Release&lt;br /&gt;
  Pos := Pos + r;&lt;br /&gt;
  if t &amp;lt;= Pos then&lt;br /&gt;
  begin&lt;br /&gt;
    x := 1.0 - (t - Pos + r)/r;&lt;br /&gt;
    x := x * Intervallaenge + Start;&lt;br /&gt;
    Result := holdlevel - holdlevel * (1.0 - 1/e*(Power(e, x)));&lt;br /&gt;
    Exit;&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
  Result := 0.0;&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zusätzlich benötigen wir noch ein paar weitere Hüllkurven, die ich hier jedoch etwas weniger ausführlich beschreiben werde:&lt;br /&gt;
&lt;br /&gt;
Eine Attack-Sustain-Release-Hüllkurve hat, wie ihr Name verrät 3 Phasen. Im Attack Bereich schwillt die Lautstärke auf ihr Maximum, bleibt dann im Sustain Bereich auf diesem Niveau, um schließlich wieder wie gehabt in der Release-Phase abzufallen.&lt;br /&gt;
&lt;br /&gt;
Eine abbrechbare Attack-Decay-Hüllkurve: Der Attack Bereich ist wie gehabt. In der Decay-Phase fällt die Lautstärke bis auf das Null Niveau ab. Dieser Vorgang kann jedoch an jeder beliebigen Stelle abgebrochen werden und in eine gedämpfte Release-Phase übergehen.&lt;br /&gt;
&lt;br /&gt;
==Ein paar synthetische Musikinstrumente==&lt;br /&gt;
&lt;br /&gt;
Nun wird es wirklich einmal Zeit, Töne zu erzeugen, bei denen man sich nicht nach kürzester Zeit gequält die Ohren zuhalten muss. Eine gute Möglichkeit dies zu erreichen, besteht darin echte Musikinstrumente zu simulieren. Die einfachen Mittel, die wir bis jetzt kennengelernt haben, reichen dafür völlig aus. Ich werde hier nicht an jeder Stelle Quellcodes mitliefern, ein Blick in die Dateien des synth5 Projektes sollte jedoch Klarheit schaffen. Beim Nachstellen eines Instrumentes ist v.a. ein wenig mit den Parametern spielen angesagt - den Spass will ich euch nicht nehmen. Viele meiner Instrumente sind sicherlich noch verbesserungsfähig.&lt;br /&gt;
&lt;br /&gt;
===Klavier===&lt;br /&gt;
&lt;br /&gt;
Das Öffnen eines Klavieres kann uns sehr dabei helfen, herauszufinden, wie wir einen Ton synthetisieren müssen. Das typische Klavier besitzt 52 weiße Tasten, die mechanisch die ihnen zugehörigen Saiten mit einem Hammer anschlagen. Zu jeder Taste gehören 3 gespannte, metallische Saiten, die leicht gegeneinander verstimmt sind, so dass eine Schwebung entsteht. Ein Klavier hat einen sehr vollen Ton, so dass wir davon ausgehen können, dass jeder Ton aus einer ganzen Reihe an sinusförmigen Obertönen besteht.&lt;br /&gt;
&lt;br /&gt;
Kommen wir noch zu unserer Hüllkurve: Durch den Anschlag mit dem Hammer steigt die Lautstärke schnell auf ihr Maximum. Bei längerem Tastendruck fällt die Lautstärke langsam ab und wird nach dem loslassen stark gedämpft (Durch Benutzung der unteren Pedale lässt sich hier viel verändern - d.h. hier kann man ruhig ein wenig variieren und herumspielen). Wesentlich an den Hüllkurven ist jedoch, dass die einzelnen Abschnitte der AD-Hüllkurve in ihrer Länge von der Frequenz des Grundtones abhängig sind, weshalb man die Längen nicht in Zeitdauern angibt, sondern durch die Zahl der Schwingungen.&lt;br /&gt;
&lt;br /&gt;
===Klavinett===&lt;br /&gt;
&lt;br /&gt;
Das Klavinett ist dem Klavier sehr sehr ähnlich. Um seine etwas rauheren Töne zu synthetisieren eignen sich Dreiecke oder Sägezähne sehr gut. Mit Dreiecken klingt das Klavinett ziemlich sanft, mit Sägezähnen dagegen schon sehr hart - was die zweite Variante in Verbindung mit tiefen Tönen sehr imposant erscheinen lässt. An den Hüllkurven des Klaviers muss man dagegen nichts ändern.&lt;br /&gt;
&lt;br /&gt;
===Flöte===&lt;br /&gt;
&lt;br /&gt;
Wir wollen uns hier mit einer einfachen Flöte begnügen: Man nehme eine ASR-Hüllkurve und eine Dreiecks-Schwingung. Testweise kann man auch einen Sägezahn ausprobieren, der dann zwar nicht mehr nach einer Flöte klingt, jedoch in den tiefen Tönen sehr schöne Ergebnisse liefert. Die Attack und Release Zeiten sollten sich ähneln. Üblicherweise wählt man sie rel. kurz.&lt;br /&gt;
&lt;br /&gt;
===Glocken===&lt;br /&gt;
&lt;br /&gt;
Glocken geben einen sehr untertonreichen, feinen Klang von sich, entsprechend wählt man als Wellenfunktion den Sinus. Bei vielen Glocken lässt sich auch eine Schwebung heraushören. Als Hüllkurve wählt man wie beim Klavier einen AD-Envelope.&lt;br /&gt;
&lt;br /&gt;
==Oktaven, Halbtöne und was sonst dazugehört==&lt;br /&gt;
&lt;br /&gt;
Wer sich Synth5 schon ein wenig genauer angeschaut hat, wird festgestellt haben, dass sich dort die Frequenzen für die Töne nicht mehr frei wählen lassen, sondern eine Klaviatur zur Eingabe dient. Wollen wir also ein paar Worte zur Berechnung der Frequenzen, die zu den einzelnen Tasten gehören, verlieren:&lt;br /&gt;
&lt;br /&gt;
Ein Oktavschritt verdoppelt die Frequenz, um also vom Kammerton a auf a' zu kommen, muss 440Hz * 2 gerechnet werden (Kammerton a ist auf 440Hz bzw. 436Hz festgelegt).&lt;br /&gt;
&lt;br /&gt;
Eine Oktave soll dann in 12 Teile zerlegt werden, so dass durch Multiplikation mit einem Faktor der nächst höhere Ton entsteht: Da eine Oktave einer Frequenzverdoppelung entspricht, muss für einen Halbton mit dem Faktor 12te Wurzel aus 2 = 2^(1/12) multipliziert werden.&lt;br /&gt;
&lt;br /&gt;
==Abschluss==&lt;br /&gt;
&lt;br /&gt;
Wer etwa 14 MB Festplattenplatz frei hat, möge einmal [http://files.delphigl.com/new/softsynth_src.zip synth_test] starten, um Beethovens Für-Elise mit Glocken gespielt zu hören. Wenn Interesse besteht, werde ich den Synthesizer vielleicht auch noch vor dem Projekt veröffentlichen, zu dem er eigentlich gehört: Ein bischen Feedback wäre sicher angebracht.&lt;br /&gt;
&lt;br /&gt;
Ich hoffe eure Ohren haben diesen Angriff meinerseits gut überstanden. Vielleicht konnte ich dieses Thema ja halbwegs entmystifizieren, wo es doch eigentlich eine ganz andere Thematik als die üblichen DGL Tutorials beschreibt. Ich fand es jedenfalls faszinierend, hier in eine auch für mich bis dato völlig unbekannte Welt vorzustossen, wobei das Meiste einfach aus reinem Ausprobieren entstanden ist. Gut, ich muss zugeben, dass ich hin und wieder in ein altes Buch zum Synthesizer löten gespickt habe und auch mein Dad hi und da mit Rat zur Seite stand - tagelanges rumspielen mit Geräuschen, die durchs gesamte Haus hallen können nunmal nicht ungehört bleiben. Jemand, der selbst in seinen jüngeren Jahren einmal einen Synthesizer gebaut hat, lässt es eben nicht kalt, wenn bekannte Geräusche ertönen - wenn auch nicht analog mit Schaltungen, sondern digital erzeugt ;-).&lt;br /&gt;
&lt;br /&gt;
Euer Delphic&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Multithreading]] |-}} &lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Software-Synthesizer]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=SDL_keysym&amp;diff=24343</id>
		<title>SDL keysym</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=SDL_keysym&amp;diff=24343"/>
				<updated>2009-12-09T11:45:00Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: Unicode -&amp;gt; UNICODE&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= SDL_keysym =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Name ==&lt;br /&gt;
'''SDL_keysym''' - Enthält Informationen über die gedrückte Taste&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Delphi-Spezifikation ==&lt;br /&gt;
 type '''TSDL_keysym''' = record&lt;br /&gt;
        ''scancode'' : UInt8;    &lt;br /&gt;
        ''sym''      : TSDLKey;  &lt;br /&gt;
        ''modifier'' : TSDLMod;  &lt;br /&gt;
        ''unicode''  : UInt16;  &lt;br /&gt;
      end;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Parameter ==&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; rules=&amp;quot;all&amp;quot;&lt;br /&gt;
! ''scancode'' &lt;br /&gt;
| Hardware spezifischer Scancode&lt;br /&gt;
|-&lt;br /&gt;
! ''sym'' &lt;br /&gt;
| SDL virtual keysym (siehe [[SDLKey]])&lt;br /&gt;
|-&lt;br /&gt;
! ''modifier'' &lt;br /&gt;
| aktuelle Tastenmodifizierer (siehe [[SDL_GetModState]])&lt;br /&gt;
|-&lt;br /&gt;
! ''unicode'' &lt;br /&gt;
| in Unicode übersetzter Buchstabe&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Beschreibung == &lt;br /&gt;
Enthält Informationen über die gedrückte Taste.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Hinweis ==&lt;br /&gt;
Der Tastendruck wird nur in Unicode übersetzt wenn [[SDL_EnableUNICODE]] gesetzt wurde.&lt;br /&gt;
&lt;br /&gt;
== Siehe auch ==&lt;br /&gt;
[[SDLKey]], [[SDLMod]]&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:SDL|keysym]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Popping&amp;diff=23951</id>
		<title>Diskussion:Popping</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Popping&amp;diff=23951"/>
				<updated>2009-07-24T09:51:13Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;quot;Langsames Einblenden der Objekte mittels Blending.&amp;quot;&lt;br /&gt;
Das Zitat verlinkt direkt auf den Artikel Blending. Ich denke, daß die hier genannten Dinge zwar sehr ähnlich sind, aber ich glaube der Verweis ist für jemand der das nicht weis eher irreführend. Ich würde den Link entfernen und stattdessen einblenden schreiben - es handelt sich ja auch meistens um LOD. Vielleicht findet noch jemand einen besseren Begriff als ich, aber ich glaube, daß das Blending hier zwar rechnerisch sehr ähnlich ist, aber vom Effekt etwas völlig anderes beschreibt. ([[Benutzer:Delphic|Delphic]] 16:56, 24. Dez 2006 (CET))&lt;br /&gt;
&lt;br /&gt;
Wieso? Mann kann doch dentransparenzwert verändern. In verbindung mit villeicht glFog, könnte das Funktionieren. Oder nicht?&lt;br /&gt;
LOD ist sicherlich die bessere Lösung.&lt;br /&gt;
&lt;br /&gt;
hmmm... ja. das kann sein. wenns ichs heute seh bin ich eh etwas verwirrt. trotzdem scheint mir der Artikel mit der Begrifflichkeit etwas seltsam zu sein, weil später einblenden für LOD kommt und das mitteln &amp;quot;Blending&amp;quot; verlinkt ist (Man kommt bei einem Artikel der sich Blenden nennt heraus). Da ist die Verwirrung dann ganz schnell perfekt, besonders wenn man vorher schon dem Blending einmal gefolgt ist und woanders herauskam.&lt;br /&gt;
Vielleicht sollte man diese Zeile&lt;br /&gt;
&amp;quot;*Langsames Einblenden der neuen Detailstufe über die Alte mittels [[Blenden|Blending]].&amp;quot;&lt;br /&gt;
durch:&lt;br /&gt;
*Langsames [[Blenden|Einblenden]] der neuen Detailstufe über die Alte.&lt;br /&gt;
ersetzen. Dann wird man dadurch wohl nicht so irritiert, daß hier selbige Begriffe für unterschiedliches im Einsatz sind. ([[Benutzer:Delphic|Delphic]])&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Archiv:tut_terrain2_exe&amp;diff=23950</id>
		<title>Archiv:tut terrain2 exe</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Archiv:tut_terrain2_exe&amp;diff=23950"/>
				<updated>2009-07-24T09:49:58Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Archiv|autor=[[Benutzer:Delphic|Delphic]]|beschreibung=Windows 32 Binary zum [[Tutorial Terrain2]].}}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Archiv:tut_terrain2_src_vcl&amp;diff=23949</id>
		<title>Archiv:tut terrain2 src vcl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Archiv:tut_terrain2_src_vcl&amp;diff=23949"/>
				<updated>2009-07-24T09:49:43Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Archiv|autor=[[Benutzer:Delphic|Delphic]]|beschreibung=Delphi-VLC-Quelltext zum [[Tutorial Terrain2]]|todo=Auf dglOpenGL.pas überarbeiten.}}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Archiv:tut_terrain1_src_vcl&amp;diff=23948</id>
		<title>Archiv:tut terrain1 src vcl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Archiv:tut_terrain1_src_vcl&amp;diff=23948"/>
				<updated>2009-07-24T09:49:28Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Archiv|autor=[[Benutzer:Delphic|Delphic]]|beschreibung=Delphi-VLC-Quelltext zum [[Tutorial Terrain1]]|todo=Auf dglOpenGL.pas überarbeiten.}}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Archiv:tut_kameras_src_vcl&amp;diff=23947</id>
		<title>Archiv:tut kameras src vcl</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Archiv:tut_kameras_src_vcl&amp;diff=23947"/>
				<updated>2009-07-24T09:49:13Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Archiv|autor=[[Benutzer:Delphic|Delphic]]|beschreibung=Delphi-VCL-Quelltext zum Programm vom [[Tutorial Kamera1]].|todo=Passende Geometry.pas muss gefunden und eingebunden werden, evtl. haben in der Geometry sich teilweise Bezeichner geändert.}}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Archiv:tut_kameras_exe&amp;diff=23946</id>
		<title>Archiv:tut kameras exe</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Archiv:tut_kameras_exe&amp;diff=23946"/>
				<updated>2009-07-24T09:48:52Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Archiv|autor=[[Benutzer:Delphic|Delphic]]|beschreibung=Programm (win32) zum Tutorial [[Tutorial Kamera1]].}}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Raytracing&amp;diff=23945</id>
		<title>Diskussion:Raytracing</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Raytracing&amp;diff=23945"/>
				<updated>2009-07-24T09:48:31Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Schöne Bilder! Das mit den implizierten Körpern klingt interessant. Falls du da mal Lust (und Bilder) hast, kannst du das gern vertiefen. Auch in einem extra Artikel. Solche Artikel wie der hier, machen richtig was her! Ich schlag den mal als excellent vor. --[[Benutzer:Flash|Flash]] 08:36, 10. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Das ehrt mich. Ja kann mal ein bischen was darüber erzählen, wie man implizite Tracen kann, sobald Zeit dafür ist. Für einen exzellenten enthält diese Artikel aber etwas zu wenig Information, obwohl er natürlich sehr schön anzusehen ist :-) --[[Benutzer:Delphic|Delphic]] 17:17, 10. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
OK, ich denke wir lassen ihn in der Wartestellung bis er Inhaltlich einen besseren Überblick über das Thema gibt.--[[Benutzer:Flash|Flash]] 17:56, 10. Dez. 2008 (UTC)&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Matrix&amp;diff=23944</id>
		<title>Diskussion:Matrix</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Matrix&amp;diff=23944"/>
				<updated>2009-07-24T09:48:17Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Bei der mxn-nxr-Matrix-Matrix Multiplikation ist ein Fehler: Bei dem Element unten links muss es nicht heißen &amp;quot;3*7+0+1*4&amp;quot; sondern &amp;quot;3*5+0+4*7&amp;quot;. Deshalb ist dann auch das Ergebnis 43 und nicht 25.&lt;br /&gt;
Am besten wäre es sowieso, die gescannten Sachen durch schöne LaTeX-Formeln zu ersetzen. --[[Benutzer:Wilson|Wilson]] 15:26, 5. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Latex ist leider nicht automatisch möglich und wir müssten dafür eigene Bilder erstellen :(&lt;br /&gt;
--[[Benutzer:I0n0s|I0n0s]] 22:48, 5. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Fehler bestätigt. Da ist wohl unserem Mathematiker mal ein Ausrutscher passiert. ;) --[[Benutzer:Flash|Flash]] 19:51, 6. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
# Austrutscher? Wollte nur testen, ob auch alle aufpassen :-). Ich werde mich drum kümmern, evtl. wird sogar geTeXt... --[[Benutzer:Delphic|Delphic]] 22:44, 6. Dez. 2008 (UTC) &lt;br /&gt;
# Erledigt. Schaut doch mal ob ich mich irgendwo vertan habe. --[[Benutzer:Delphic|Delphic]] 10:41, 7. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Sieht gut aus - sogar besser. Fehler konnte ich jetzt nicht sehen, aber als Beweis der Richtigkeit kann man das definitv nicht gelten lassen. ;) --[[Benutzer:Flash|Flash]] 14:49, 7. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Scheint in Ordnung zu sein.&lt;br /&gt;
Um die &amp;quot;Siehe Auch&amp;quot;-Seiten kümmern sich dann doch hoffentlich Erst-Semester oder? ;-)&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:I0n0s|I0n0s]] 21:57, 7. Dez. 2008 (UTC)&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Farbraum&amp;diff=23943</id>
		<title>Diskussion:Farbraum</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Farbraum&amp;diff=23943"/>
				<updated>2009-07-24T09:47:48Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Die Bilder im Artikel werden nicht angezeigt&lt;br /&gt;
Bei LAB könnte die Erklärung noch etwas umfangreicher ausfallen. Speziell auch der Zusammenhang wie man von einer bestimmten Wellenlänge auf die Farbe, oder bei einem schwarzen Körper auf seine seine Farbe (nein, nicht den wörtlichen, sondern den physikalischen mein ich ;-)) wäre hilfreich.&lt;br /&gt;
&lt;br /&gt;
Vergleiche auch folgenden Thread aus'm DF: http://www.delphi-forum.de/viewtopic.php?t=80668&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:BenBE|BenBE]] 02:50, 27. Feb. 2008 (CET)&lt;br /&gt;
&lt;br /&gt;
Oh Fehlen die Bilder schon wieder... Oder immernoch. Das Problem hatten wir jedenfalls schon einmal. Werde Flow mal wieder deswegen anhauen.&lt;br /&gt;
&lt;br /&gt;
Das mit LAB stell ich gerne jemand Anderes zur Verfügung - ich hab nur wenig Erfahrung in Sachen Farbechtheit und selbst auch nicht die nötige Hardware für sowas (Wenns mir jemand zur Verfügung stellt wärs evtl was anderes ;-) ). Da bin ich nicht sehr kompetent und bei meinen bisherigen Recherchen zu diesem Thema hab ich soweit nur festgestellt, daß gute Informationen wohl schiwerig zu haben sind. Einiges dazu gibts aber hier:&lt;br /&gt;
http://www.color.org/&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Delphic|Delphic]] 17:56, 27. Feb. 2008 (CET)&lt;br /&gt;
&lt;br /&gt;
Ich hab mich mal um die Bilder gekümmert; War ziemlich ekelig alle Dateien im Wiki-Durcheinander wiederzufinden, aber jetzt sollte alles umbenannt sein und wieder funktionieren. Jemanden für LAB hab ich aber immer noch nicht aufgetrieben, nur festgestellt, daß fast niemand kalibrierte Monitore besitzt :-) --[[Benutzer:Delphic|Delphic]] 19:43, 9. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Wo hast du das eigentlich her mit den Personen die 4 Grundfarben sehen können? Es gibt doch nur 3 Rezeptoren. --[[Benutzer:Flash|Flash]] 17:00, 15. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Genetische Mutation... Hab das ursprünglich ausm Bio-Unterricht, hab aber auch etwas darüber wiedergefunden: http://en.wikipedia.org/wiki/Tetrachromacy#Possibility_of_human_tetrachromats --[[Benutzer:Delphic|Delphic]] 10:41, 16. Dez. 2008 (UTC)&lt;br /&gt;
&lt;br /&gt;
Interessant. Ich hab das im Artikel mal vermerkt. Quellen können durchaus nicht schaden. --[[Benutzer:Flash|Flash]] 13:09, 17. Dez. 2008 (UTC)&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei_Diskussion:Tutorial_RaytracingI_strahlgleichung.png&amp;diff=23942</id>
		<title>Datei Diskussion:Tutorial RaytracingI strahlgleichung.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei_Diskussion:Tutorial_RaytracingI_strahlgleichung.png&amp;diff=23942"/>
				<updated>2009-07-24T09:46:57Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Mathematisch korrekt ist die runde Klammer anstatt dem umgedrehten Eckigen.&lt;br /&gt;
Daher bitte die alte Version wiederherstellen.&lt;br /&gt;
&lt;br /&gt;
Danke --[[Benutzer:I0n0s|I0n0s]] 22:20, 25. Dez 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
Edit: Bäh, böser Cache. Habe die alte Version aus dem obigen Grund wiederhergestellt.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:I0n0s|I0n0s]] 22:24, 25. Dez 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
Was passiert mit diesem Bild? Also ich kenne den Ausschluss einer Elementes sowohl mit Runden, als auch mit umgedrehten Eckigen klammern. Das macht eigentlich jeder so wie ers mag... Ich hab mich an die Runden gewöhnt, drum ists ne runde geworden, aber so schrecklich wichtig ist das eigentlich nicht. Und gelgentlich ist es auch ganz nett, unendlich mit ins Intervall zu nehmen und die Reelen Zahlen abzuschließen. Allzuviel sind macht das hier allerdings nicht. ([[Benutzer:Delphic|Delphic]])&lt;br /&gt;
&lt;br /&gt;
Ich bin dafür, dass es mit den runden Klammer bleibt, daher auch das obige Chaos als ich versucht habe es wiederherzustellen und am Browsercache gescheitert bin :'(&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:I0n0s|I0n0s]] 14:59, 26. Dez 2006 (CET)&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Popping&amp;diff=23941</id>
		<title>Diskussion:Popping</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Popping&amp;diff=23941"/>
				<updated>2009-07-24T09:46:36Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;quot;Langsames Einblenden der Objekte mittels Blending.&amp;quot;&lt;br /&gt;
Das Zitat verlinkt direkt auf den Artikel Blending. Ich denke, daß die hier genannten Dinge zwar sehr ähnlich sind, aber ich glaube der Verweis ist für jemand der das nicht weis eher irreführend. Ich würde den Link entfernen und stattdessen einblenden schreiben - es handelt sich ja auch meistens um LOD. Vielleicht findet noch jemand einen besseren Begriff als ich, aber ich glaube, daß das Blending hier zwar rechnerisch sehr ähnlich ist, aber vom Effekt etwas völlig anderes beschreibt. ([[Benutzer:Delphic|Delphic]] 16:56, 24. Dez 2006 (CET))&lt;br /&gt;
&lt;br /&gt;
Wieso? Mann kann doch dentransparenzwert verändern. In verbindung mit villeicht glFog, könnte das Funktionieren. Oder nicht?&lt;br /&gt;
LOD ist sicherlich die bessere Lösung.&lt;br /&gt;
&lt;br /&gt;
hmmm... ja. das kann sein. wenns ichs heute seh bin ich eh etwas verwirrt. trotzdem scheint mir der Artikel mit der Begrifflichkeit etwas seltsam zu sein, weil später einblenden für LOD kommt und das mitteln &amp;quot;Blending&amp;quot; verlinkt ist (Man kommt bei einem Artikel der sich Blenden nennt heraus). Da ist die Verwirrung dann ganz schnell perfekt, besonders wenn man vorher schon dem Blending einmal gefolgt ist und woanders herauskam.&lt;br /&gt;
Vielleicht sollte man diese Zeile&lt;br /&gt;
&amp;quot;*Langsames Einblenden der neuen Detailstufe über die Alte mittels [[Blenden|Blending]].&amp;quot;&lt;br /&gt;
durch:&lt;br /&gt;
*Langsames [[Blenden|Einblenden]] der neuen Detailstufe über die Alte.&lt;br /&gt;
ersetzen. Dann wird man dadurch wohl nicht so irritiert, daß hier selbige Begriffe für unterschiedliches im Einsatz sind. ([[Benutzer:Nico Michaelis|Nico Michaelis]])&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Techniken_zur_Matrixinversion&amp;diff=23940</id>
		<title>Diskussion:Techniken zur Matrixinversion</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Techniken_zur_Matrixinversion&amp;diff=23940"/>
				<updated>2009-07-24T09:46:01Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Es wäre vieleicht noch toll, bei &amp;quot;transponieren&amp;quot; ein Beispiel zu machen.&lt;br /&gt;
&amp;lt;pre&amp;gt;a1 a5 a9  a13     a1  a2  a3  a4&lt;br /&gt;
a2 a6 a10 a14 --\ a5  a6  a7  a8&lt;br /&gt;
a3 a7 a11 a15 --/ a9  a10 a11 a12&lt;br /&gt;
a4 a8 a12 a16     a13 a14 a15 a16&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ich dachte eigentlich, daß Transposition sich eigentlich ganz gut so erklärt. In einer Tabelle zeilen mit Spalten zu vertauschen dürfte doch eigentlich klar sein? Allerdings ist imho Transposition selbst so wichtig, daß es ihr und ihren Eigenschaften in Bedarfsfall auch gerecht wird, ihr einen eigenen Artikel zu spendieren: da kann man dann gerne auch Beispiele bringen und es auch an Vektoren oder nichtquadratischen Matrizen zeigen, da sieht man dann auch etwas mehr - ob man allerdings in der 3D Grafik noch wesentlich mehr Anwendungen findet, als das invertieren von unitären Matrizen, da bin ich mir nicht so sicher - mir fällt zu dem thema jedenfalls nichts wesentliches ein.&lt;br /&gt;
&lt;br /&gt;
== Matrixinversion direkt mit OpenGL ==&lt;br /&gt;
&lt;br /&gt;
Mir fällt da noch eine ganz einfache Methode für die Berechnung der Matrixinverse ein ;)&lt;br /&gt;
&lt;br /&gt;
Hat man eine Modelview-Matrix setzt sich diese ja bekanntlich als Produkt verschiedener Matrizen mittels glRotate, glTranslate oder glScalef zusammen, also z.B. MV = ( A * B * C ).&lt;br /&gt;
Für die Inverse gilt dann MV ^ -1 = ( A * B * C ) ^ -1.&lt;br /&gt;
&lt;br /&gt;
Bei der Matrizenmultiplikation gilt nun, dass sich bei der Auflösung der Klammer auf der rechten Seite die Matrizen vertauschen, also gilt dann :&lt;br /&gt;
MV ^ -1 = C ^ -1 * B ^ -1 * A ^ -1.&lt;br /&gt;
&lt;br /&gt;
Man braucht also nur die Matrizenoperationen in umgekehrter Reihenfolge aufschreiben und die 'Inverse' nehmen.&lt;br /&gt;
Das bedeutet z.B. dass man bei glTranslate( x, y, z ) als Inverse glTranslate( -x, -y, -z ) und bei glRotate( w, 1, 0, 0 ) als Inverse glRotate( -w, 1, 0, 0 ) nimmt, usw.&lt;br /&gt;
&lt;br /&gt;
Zum Schluss muß man sich die von OpenGL berechnete Matrix nur noch holen...&lt;br /&gt;
&lt;br /&gt;
Hier mal ein Code-Beispiel :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//Speicher für Matrix&lt;br /&gt;
float M_inv[16];&lt;br /&gt;
&lt;br /&gt;
glMatrixMode( GL_MODELVIEW );&lt;br /&gt;
//Einheitsmatrix laden&lt;br /&gt;
glLoadIdentity();&lt;br /&gt;
    &lt;br /&gt;
//glRotate, glTranslate-Befehle in umgekehrter Reihenfolge und 'invertiert'&lt;br /&gt;
&lt;br /&gt;
//Matrix holen&lt;br /&gt;
glGetFloatv( GL_TRANSPOSE_MODELVIEW_MATRIX, M_inv );&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Dj3hut1|Dj3hut1]] 08:48, 10. Jan. 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
Ja das ginge schon, aber meistens hat man ja eher das Problem, dass man laengst nicht mehr rekonstruieren kann, wie die matrix entstand, weil recht viele iterationen von rotationen und translationen dahinter stehen und man ja gerade die matrix gespeichert hat, um sich das alles zu merken, die entstehungsdetails aber überflüssig sind. und transponieren ist schon ein sehr billiger vorgang, muss ja nicht einmal addieren oder multiplizieren dazu. &lt;br /&gt;
[[Benutzer:Delphic|Delphic]] 09:52, 10. Jan. 2009 (UTC)&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Diskussion:Tutorial_Texturgenerator&amp;diff=23939</id>
		<title>Diskussion:Tutorial Texturgenerator</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Diskussion:Tutorial_Texturgenerator&amp;diff=23939"/>
				<updated>2009-07-24T09:45:30Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Ich denke, wir koennen das gute Stueck mal entsorgen? Da hat sich schon lang nix mehr getan und antworten tut Red ja scheints auch nicht? Muesste aber jemand mit den entsprechenden Rechten tun.&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Delphic|Delphic]] 15:12, 13. Dez 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
Tut scheint tod zu sein. Was damit machen?&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:I0n0s|I0n0s]] 14:40, 30. Apr 2006 (CEST)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Ich schreib Red nochmal an.&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:Flash|Flash]] 18:05, 30. Apr 2006 (CEST)&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Kategorie_Diskussion:Exzellent&amp;diff=23938</id>
		<title>Kategorie Diskussion:Exzellent</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Kategorie_Diskussion:Exzellent&amp;diff=23938"/>
				<updated>2009-07-24T09:44:55Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Voraussetzungen für Exzellente Artikel=&lt;br /&gt;
Hier könnt ihr Artikel vorschlagen welche ihr als &amp;quot;exzellenten Artikel&amp;quot; einstufen würdet.&lt;br /&gt;
&lt;br /&gt;
Folgende Punkte '''müssen''' erfüllt sein:&lt;br /&gt;
* Kein Sackgassenartikel - Artikel muss auf andere Artikel direkt (nicht über Code) verlinken&lt;br /&gt;
* Kein Plain Text - Artikel muss eine einheitliche Formatierung aufweisen&lt;br /&gt;
* Bilder - Artikel muss mindestens ein Bild/Grafik besitzen&lt;br /&gt;
* Umfassend - Der Artikel muss das Thema umfassend behandeln.&lt;br /&gt;
* Kein Tutorial - Der Artikel darf nicht der [[:Kategorie:Tutorial|Kategorie Tutorial]] angehören.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Damit ein Artikel als '''exzellent''' eingestuft wird müssen:&lt;br /&gt;
* 3 Wiki-User der Wahl zustimmen darunter mindestens ein Moderator,&lt;br /&gt;
* keine Gegenstimmen bestehen,&lt;br /&gt;
* die Voraussetzungen von oben gelten.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=Kandidatenliste=&lt;br /&gt;
Um einen Artikel zur Kandidatenliste hinzuzufügen bitte den Nachfolgenden Code vor dem Ende (&amp;quot;&amp;lt;nowiki&amp;gt;|}&amp;lt;/nowiki&amp;gt;&amp;quot;) der Tabelle einfügen:&lt;br /&gt;
&lt;br /&gt;
 |&amp;lt;nowiki&amp;gt;[[Artikelname]]&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 |&lt;br /&gt;
 |&lt;br /&gt;
 |&lt;br /&gt;
 |-&lt;br /&gt;
&lt;br /&gt;
Um eine Stimme abzugeben, kopiert ihr bitte den Wiki-Code &amp;quot;&amp;lt;nowiki&amp;gt;--~~~~&amp;lt;/nowiki&amp;gt;&amp;quot; in die entsprechende Spalte. Das Wiki generiert daraus eure Unterschrift (Signatur).&lt;br /&gt;
&lt;br /&gt;
Falls ihr eine Gegenstimme abgebt, muss eine Begründung dazu gegeben werden.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Vorgeschlagener Artikel&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Beführworter&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Gegner&lt;br /&gt;
!width=&amp;quot;45%&amp;quot;|Begründung für Gegenstimme / Diskussion&lt;br /&gt;
|-&lt;br /&gt;
| [[glTexParameter]]&lt;br /&gt;
| &lt;br /&gt;
| --[[Benutzer:Flash|Flash]] 09:56, 11. Jan 2007 (CET)&lt;br /&gt;
|Wenn jemand noch die restlichen Wrapmodes einbaut sicher ein guter kandidat  (GL_CLAMP_TO_EDGE,  GL_CLAMP_TO_BORDER,GL_MIRRORED_REPEAT laut glitmap.pas) (Winner)&lt;br /&gt;
&lt;br /&gt;
Stimme Winner zu. Ohne die ergänzungen kommt der Artikel nicht in Frage.&lt;br /&gt;
|-&lt;br /&gt;
|[[gluCylinder]]&lt;br /&gt;
| --[[Benutzer:Flash|Flash]] 09:09, 10. Apr. 2008 (UTC)&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
|[[Raytracing]]&lt;br /&gt;
| &lt;br /&gt;
| --[[Benutzer:I0n0s|I0n0s]] 13:25, 10. Dez. 2008 (UTC)&lt;br /&gt;
--[[Benutzer:Delphic|Delphic]] 17:14, 10. Dez. 2008 (UTC)&lt;br /&gt;
|&lt;br /&gt;
# Es existieren 2 Tutorials zu dem Thema.&lt;br /&gt;
# Ist nur als Oberflächliche Information konzipiert und enthält keine Information, wie die Techniken tatsächlich zu verwenden sind.&lt;br /&gt;
&lt;br /&gt;
Ok. Bis der Artikel das Thema etwas besser &amp;quot;ausleuchtet&amp;quot; ;) bleibt das Veto stehen. Die Tutorials sprechen nicht dagegen. --[[Benutzer:Flash|Flash]] 17:58, 10. Dez. 2008 (UTC)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Auswahlkriterien ==&lt;br /&gt;
&lt;br /&gt;
Ich finde die Asuwahlkriterien etwas strange. Schließlich sind Tutorials auch Artikel und in den meisten Fällen noch dazu ziemlich gute. Warum sollten diese also ausgeschlossen werden? Vermitteln ja schließlich meist recht anschaulich viel Information. Also exakt das, was nen guten Artikel ausmacht.&lt;br /&gt;
--[[Benutzer:Frase|Frase]] 18:48, 18. Mär 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Tutorials sind einzelarbeiten die von einer Person gemacht wurden und die eigentlich auch nur von dieser zu Verantworten/Verbessern sind. Die Auszeichnung soll gerade dafür sorgen die &amp;quot;graue Maus&amp;quot; Artikel aufzuwerten. Das unsere Tutorials alle Exzellent sind steht außer Frage. Die Auszeichnung heißt aber nicht um sonst &amp;quot;Exzellente Artikel&amp;quot; und nicht &amp;quot;Exzellente Tutorials&amp;quot;. Außerdem soll die Auzeichnung erreichen, dass die Nutzer einfach mal ins Wiki reinlesen. Tutorials sind in sich geschlossen und verlinken kaum auf andere Artikel. Sie behandeln ein Thema, und das ist gut so.&lt;br /&gt;
--[[Benutzer:Flash|Flash]] 01:11, 19. Mär 2006 (CET)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Und es kann die Leute animieren die Artikel den Kritierie anzupassen bzw. eigene Artikel einzustellen.&lt;br /&gt;
So hat es zumindest bei mir funktioniert. Ich habe jetzt sogar Bilder! :lol:&lt;br /&gt;
&lt;br /&gt;
--[[Benutzer:I0n0s|I0n0s]] 04:35, 19. Mär 2006 (CET)&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Datei:Frustum.jpg&amp;diff=23937</id>
		<title>Datei:Frustum.jpg</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Datei:Frustum.jpg&amp;diff=23937"/>
				<updated>2009-07-24T09:43:40Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Frustum-Handzeichnung&lt;br /&gt;
&lt;br /&gt;
Zeichner: Delphic&amp;lt;br&amp;gt;&lt;br /&gt;
Datum: 10. September 04&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Raytracing_-_Grundlagen_II&amp;diff=23934</id>
		<title>Tutorial Raytracing - Grundlagen II</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Raytracing_-_Grundlagen_II&amp;diff=23934"/>
				<updated>2009-07-23T15:12:22Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Raytracing Grundlagen II =&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_teaser.jpg|center]]&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Und weiter geht es mit unsem Raytracing Tutorial. Wir wollen unseren Raytracer nun langsam aber sicher soweit bekommen, daß sich damit etwas ansehnlichere Bilder erzeugen lassen. Wer das [[Tutorial_Raytracing_-_Grundlagen_I|vorangehende Tutorial]] nicht gelesen hat, sollte dies am besten gleich tun - ich will ja nicht alles neu erklären. Womit werden wir uns denn heute beschäftigen? Zuerst werden wir ein erweiterbares Objektmodell für alle Objekte planen und überlegen. Dann wollen wir uns ein wenig mit Phong-Lighting beschäftigen und einige Gedanken in Richtung Transformationen verschwenden. Mit diesem Plan sind wir, so denke ich, erstmal gut beschäftigt.&lt;br /&gt;
&lt;br /&gt;
== Ein schönes Basisobjekt ==&lt;br /&gt;
Wir wollen die Objekte in unsem Raytracer möglichst gleich behandeln können, so daß der eigentliche Raytracing Algorithmus ohne jegliches wissen über die Struktur der Objekte arbeiten kann. Sprich: Wir definieren ein Basisobjekt, von dem anschließend alle weiteren Objekte abgeleitet werden. Was also soll dieses Objekt an Methoden und Eigenschaften zur Verfügung stellen? Jedes Objekt hat sicherlich eine Position, sowie gewissen Materialeigenschaften, die dem Objekt zugewiesen werden. Auch soll das Objekt sauber mit Transformationen umgehen können. Und was natürlich ganz wichtig ist: Wir brauchen eine Methode die prüft, ob sich das Objekt mit dem Strahl schneidet. Über einige dieser Dinge haben wir uns noch keine Gedanken gemacht, entsprechend sollen hierfür nur leere Dummyklassen und Methoden zum Einsatz kommen, die wir erst später realisieren. Damit es nicht vergessen wird: Es ist auch sinnvoll Vater-Kindbeziehungen zu haben um später zusammengesetzte Objekte definieren zu können. Das klingt alles etwas wild, artet in einer großen Menge Code aus, ist aber eigentlich gar nicht so schlimm, wei es sich anhört:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;    /// General Raytracing object in a tracer. All traceable objects must be derivates&lt;br /&gt;
    public abstract class ObjectBase&lt;br /&gt;
    {&lt;br /&gt;
        #region Positioning Variables&lt;br /&gt;
        &lt;br /&gt;
        private Vertex3 pos = new Vertex3();&lt;br /&gt;
        /// The Position of the Object in parental Space&lt;br /&gt;
        public Vertex3 Position&lt;br /&gt;
        {&lt;br /&gt;
            get { return pos; }&lt;br /&gt;
            set { pos = value; /*InvalidateBoundings(true);*/ }&lt;br /&gt;
            // Anm.: InvalidateBoundings brauchen wir jetzt noch &lt;br /&gt;
            // nicht. Wenn man allerdings mit Bounding-Volumes&lt;br /&gt;
            // zu arbeiten beginnt, wird man entsprechende&lt;br /&gt;
            // Funktionalität benötigen. Vorerst gilt: Forget it.&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        private ILinearTransformation ptransformation;&lt;br /&gt;
        /// The Transformation applied to the object&lt;br /&gt;
        public ILinearTransformation Transformation&lt;br /&gt;
        {&lt;br /&gt;
            get&lt;br /&gt;
            {&lt;br /&gt;
                return ptransformation;&lt;br /&gt;
            }&lt;br /&gt;
            set&lt;br /&gt;
            {&lt;br /&gt;
                ptransformation = value;&lt;br /&gt;
                //InvalidateBoundigs(true);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&lt;br /&gt;
        #region Material&lt;br /&gt;
        private Material objMaterial = new StandardMaterial();&lt;br /&gt;
        /// Material assigned to object&lt;br /&gt;
        public Material ObjectMaterial&lt;br /&gt;
        {&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&lt;br /&gt;
        #region Parenting&lt;br /&gt;
        // The parental object&lt;br /&gt;
        private ObjectBase fParent;&lt;br /&gt;
&lt;br /&gt;
        /// The Parent of the object&lt;br /&gt;
        public ObjectBase Parent&lt;br /&gt;
        {&lt;br /&gt;
            ...&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&lt;br /&gt;
        #region Trans Space Functions&lt;br /&gt;
        public virtual Vertex3 TransSpaceWorldToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Ray TransSpaceWorldToObject(Ray r) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpacePointWorldToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpacePointParentToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Ray TransSpaceParentToObject(Ray r) &lt;br /&gt;
        {&lt;br /&gt;
            Ray ray = r;&lt;br /&gt;
            ray.o -= pos;&lt;br /&gt;
            return ray;&lt;br /&gt;
        }&lt;br /&gt;
        public virtual Vertex3 TransSpaceParentToObject(Vertex3 v) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpaceObjectToWorld(Vertex3 v) {...}&lt;br /&gt;
        public virtual Vertex3 TransSpacePointObjectToWorld(Vertex3 v) {...}&lt;br /&gt;
        #endregion&lt;br /&gt;
        &lt;br /&gt;
        #region Intersection Tests&lt;br /&gt;
        /// Calculates the first visible intersection. Returns values smaller&lt;br /&gt;
        /// equal zero if there is no intersection. &lt;br /&gt;
        /// param name=&amp;quot;rs&amp;quot;: Global rendersettings&lt;br /&gt;
        /// param name=&amp;quot;ray&amp;quot;: the ray to test for intersection&lt;br /&gt;
        /// param name=&amp;quot;raymindist&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;raymaxdist&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;calcNormals&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;calcTextureCoordinates&amp;quot;:&lt;br /&gt;
        /// param name=&amp;quot;info&amp;quot;:&lt;br /&gt;
        public abstract int Intersect(RenderSettings rs, Ray ray, double raymindist, double raymaxdist,&lt;br /&gt;
            bool calcNormals, bool calcTextureCoordinates, ref IntersectionInfo info);&lt;br /&gt;
        #endregion&lt;br /&gt;
    }        &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Das schaut jetzt tatsächlich etwas wild aus, aber keine Angst. Wir werden das alles der Reihe nach mit Leben füllen. Die Trans-Space-Funktionen werden wir anschließend mit Leben füllen - nur TransSpaceParentToObject kann gleich bestückt werden (wir werden das aber später erweitern müssen). Sie soll Strahlen aus dem Eltern-Raum in den lokalen Raum überführen - für die meisten Objekte bedeutet dies: Die globalen Koordinaten werden in lokale übersetzt, so daß sich unser Objekt genau im Zentrum des Geschehens, d.h. bei (0,0,0), befindet und wir uns dann nie wieder über die Position des Objektes Gedanken machen müssen.&lt;br /&gt;
&lt;br /&gt;
Einen Blick sind auch die Parameter von Intersect wert. rs beschreibt globale Einstellungen des Renderers. Darin könnte man z.B. festlegen, ob Schatten berechnet werden sollen oder nicht. Ihr könnt hier im wesentlichen spazieren führen was ihr wollt, aber diese Option zu haben ist jedenfalls nicht verkehrt. ray dürfte klar sein.&lt;br /&gt;
Dies wird ein Strahl sein, der jeweils in elterlichen Koordinaten gegeben ist, also mithilfe von TransSpaceParentToObject in lokale Koordinaten umgerechnet werden kann. raymindist und raymaxdist beschreiben jeweils Bereich des Strahles, in dem wir nach Überschneidungen suchen sollen - haben wir es mit einem numerisch zu berechnenden Objekt zu tun, kann diese Information bereits sehr viel Geschwindigkeit ausmachen. Beim Schnitt mit Kugeln ist die Sache dagegen weniger wichtig. Essenziell ist, daß beim Aufruf von Intersect sichergestellt sein muss, daß nur dann positive Rückmeldung gemacht wird, wenn die Überschneidung an einer Stelle des Strahles zu finden ist, die größer gleich raymindist ist: Darauf sollte man sich verlassen können. calcNormals und calcTextureCoordinates beschreibt, ob beim Überschneidungstest Informationen über Flächennormalen bzw. Texturkoordinaten erzeugt werden sollen: Bei manchen Objekten ist auch diese Information nur kostspielig zu bekommen und wir wollen es deshalb optional halten. Es bleibt noch der Call by Reference Parameter info. Darin sollen genauere Informationen bezüglich des Schnittes gespeichert werden - etwa lokale Farben, Material, Texturkoordinaten, Schnittposition, etc. (Die Schnittposition könnte man auch direkt zurückgeben, also den Rückgabewert durch einen Float-Typ wie double ersetzen. Seis drum)&lt;br /&gt;
&lt;br /&gt;
Noch schnell ein kleiner Blick in eine mögliche Definition der IntersectionInfo. Darin befindet sich nichts anderes, als wie das, was ich gerade beschrieben habe. Also keine Überraschungen ;-)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;    public struct IntersectionInfo&lt;br /&gt;
    {&lt;br /&gt;
        /// Position on ray where the cut occured&lt;br /&gt;
        public double rayPosition;&lt;br /&gt;
        /// Normal of surface at cut position&lt;br /&gt;
        public Vertex3 normal;&lt;br /&gt;
        /// Texture coordinates&lt;br /&gt;
        public Vertex3 texture;&lt;br /&gt;
        /// Material of surface at intersection position&lt;br /&gt;
        public Material material;&lt;br /&gt;
        /// The local color of the intersection. This must be optional&lt;br /&gt;
        /// for all materials!!! Some Objects may always return black here.&lt;br /&gt;
        public Color localColor;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Transformationen ==&lt;br /&gt;
Wir wollen uns nun um Transformationen kümmern. Was also sind Transformationen? Wer mit OpenGl vertraut ist, kennt sie sie ganz gut: Es handelt sich um genau das, was man mit den Funktionen [[glTranslate]], [[glRotate]], [[glScale]], usw. bewirken kann. Verschiebungen haben wir bereits durch die Position des Objektes abgehakt, wir können uns hier also auf Dinge wie Scheerungen, Rotationen usw. beschränken. Wer Nachholbedarf in diesen Themen hat, der sollte sich jetzt hier darum kümmern, dieses Defizit etwas zu mildern. Da DelphiGl aber schon eine Weile existiert, finden sich fast alle nötigen Informationen in Tutorias oder Wiki-Artikeln: [[Matrix]],&lt;br /&gt;
[[Tutorial_Nachsitzen|Nachsitzen]], [[Tutorial_Matrix2|Matrix 2]], [[Quaternion]]. Auch die Wikipedia ist hier in der [http://de.wikipedia.org/wiki/Kategorie:Lineare_Algebra Kategorie Lineare Algebra] gut ausgestattet, um weitere Informationen einzuholen.&lt;br /&gt;
Wer hoch in den Code des Basis-Objektes schaut, dem wird auffallen, daß Transformationen durch das Interface ILinearTransformation definiert sind:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
    /// Defines a linear Trafo&lt;br /&gt;
    public interface ILinearTransformation&lt;br /&gt;
    {&lt;br /&gt;
        /// Applys the Trafo to v&lt;br /&gt;
        Vertex3 Apply(Vertex3 v);&lt;br /&gt;
        /// Applys the inverse Trafo to v&lt;br /&gt;
        Vertex3 ApplyInverse(Vertex3 v);&lt;br /&gt;
&lt;br /&gt;
        /// Conversion of the Trafo to Matrix3x3&lt;br /&gt;
        Matrix3x3 ConvertTo3x3();&lt;br /&gt;
        /// Conversion of the Inverse Trafo to Matrix3x3 &lt;br /&gt;
        Matrix3x3 ConvertInverseTo3x3();&lt;br /&gt;
&lt;br /&gt;
        /// Right Mulltiplication of factor with this to a new, returned ILinearTransformation.&lt;br /&gt;
        /// Probably the trafos are converted to a LinearTransformationMatrix, but if both&lt;br /&gt;
        /// trafos are of the same type, its a good idea to multiply them together.&lt;br /&gt;
        ILinearTransformation MultiplyWithLinear(ILinearTransformation factor);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So kann man ohne weiteres Quaternionen und Matrizen wild nebeneinander verwenden. Mit der Methode MultiplyWithLinear kann man dann auch verschiedene Multiplikationen miteinander verknüpfen. So kann man Quaternionen einfach mit Quaternionen multiplizieren und gemischtes, wenn etwa Quaternionen mit Matrizen multipliziert werden, in Matrizen umwandeln:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
        #region ILinearTransformation Members&lt;br /&gt;
&lt;br /&gt;
        /// Rotates a Vertex3 through the Quaternion - this should be normalized!&lt;br /&gt;
        public Vertex3 Apply(Vertex3 v) {...}&lt;br /&gt;
        /// Rotates a Vertex3 against the Quaternion. A normalized Quaternion is assumed!&lt;br /&gt;
        public Vertex3 ApplyInverse(Vertex3 v) {...}&lt;br /&gt;
&lt;br /&gt;
        /// Converts the Quaternion to a 3x3 Matrix&lt;br /&gt;
        public Matrix3x3 ConvertTo3x3()&lt;br /&gt;
        {&lt;br /&gt;
            Matrix3x3 result = new Matrix3x3();&lt;br /&gt;
            result.sp0 = Apply(new Vertex3(1.0, 0.0, 0.0));&lt;br /&gt;
            result.sp1 = Apply(new Vertex3(0.0, 1.0, 0.0));&lt;br /&gt;
            result.sp2 = Apply(new Vertex3(0.0, 0.0, 1.0));&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /// Converts the Inverse Quaternion to a 3x3 Matrix&lt;br /&gt;
        public Matrix3x3 ConvertInverseTo3x3()&lt;br /&gt;
        {&lt;br /&gt;
            Matrix3x3 result = new Matrix3x3();&lt;br /&gt;
            result.sp0 = ApplyInverse(new Vertex3(1.0, 0.0, 0.0));&lt;br /&gt;
            result.sp1 = ApplyInverse(new Vertex3(0.0, 1.0, 0.0));&lt;br /&gt;
            result.sp2 = ApplyInverse(new Vertex3(0.0, 0.0, 1.0));&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /// Multiply the Quaternion with another trafo. If its a Quaternion, this and factor&lt;br /&gt;
        /// will be multiplied together, otherwise a LinearTransformationMatrix is generated.&lt;br /&gt;
        public ILinearTransformation MultiplyWithLinear(ILinearTransformation factor)&lt;br /&gt;
        {&lt;br /&gt;
            if (factor == null) return this;&lt;br /&gt;
            Quaternion fac = factor as Quaternion;&lt;br /&gt;
            if (fac != null)&lt;br /&gt;
            {&lt;br /&gt;
                return Multiply(fac);&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
            {&lt;br /&gt;
                // factor is not wenn known to us, we need a new LinearTransformationMatrix&lt;br /&gt;
                Matrix3x3 lin = ConvertTo3x3() * factor.ConvertTo3x3();&lt;br /&gt;
                Matrix3x3 inv = factor.ConvertInverseTo3x3() * ConvertInverseTo3x3();&lt;br /&gt;
                return new LinearTransformationMatrix(lin, inv, factor.Operator2Norm() * Operator2Norm());&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
        #endregion&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
An diesem Beispiel aus meinem Quaternioncode kann man folgendes sehen: Die Funktionen ConvertTo3x3 und ConvertInverseTo3x3 berechnen jeweils die zum Quaternion gehörenden, äquivalenten Matrizen ( Man erinnere sich an den Satz, den ich bereits im Nachhilfe Tutorial zitiert habe: Die Spalten sp&amp;lt;sub&amp;gt;i&amp;lt;/sub&amp;gt; der Matrix sind die Bilder der Einheitsvektoren. Dann dürfte sofort klar sein, was hier passiert ). In MultiplyWithLinear wird dann einfach geprüft, ob die Transformation mit der rechts multipliziert wird, ein Quaternion ist. Dann wird einfach Quaternion-Multiplikation durchgeführt, ansonsten werden sowohl der Faktor als auch das betrachtete Quaternion in 3x3 Matrizen umgewandelt und in einer LinearTransformationMatrix abgelegt - welches natürlich ILinearTransformation implementiert und immer die Transformationsmatrix und ihr Inverses bereithält.&lt;br /&gt;
&lt;br /&gt;
Damit ihr nicht ewig rumrechnen müsst (es handelt sich nämlich um eine schrecklich langwierige und ekelige Rechnerei: Ich habe etwa 2 Stunden gebraucht, bis das Ergebnis endlich fehlerfrei und brauchbar auf 2 DIN-A4 Blättern verteilt da stand), wenn ihr Quaternionen implementiert noch ein paar kleine Methoden des Quaternions. Den Rest werdet ihr dann wohl aus dem [[Quaternion|Quaternionen-Artikel]] selbst in kurzer Zeit zusammenstöpseln können.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        // &amp;quot;Coordinates&amp;quot; of the Quaternion. &lt;br /&gt;
        // coords[0] is the real component, coords[1] the i comp., ...&lt;br /&gt;
        private double[] coords = new double[4];&lt;br /&gt;
&lt;br /&gt;
        /// Creates a rotation Quaternion&lt;br /&gt;
        public Quaternion(double alpha, Vertex3 rotAxis)&lt;br /&gt;
        {&lt;br /&gt;
            alpha = (2.0*Math.PI/(360.0*2.0))* alpha;&lt;br /&gt;
&lt;br /&gt;
            coords[0] = 1.0;&lt;br /&gt;
            if (rotAxis.Magnitude &amp;lt; double.Epsilon)&lt;br /&gt;
            {&lt;br /&gt;
                return;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            rotAxis.Normalize();&lt;br /&gt;
            double c, s;&lt;br /&gt;
            c = Math.Cos(alpha); s = Math.Sin(alpha);&lt;br /&gt;
            coords[0] = c; coords[1] = rotAxis[0] * s; &lt;br /&gt;
            coords[2] = rotAxis[1] * s; coords[3] = rotAxis[2] * s;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        /// Rotates a Vertex3 through the Quaternion - this should be normalized!&lt;br /&gt;
        public Vertex3 Apply(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            Vertex3 result = new Vertex3();&lt;br /&gt;
            double v0 = v[0]; double v1 = v[1]; double v2 = v[2];&lt;br /&gt;
            double a00 = coords[0] * coords[0];&lt;br /&gt;
            double a01 = coords[0] * coords[1];&lt;br /&gt;
            double a02 = coords[0] * coords[2];&lt;br /&gt;
            double a03 = coords[0] * coords[3];&lt;br /&gt;
            double a11 = coords[1] * coords[1];&lt;br /&gt;
            double a12 = coords[1] * coords[2];&lt;br /&gt;
            double a13 = coords[1] * coords[3];&lt;br /&gt;
            double a22 = coords[2] * coords[2];&lt;br /&gt;
            double a23 = coords[2] * coords[3];&lt;br /&gt;
            double a33 = coords[3] * coords[3];&lt;br /&gt;
            result[0] = v0 * (+a00 + a11 - a22 - a33)&lt;br /&gt;
                + 2 * (a12 * v1 + a13 * v2 + a02 * v2 - a03 * v1);&lt;br /&gt;
            result[1] = v1 * (+a00 - a11 + a22 - a33)&lt;br /&gt;
                + 2 * (a12 * v0 + a23 * v2 + a03 * v0 - a01 * v2);&lt;br /&gt;
            result[2] = v2 * (+a00 - a11 - a22 + a33)&lt;br /&gt;
                + 2 * (a13 * v0 + a23 * v1 - a02 * v0 + a01 * v1);&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
        /// Rotates a Vertex3 against the Quaternion. A normalized Quaternion is assumed!&lt;br /&gt;
        public Vertex3 ApplyInverse(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            Vertex3 result = new Vertex3();&lt;br /&gt;
            double v0 = v[0];&lt;br /&gt;
            double v1 = v[1];&lt;br /&gt;
            double v2 = v[2];&lt;br /&gt;
            // Like Apply. We only konjugate the im. factors&lt;br /&gt;
            double a00 = coords[0] * coords[0];&lt;br /&gt;
            double a01 = -coords[0] * coords[1];&lt;br /&gt;
            double a02 = -coords[0] * coords[2];&lt;br /&gt;
            double a03 = -coords[0] * coords[3];&lt;br /&gt;
            double a11 = +coords[1] * coords[1];&lt;br /&gt;
            double a12 = +coords[1] * coords[2];&lt;br /&gt;
            double a13 = +coords[1] * coords[3];&lt;br /&gt;
            double a22 = +coords[2] * coords[2];&lt;br /&gt;
            double a23 = +coords[2] * coords[3];&lt;br /&gt;
            double a33 = +coords[3] * coords[3];&lt;br /&gt;
            result[0] = v0 * (+a00 + a11 - a22 - a33)&lt;br /&gt;
                + 2 * (a12 * v1 + a13 * v2 + a02 * v2 - a03 * v1);&lt;br /&gt;
            result[1] = v1 * (+a00 - a11 + a22 - a33) &lt;br /&gt;
                + 2 * (a12 * v0 + a23 * v2 + a03 * v0 - a01 * v2);&lt;br /&gt;
            result[2] = v2 * (+a00 - a11 - a22 + a33) &lt;br /&gt;
                + 2 * (a13 * v0 + a23 * v1 - a02 * v0 + a01 * v1);&lt;br /&gt;
            return result;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Wer ein Quaternion mithilfe des angegebenen Konstruktors erstellt, erhält ein Rotationsquaternion der Norm 1. Genau das, was für die Funktionen Apply und ApplyInverse notwendig ist, damit sie das tun, was sie sollen. Damit soll ersteinmal der Faulheit beim Rechnen und dem Copy&amp;amp;Paste genüge getan sein. Und wehe ich entdecke irgendwann Raytracer, die Objekte nur rotieren können statt beliebige [[Matrix|Matrizen]] zu vertragen ;-) Am Ende bleibt es natürlich euch überlassen. Wenn ihr wollt, könnt ihr all das auch allein durch Matrizen implementieren und euch den Umweg über das Quaternion ersparen - allerdings sieht man einem Quaternion schneller an was es bewirkt, als einer Matrix.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir einen kleinen Ausflug in Richtung Quaternionen und Transformationen hinter uns gebracht haben, könnte man hoffen, daß wir jetzt endlich mit dem abstrakten Kram aufhören und wir bald mal wieder ein paar neue Bilder zu Gesicht bekommen. Soweit ist es leider noch nicht. Ich möchte zwischendrin den Schlachtplan für die nächsten Minuten bekannt geben: Wir werden jetzt die Punkte in den Trans-Space-Funktionen der Basisklasse füllen, um uns dann dem Licht durch Phong-Lighting über den Umweg der Normalen zu widmen. Beginnen wir also mit der Funktion TransSpaceParentToObject, welche Strahlen des elterlichen Raumes in den lokalen Raum transformieren soll. Wenn man nun an die Kameraanalogie denkt, wie sie etwa im [[Tutorial_Kamera1|Kamera Tutorial]] beschrieben ist, dann wissen wir, daß wir die auf das Objekt angewendete Transformation einfach nur umkehren müssen. Denkt man dann noch daran, daß wir erreichen wollen, daß das Objekt im lokalen Raum am Ursprung befinden soll, ist die Implementation schnell naheliegend: Den Ursprung des Strahles müssen wir erst um die Position verschieben und dann invers transformieren. Bei der Richtung genügt es, diese invers zu transformieren.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;&lt;br /&gt;
        public virtual Ray TransSpaceParentToObject(Ray r)&lt;br /&gt;
        {&lt;br /&gt;
            Ray ray = r;&lt;br /&gt;
            ray.Origin -= pos;&lt;br /&gt;
            if (ptransformation != null)&lt;br /&gt;
            {&lt;br /&gt;
                ray.Origin = ptransformation.ApplyInverse(ray.Origin);&lt;br /&gt;
                ray.Direction = ptransformation.ApplyInverse(ray.Direction);&lt;br /&gt;
            }&lt;br /&gt;
            return ray;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei dieser Überlegung fallen auch gleich die Funktionen TransSpacePointParentToObject, welche einen Punkt in die lokalen Koordinaten überträgt und die Entsprechende Funktion TransSpaceParentToObject für Richtungen ab. Das ganze können wir natürlich auch in die andere Richtung machen: Bislang ist mir aber noch kein Grund eingefallen, dies zu tun. Wichtig dagegen ist es, Richtungen in Weltkoordinaten umzurechnen, da wir dies für die Normalen später benötigen werden. Dies erreichen wir leicht, wenn wir ausnutzen, daß Objekte immer ihre Eltern kennen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        public virtual Vertex3 TransSpaceObjectToWorld(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            if (ptransformation != null)&lt;br /&gt;
            {&lt;br /&gt;
                v = ptransformation.Apply(v);&lt;br /&gt;
            }&lt;br /&gt;
            if (fParent != null)&lt;br /&gt;
            {&lt;br /&gt;
                v = fParent.TransSpaceObjectToWorld(v);&lt;br /&gt;
            }&lt;br /&gt;
            return v;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die entsprechende Funktion für Punkte solltet ihr der Übung halber selbst schreiben. Mit den genannten Zweien kommen wir auf jeden Fall erst einmal aus - ich bin mir gar nicht sicher, ob in meinem eigenen Raytracer je die Anderen zum Einsatz gekommen sind. Naja, es schadet jedenfalls nicht, wenn sie da sind.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_RaytracingII_spherenormals.jpg|right|framed|Visualisierung der Normalen]]&lt;br /&gt;
Um nun mit dem Licht weiter machen zu können, müssen wir die Intersect-Funktionen für Kugeln und Ebenen um Normalenerzeugung erweitern. Wir dürfen nicht vergessen, diese dann in den World-Space zu transformieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;        /// Calculates the World-Space normal for a surface point&lt;br /&gt;
        protected Vertex3 CalcNormal(Vertex3 v)&lt;br /&gt;
        {&lt;br /&gt;
            Vertex3 normal = TransSpaceObjectToWorld(v);&lt;br /&gt;
            normal.Normalize();&lt;br /&gt;
            return normal;&lt;br /&gt;
        }&lt;br /&gt;
        ...&lt;br /&gt;
        public override int Intersect(RenderSettings rs, Ray ray, &lt;br /&gt;
            double raymindist, double raymaxdist, bool calcNormals, &lt;br /&gt;
            bool calcTextureCoordinates, ref IntersectionInfo info)&lt;br /&gt;
        {&lt;br /&gt;
            Ray osray = TransSpaceParentToObject(ray);&lt;br /&gt;
&lt;br /&gt;
            double a, b, c;&lt;br /&gt;
            a = osray.d.DotDot; b = 2 * (osray.o * osray.d);&lt;br /&gt;
            c = osray.o.DotDot - sphereRadius * sphereRadius;&lt;br /&gt;
&lt;br /&gt;
            double t1, t2;&lt;br /&gt;
            int roots = GeoMath.CalcQuadricRoots(a, b, c, out t1, out t2);&lt;br /&gt;
&lt;br /&gt;
            // roots are sorted so check only for tr2&lt;br /&gt;
            if (roots &amp;gt; 0 &amp;amp;&amp;amp; t2 &amp;gt;= raymindist &amp;amp;&amp;amp; t1 &amp;lt;= raymaxdist)&lt;br /&gt;
            {&lt;br /&gt;
                info = new IntersectionInfo();&lt;br /&gt;
                Vertex3 v; info.material = ObjectMaterial;&lt;br /&gt;
&lt;br /&gt;
                info.rayPosition = t1;&lt;br /&gt;
                if (t1 &amp;gt;= raymindist)&lt;br /&gt;
                {&lt;br /&gt;
                    v = osray.Evaluate(t1);&lt;br /&gt;
                    if (calcNormals) info.normal = CalcNormal(v);&lt;br /&gt;
                    if (calcTextureCoordinates) &lt;br /&gt;
                        info.texture = GeoMath.SphereCoordinates(v);&lt;br /&gt;
                    return 1;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                v = osray.Evaluate(t2);&lt;br /&gt;
                if (calcNormals) info.normal = CalcNormal(v);&lt;br /&gt;
                if (calcTextureCoordinates) &lt;br /&gt;
                    info.texture = GeoMath.SphereCoordinates(v);&lt;br /&gt;
                info.rayPosition = t2;&lt;br /&gt;
                return 1;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                return -1;&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Phong Licht ==&lt;br /&gt;
[[Bild:Tutorial_RaytracingII_phong.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wir sind soweit. Die ersten hübscheren Bilder aus unserem Raytracer sind greifbar nahe. Wir müssen uns im wesentlichen nur noch mit Phong Licht beschäftigen, um aus unserem Raytracer mehr herauszuquetschen. Das Phong-Beleuchtungsmodell ist ein sehr einfaches Modell, um Licht zu simulieren. Es ist physikalisch ziemlich falsch: Durch Hinzufügen von Objekten in einen physikalischen Raum, die sich lichttechnisch nach dem Phong Modell verhalten, wird i.A. die vorhandene Lichtenergie erhöht. Das ist sehr tragisch, wenn man globale Beleuchtungsmethoden verwendet, aber fürs erste ist es ein sehr gut aussehendes und leicht zu  berechnendes Modell. Wir wollen uns also von dieser Anomalität nicht beunruhigen lassen und uns nur daran erinnern, wenn wir einmal globale Beleuchtungsmethoden einführen wollen. Jedem sollte das Phong Modell wohl vertraut sein, da es das Standard-Modell in OpenGl ist. Wer hier noch Nachholbedarf hat, schaue doch einmal im [[Beleuchtung|Beleuchtungs-Artikel]] oder [http://www.delphi3d.net/articles/viewarticle.php?article=phong.htm in Tom Nuydens': Phong For Dummies]. &lt;br /&gt;
&lt;br /&gt;
Jedenfalls, wenn wir jedem Objekt ein Material mit den Koeffizienten aus dem Phong-Modell zugeordnet haben, dann können wir mithilfe einer IntersectionInfo für Strahl/Objekt-Schnittpunkte und aller Lichtquellen leicht die zugehörige Farbe bestimmen. An der Stelle, wo wir also im Tiefentracer den Grauwert bestimmten, bestimmen wir&lt;br /&gt;
jetzt den zugehörigen Farbwert über unser Material: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;public RaytraceImage ( int width , int height )&lt;br /&gt;
{&lt;br /&gt;
    for ( int x = 0; x &amp;lt; width; x++) {&lt;br /&gt;
        for ( int y = 0 ; y &amp;lt; height; y++) {&lt;br /&gt;
            Ray shoot = ShootRay (x , y);&lt;br /&gt;
            double maxdist = double.Infinity;&lt;br /&gt;
            &lt;br /&gt;
            IntersectionInfo cinfo = new IntersectionInfo();;&lt;br /&gt;
            IntersectionInfo iinfo = new IntersectionInfo();&lt;br /&gt;
            &lt;br /&gt;
            foreach (ObjectBase obj in SichtbareObjekte) {&lt;br /&gt;
                if (obj.Intersect(rs, shoot, 0, maxdist, true, true, ref cinfo) &amp;gt; 0 &lt;br /&gt;
                  &amp;amp;&amp;amp; cinfo.rayPosition &amp;lt; maxdist) iinfo = cinfo;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            if (maxdist &amp;lt; double.Infinity &amp;amp;&amp;amp; iinfo.material != null) {&lt;br /&gt;
                SetColor(x, y, iinfo.Material.GetColor(iinfo));&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                SetColor(x, y, BackgroundColor);   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Abschluss ==&lt;br /&gt;
Da habt ihr euch ja durch ein dickes Ding gequält ( besonders wenn ihr im Bereich Transformationen oder Phong noch Nachholbedarf hattet, hats sicher eine Weile gedauert ). Gratulation. Langsam wird das Raytracing ja interessant und die Szenen sind nicht mehr ganz so langweilig. Es bleibt aber immer noch genügend Stoff für ein weiteres Grundlagen Tutorial: In Planung sind hier ein paar Worte bezüglich Reflexionen, Schatten und ein paar weiteren Objekten wie Dreiecken (das impliziert eine Lehrstunde in Sachen Phong Shading), Boxen und Zylinder. Dazu sollten wir ausserdem unseren Raytracer umbauen: Er wird in eine eigene Tracer-Klasse ausgelagert werden, um so schnell die Wahl zwischen verschiedenen Raytracern zu haben. Stay tuned.&lt;br /&gt;
&lt;br /&gt;
'''Delphic'''&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Raytracing_-_Grundlagen_I&amp;diff=23933</id>
		<title>Tutorial Raytracing - Grundlagen I</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Raytracing_-_Grundlagen_I&amp;diff=23933"/>
				<updated>2009-07-23T15:12:00Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Tutorial Raytracing - Grundlagen I =&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_teaser.jpg|center]]&lt;br /&gt;
== Einführung ==&lt;br /&gt;
Da melde ich mich mal wieder zurück mit einem kleinen Tutorial bezüglich Raytracing. Ihr sollt ja gelegentlich was neues lernen. Es ist zwar etwas schade, daß nur noch selten Tutorials aus der Community kommen - ich hoffe immernoch, daß sich das irgendwann wieder ändern wird. Und alle die bislang Tutorials geschrieben haben, mussten ja irgendwann ihr erstes schreiben - also nur Mut (mein allererstes war im Übrigen das 1. Tutorial aus der Terrain-Reihe). Nunja. Was hat es also mit dem Raytracing auf sich? Und warum heisst dieses Tutorial Grundlagen I? Ich will es euch erklären. Beim Raytracing verfolgt man im Gegensatz zum Rastern wie es etwa OpenGl oder Direct3D machen, einen anderen Ansatz. Statt Objekte oberflächlich in Polygone zu zerschneiden und sie dann auf den Bildschirm per Z-Buffer zu projezieren, wirft die Kamera Strahlen in die Szenerie und auf jedem Strahl prüft man, ob sich ein Objekt mit dem Strahl schneidet. Man verliert dadurch sehr deutlich Geschwindigkeit: die wenigsten Raytracer sind so schnell, dass man interaktiv damit arbeiten kann. Wozu also ist dann Raytracing gut? Man kann im Raytracer hoch realistisch wirkende Bilder erzeugen und auch Verfahren verwenden, die im Rasterizer nicht oder kaum nachzubauen sind - die gute alte Grafikkarte muss dabei nicht völlig unnütz werden: Diese besitzen sehr flotte und massiv parallele Geometrie-Einheiten, die auch im Raytracer Verwendung finden können - dies ist aber etwas zu speziell für unser kleines Tutorial und vielleicht auch nicht das, was man in seinem ersten Raytracer implementieren würde. Was sich im Bereich interaktiver Grafik allerdings anbietet, ist den Raytracer ein wenig umzumodeln und mit ihm statische Lightmaps erzeugen oder ihn zur Selection missbrauchen. Das einzige Problem welches wir dabei haben: Wir müssen alles von Grund auf zusammenbasteln - nicht so schön, wie bei OpenGl, wo man nach ein paar Stunden recht ansehnliche Bilder samt Beleuchtung zeichnen kann. Wir werden da wohl etwas länger brauchen, aber ewig wird es auch nicht dauern - und schliesslich musste OpenGl ja auch erst einmal designed werden. Andere Dinge werden sich dagegen deutlich leichter implementieren lassen als mit OpenGl, so sind etwa Schatten im Raytracer ein Kinderspiel - im Rasterizer können sie richtig arbeitsintensiv werden.&lt;br /&gt;
&lt;br /&gt;
== Die griechische Vorstellung ==&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_griechisch.jpg|right]]&lt;br /&gt;
Die Griechen hatten eine etwas sonderbare Vorstellung vom Sehen: Sie stellten sich vor, dass aus ihren Augen Strahlen kommen, die dann auf die Umgebung treffen und quasi Nachricht an das Auge geben, was sie getroffen haben, wie weit weg es ist und welche Farbe es hat. Das ist in etwa das was auch ein Raytracer macht. Wir wollen das erst einmal im Hinterkopf behalten und uns zunächst mit Strahlen genauer auseinandersetzen. Danach werden wir Kugeln mit diesen Strahlen schneiden und eine passende perspektivische Kamera entwerfen. Schließlich werden wir einen sehr einfachen Raytracer schreiben, und ihm anschließend noch Ebenen als Objekte näherbringen, weil Kugeln alleine doch etwas langweilig sind.&lt;br /&gt;
&lt;br /&gt;
== Strahlen ==&lt;br /&gt;
Was ist also ein Strahl? Ein Strahl hat einen Ursprung, an dem er beginnt, und eine Richung, in die er verläuft. Wer in der Schule in Geometrie aufgepasst hat, kennt dieses Objekt sicher auch noch als Halbgerade. Da wir später damit rechnen werden, müssen wir den Strahl in eine schöne Formel packen:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_strahlgleichung.png|center]]&lt;br /&gt;
Die Punkte auf unserem Strahl r sind also parametrisiert durch t, welches die&lt;br /&gt;
Zahlen von 0 bis unendlich durchläuft. Der Ursprung des Strahles ist o und seine&lt;br /&gt;
Richung d. Somit kennen wir alle Punkte auf dem Strahl. &lt;br /&gt;
&lt;br /&gt;
Um nun zu prüfen, ob ein Strahl nun ein Objekt trifft, beginnen wir bei t = 0 und laufen alle Punkte ab, bis wir bei t = unendlich angekommen ... ... ... Nein so machen wir das natürlich nicht - funktionieren würde es zwar, würde aber unendlich lange dauern: Nicht gerade das, was wir uns unter schnell vorstellen. &lt;br /&gt;
&lt;br /&gt;
Bevor wir weitermachen, sollten wir unseren Strahl gleich in&lt;br /&gt;
etwas Code verpacken, schließlich wollen wir uns ja einen Raytracer schreiben:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;public struct Ray&lt;br /&gt;
{&lt;br /&gt;
    public Vertex3 Origin;&lt;br /&gt;
    public Vertex3 Direction;&lt;br /&gt;
&lt;br /&gt;
    public Vertex3 Evaluate (double t)&lt;br /&gt;
    {&lt;br /&gt;
        return Origin + t * Direction;&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zurück zu unserem Problem: Wir müssten also unendlich lange darauf warten, bis unser Raytracer das Objekt gefunden hat, mit dem sich der momentan betrachtete Strahl schneidet. Viel schneller geht die Sache, wenn wir vorher beschließen, welche Objekte wir anzeigen können wollen. Für den Anfang wollen wir uns mit sehr einfachen Objekten begnügen: Kugeln. Sie sind schnell berechnet und werden für erste Experimente ausreichen.&lt;br /&gt;
&lt;br /&gt;
== Kugeln ==&lt;br /&gt;
Erinnerung: Eine Kugel ist definiert durch ihren Mittelpunkt und ihren Radius r. Setzt man den Mittelpunkt auf den Ursprung des Koordinatensystems, dann sind die Punkte auf der Oberfläche O unserer Kugel gerade die Punkte, die vom Ursprung den Abstand r haben. Die uns interessierende Bedingung wird so zu ||p|| = r für Punkte p auf O. Die Gleichung kann man schadlos quadrieren und statt der Vektorlänge ||p|| bekommt man das ohne Wurzel ziehen zu berechnende [[Standard Skalarprodukt|Skalarprodukt]] von p mit sich selbst:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_skalprodpp.png|center]]&lt;br /&gt;
Setzt man hierein die obige Gleichung für den Strahl, ergibt sich:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_radsqr.png|center]]&lt;br /&gt;
Und damit:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_radsqr2.png|center]]&lt;br /&gt;
Da die Richtung o und d unseres Strahls bekannt sind, haben wir eine quadratische Gleichung vor der Nase, die wir mittels Mitternachtsformel lösen können:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_mitternacht.png|center]]&lt;br /&gt;
Anhand der Diskriminante D, also dem Teil des obigen Ausdrucks, der unter der Wurzel steht, können wir entscheiden, ob der Strahl die Kugel trift. Ist nämlich D &amp;lt; 0, so kann man in den reelen Zahlen die Wurzel nicht berechnen. Ist D = 0, so gibt es genau eine Lösung der Schnittgleichung und für D &amp;gt; 0 schneidet der Strahl die Kugel genau 2 mal. Da wir unseren Strahl nur für positive Parameter t definiert haben, sollten wir die errechneten Schnittpunkte t&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; und t&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; noch daraufhin untersuchen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;public double RayIntersect ( Ray ray )&lt;br /&gt;
{&lt;br /&gt;
    double boundingSquare = sphereRadius * sphereRadius ;&lt;br /&gt;
    ray.Origin -= Position;&lt;br /&gt;
    double a, b, c;&lt;br /&gt;
    a = ray.Direction.DotDot ;&lt;br /&gt;
    // DotDot ^= Skalarprod mit sichselbst : &amp;lt;d, d&amp;gt;&lt;br /&gt;
    b = 2 * ( ray.Origin * ray.Direction );&lt;br /&gt;
    // * ^= normales Skalarprod&lt;br /&gt;
    c = ray.Origin.DotDot - boundingSquare;&lt;br /&gt;
&lt;br /&gt;
    double t1 , t2 ;&lt;br /&gt;
    int roots = CalcQuadricRoots (a, b, c, out t1, out t2) ;&lt;br /&gt;
&lt;br /&gt;
    if (roots &amp;gt; 0)&lt;br /&gt;
        return t1 &amp;gt;= 0 ? t1 : t2 ;&lt;br /&gt;
        // kleinsterpositiver pos. Wert aus t1, t2&lt;br /&gt;
    else&lt;br /&gt;
        return -1; // Kein Schnittpunkt&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
Einen kleinen Haken hat die Sache jedoch: Analytisch, d.h. per Stift und Papier, lässt sich mit der Mitternachtsformel wunderbar rechnen. Am Computer neigt sie zu Fehlern, was ganz allein an dem &amp;amp;plusmn; liegt. So führt man verlässlich eine Subtraktion durch, wenn D &amp;gt; 0 ist - und Subtraktionen sind reines Gift für die Genauigkeit bei numerischen Rechnungen. Durch kleine Umformungen und das Bestimmen eines Vorzeichens, können wir das Problem umgehen:&lt;br /&gt;
&lt;br /&gt;
== Quadratische Gleichungen ==&lt;br /&gt;
Hat man also eine Quadratische Gleichung in der allgemeinen Form:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_quadratisch.png|center]]&lt;br /&gt;
dann bestimmt man die Nullstellen am besten durch:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_quadratisch_numerisch.png|center]]&lt;br /&gt;
Bei der Auswertung von q wird so sicherlich echt addiert, weil zu b eine Zahl gleichen Vorzeichens summiert wird. Dass der Wert für t&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; stimmt, hat man dann auch sehr leicht nachgerechnet, wohingegen t&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; in wildes Rumgeschiebe der Formel ausartet und sich erst recht spät sign(b) herauswerfen lässt. Ich erspare euch nähere Erläuterungen ;-) Ein bischen Quellcode hierzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;public static int CalcQuadricRoots(double a, double b, double c, out double x1, out double x2)&lt;br /&gt;
{&lt;br /&gt;
    double determinant = b * b - 4 * a * c;&lt;br /&gt;
    if (determinant &amp;lt; 0)&lt;br /&gt;
    {&lt;br /&gt;
        x1 = 0.0;&lt;br /&gt;
        x2 = 0.0;&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
    determinant = Math.Sqrt(determinant);&lt;br /&gt;
    double q = -0.5 * (b + PSgn(b) * determinant);&lt;br /&gt;
    // Psgn: gives - 1 if b &amp;lt; 0 and 1 if b &amp;gt;= 0. &lt;br /&gt;
    // so no zero as normal sgn would give us.&lt;br /&gt;
    x1 = q / a;&lt;br /&gt;
    x2 = c / q;&lt;br /&gt;
    // Sort by value&lt;br /&gt;
    if (x1 &amp;gt; x2)&lt;br /&gt;
    {&lt;br /&gt;
        q = x2; x2 = x1; x1 = q;&lt;br /&gt;
    }&lt;br /&gt;
    return x1 == x2 ? 1 : 2;&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
Die Funktion speichert die Nullstellen in den Variablen x1, x2 dem Wert nach sortiert ab und gibt die Anzahl der Nullstellen zurück.&lt;br /&gt;
Da wir jetzt bereits bestimmen können, wo und wie oft unser Strahl die Kugel trift, können wir, nachdem wir uns noch einen Strahlenwerfer, (also eine Kamera) konstruiert haben, unseren ersten Raytracer bauen.&lt;br /&gt;
&lt;br /&gt;
== Perspektivische Kamera ==&lt;br /&gt;
Jeder, der sich mit OpenGL auskennt, wird bei der Konstruktion einer perspektivischen Kamera gleich schreien, daß man dazu doch einfach nur eine Projektionsmatrix braucht, die man sich ganz einfach aus der OpenGL Spezifikation stibitzen kann. Falsch gedacht: Ein Raytracer ist kein Rasterizer: Wir brauchen keine Projektionsmatrizen, noch nicht einmal Matrizen. Die perspektivische Kamera eines Ray-Tracers lässt sich direkt nach vorn heraus entwerfen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_perspektivisch.png|center]]&lt;br /&gt;
&lt;br /&gt;
Unrotiert und unverschoben soll unsere Kamera in die Tiefenrichtung z blicken. Dabei wird unser Bildschirm durch die Parameter links, rechts, oben und unten beschrieben. Ist die Auflösung des Bildschirms in X wie in Y-Richtung bekannt, so kann man leicht die Richtung d des Vektors bestimmen, der vom Betrachter auf den Bildschirm zeigt. Sofort bekommt man so einen Strahl, wenn man als Anfangspunkt o die Position des Betrachters wählt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;public Ray ShootRay ( int x , int y )&lt;br /&gt;
{&lt;br /&gt;
    Ray result = new Ray();&lt;br /&gt;
    result.Origin = Position;&lt;br /&gt;
&lt;br /&gt;
    double xpart , ypart ;&lt;br /&gt;
    xpart = ( ( double ) x ) / (double ) widthpixels;&lt;br /&gt;
    ypart = ( ( double ) y ) / (double ) heightpixels;&lt;br /&gt;
 &lt;br /&gt;
    xpart = left + xpart * ( right - left ) ;&lt;br /&gt;
    ypart = top + ypart * ( bottom - top ) ;&lt;br /&gt;
 &lt;br /&gt;
    result.Direction.x = xpart;&lt;br /&gt;
    result.Direction.y = ypart;&lt;br /&gt;
    result.Direction.z = 1.0;&lt;br /&gt;
&lt;br /&gt;
    /* if ( Transformation != null )&lt;br /&gt;
    {&lt;br /&gt;
        result.Direction =&lt;br /&gt;
        Transformation.Apply( result.Direction );&lt;br /&gt;
    } */&lt;br /&gt;
    result.Direction.Normalize();&lt;br /&gt;
    return result;&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
Die auskommentierte if-Abfrage soll vorerst nicht stören. Ihr wird später leben eingehaucht, wenn wir dem Raytracer Verschiebungen,&lt;br /&gt;
Rotationen, Skalierungen, Scheerungen, u.s.w. einbauen.&lt;br /&gt;
&lt;br /&gt;
== Einfacher Raycaster ==&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_depthcasting.jpg|right]]&lt;br /&gt;
Damit sind wir dann auch schon soweit, daß wir unsere ersten Gehversuche in Sachen Raytracing wagen können. Für jedes Pixel im Bild werfen wir mittels ShootRay einen Strahl und prüfen, ob dieser die Kugeln in unserer Szene schneidet. Wenn ja, merken wir uns den nähestes dieser Schnittpunkte und weisen ihm einen Farbwert zu. So erhalten wir ein Bild, das in etwa die Informationen wieder gibt, die OpenGl in seinem Tiefenpuffer speichern würde. Ich gebe zu, das ist nicht hochgradig spannend, aber solange wir uns noch nicht eingehender mit Licht und Shading beschäftigt haben, können wir auch nicht mehr erwarten - und wir haben beim Raytracing ja leider das Problem, daß wir ganz von vorne anfangen müssen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;cpp&amp;quot;&amp;gt;public RaytraceImage ( int width , int height )&lt;br /&gt;
{&lt;br /&gt;
    // near und far sind die Werte fuer den Bereich ,&lt;br /&gt;
    // von dem Tiefeninformationen abgebildet werden&lt;br /&gt;
    for ( int x = 0; x &amp;lt; width; x++) {&lt;br /&gt;
        for ( int y = 0 ; y &amp;lt; height; y++) {&lt;br /&gt;
            Ray shoot = ShootRay (x , y);&lt;br /&gt;
            double maxdist = double.Infinity;&lt;br /&gt;
            &lt;br /&gt;
            foreach (Kugel obj in SichtbareKugeln) {&lt;br /&gt;
                double hitdist = obj.RayIntersect(shoot) ;&lt;br /&gt;
                if (hitdist &amp;gt; 0 &amp;amp;&amp;amp; maxdist &amp;gt; hitdist)&lt;br /&gt;
                    maxdist = hitdist;&lt;br /&gt;
            }&lt;br /&gt;
            &lt;br /&gt;
            if (maxdist &amp;lt; double.Infinity) {&lt;br /&gt;
                SetColor(x, y, Colors.Gray (Math.Min(Math .Max(0,&lt;br /&gt;
                    (maxdist - near) / ( near - far ))), 1.0)) ;&lt;br /&gt;
            }&lt;br /&gt;
            else&lt;br /&gt;
                SetColor(x, y, BackgroundColor);   &lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&amp;lt;/source&amp;gt;&lt;br /&gt;
Eine kleine Anmerkung noch: Da wir uns noch nicht über Transformationen Gedanken gemacht haben, und unsere Kugeln bislang am Nullpunkt aufgehäng sind, können wir diese noch nicht positionieren - sprich es wird höchstens die größte Kugel sichtbar, weil alle weiteren verdeckt sind. Das lässt sich beheben, indem man vor dem Test auf Schnitt vom Ursprung des entsprechenden Strahles, die Position der Kugel abzieht.&lt;br /&gt;
&lt;br /&gt;
== Ebenen ==&lt;br /&gt;
Mit Kugeln kann man zwar so einiges darstellen, aber nur Kugeln sind vielleicht doch etwas langweilig. Wir wollen deshalb noch Ebenen implementieren. Am besten betrachten wir diese dazu in der Normalform, d.h. die Ebene wird allein durch ihre Flächennormale angegeben. Für Punkte auf der Ebene gilt dann:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_ebenengleichung.png|center]]&lt;br /&gt;
Setzt man nun in x unseren Strahl ein, ergibt sich:&lt;br /&gt;
[[Bild:Tutorial_RaytracingI_ebenenrechnung.png|center]]&lt;br /&gt;
Ist &amp;lt;d,n&amp;gt;=0, dann gibt es keine Lösung, sonst genau eine. &lt;br /&gt;
&lt;br /&gt;
Welche Objekte eignen sich sonst gut zum Raytracing? ... Alle Objekte, die sich in kartesischen Koordinaten durch eine Gleichung der Form [[Bild:Tutorial_RaytracingI_kartesisch.png|center]] darstellen lassen. In (x,y,z) setzt man seinen Strahl r(t) ein und versucht nach t aufzulösen. In einigen Fällen wird dieses Problem leider kaum zu lösen sein: man kommt dann um den Einsatz von numerischen Verfahren nicht herum. Ich werde versuchen, in Folgetutorials noch ein paar weitere, interessante Objekte vorzustellen, die sich direkt lösen lassen und wenn ich viel Geduld habe, vielleicht auch einmal einen eigenen Artikel bezüglich numerischer Verfahren.&lt;br /&gt;
&lt;br /&gt;
== Vorschau ==&lt;br /&gt;
Damit sind wir auch schon wieder soweit. Die ersten Grundlagen sind abgehandelt, aber wirklich überzeugt sind wir vom Raytracing noch nicht. Damit sich das ändert, sind weitere Tutorials in Planung: Wir wollen uns dann mit Licht und Normalen beschäftigen. Ausserdem sind Reflektionen und Transparenz spannende Dinge, denen wir uns widmen können. Wir wollen ausserdem unsere Objekte transformieren, scheeren, rotieren, ... Es bleibt also noch einiges im Bereich Raytracing zu tun, was hier nicht behandelt wurde.&lt;br /&gt;
&lt;br /&gt;
Bis es soweit ist, könnt ihr euch ja selbst schonmal ein paar Gedanken zum Thema machen oder euch doch lieber in die Weiten von OpenGl flüchten.&lt;br /&gt;
&lt;br /&gt;
'''Delphic'''&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Terrain3&amp;diff=23931</id>
		<title>Tutorial Terrain3</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Terrain3&amp;diff=23931"/>
				<updated>2009-07-23T15:11:35Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Continuous Level of Detail fur Heightmaps=&lt;br /&gt;
&lt;br /&gt;
==Einführung==&lt;br /&gt;
&lt;br /&gt;
Hi, &lt;br /&gt;
&lt;br /&gt;
Ich habe in meinem ersten Heightmap Tutorial im Nachwort erzahlt, dass ich vielleicht ein Tutorial uber Level of Detail (LOD) fur Heightmaps schreibe. Ich will hiermit mein Versprechen einlosen, will euch aber auch gleich warnen, es ist nicht so leicht, wie man eigentlich denken konnte, denn viele Probleme stellen sich einem in den Weg, z.B. Cracks im [[Mesh]]. &lt;br /&gt;
&lt;br /&gt;
Erkundigt man sich unter Spieleentwicklern nach LOD fur Heightmaps, wird man in den meisten Fallen wohl auf den Begriff ROAMing stosen. Dieser wird z.B. in einem meiner Lieblingsgames Tribes 2 verwendet. Mich hat dieser Algorithmus nicht wirklich angesprochen und ich habe weitergesucht. Nach einiger Zeit bin ich auf den Algorithmus aufmerksam geworden, der im Spiel Aquanox sein Konnen zeigt. Genauer gesagt bin ich uber das [http://www.vterrain.org Virtual Terrain Project] darauf gestosen. Das Original Script von [http://www9.cs.fau.de/Persons/Roettger Stefan Rottger] findet sich direkt auf seiner Homepage unter Terrain Rendering: [http://wwwvis.informatik.uni-stuttgart.de/~roettger/data/Papers/TERRAIN.PDF Real-Time Generation of Continuous Levels of Detail for Height Fields] Ich kann euch wirklich warmstens empfehlen, dieses Script sich einmal genauer anzuschauen - sehr interessant. In diesem Tutorial werde ich das Schriftstuck etwas genauer beleuchten und ein paar Hilfestellungen dazu geben, in der Hoffnung, dass ihr es mir gleich tut und diesen Algorithmus selbst einmal nachbaut.&lt;br /&gt;
&lt;br /&gt;
==Quadtree==&lt;br /&gt;
&lt;br /&gt;
Der Ganze Algorithmus basiert auf einem Quadtree. Dieser wird durch eine Boolean Matrix(fur die Delpher, die immer noch nicht wissen, was eine Matrix ist: Wir reden uber ein 2 Dimensionales '''Array[0..n,0..n] of Boolean''') reprasentiert, so kann man sich eine Menge Pointer(und damit Speicherplatz) und viel Rechenarbeit sparen. Wir gehen davon aus, dass die Matrix eine Grose von (2n+1)x(2n+1) hat. Idealerweise hat die verwendete Heightmap die gleichen Ausmase. Die Hauptnode sitzt in der Mitte der Matrix, die 4 Kinder... Bevor ich in Erklarungsnote komme, hier einfach ein Bild, das den Sachverhalt verdeutlichen soll:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_quadmatrix.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Ok, wir wissen nun, wie die Matrix aufgebaut ist, wie die Mutter Kind Verhaltnisse des Quadtrees sind, etc., nur ist noch immer nicht klar, wozu diese Matrix. Wie bereits gesagt, handelt es sich um eine Boolean Matrix. Die Werte, die die Matrix annehmen kann, sind True oder False :-). Diese sagen aus, ob eine Node gesetzt ist und damit gezeichnet wird, oder eben nicht. Unsere Ziele sind also zum einen die Matrix rendern und zum andern die Matrix berechnen&lt;br /&gt;
&lt;br /&gt;
==Rendern der Heightmap==&lt;br /&gt;
&lt;br /&gt;
Unsere Landschaft wird gerendert, indem wir den Quadtree rekursiv entlanggehen und immer wenn ein Endpunkt des Baums erreicht wird, wird ein kompletter oder teile eines Dreieck Fans gezeichnet. Diese Fans sind besonders gut dazu geeignet, ohne Locher und Cracks im Mesh ein Heighfield darzustellen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_setmatrix.gif]]&lt;br /&gt;
[[Bild:Tutorial_Terrain3_triangulation.gif]]  &lt;br /&gt;
&lt;br /&gt;
Das linke Bild stellt eine Beispiel Matrix dar, das rechte die dazu passende Triangulation. Ihr konnt gerne nach Stellen suchen, an denen die Moglichkeit besteht, dass dort ein Crack ist. Ihr werdet keine finden. Zuerst wird einmal davon ausgegangen, dass der Levelunterschied im Quadtree zweier benachbarter Blocke niemals mehr als 1 betragt. Diese Bedingung wird beim Berechnen der Matrix abgesichert, dazu spater mehr. Das Zentrum eines Fans, ist immer auch das Zentrum eines Quadtree Blattes. Vier Vertieces bilden die Ecken des Blocks und weitere 4 bilden jeweils die Mittelpunkte der Seiten des Blattes:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_fan.gif]]&lt;br /&gt;
 &lt;br /&gt;
Es werden also hochstens 8 Dreiecke gezeichnet. Hat eine Seite keinen benachbarten Block gleichen Levels, so wird das Vertex in der Mitte der Seite einfach ubersprungen, was zur obigen Beispiel Triangulation fuhrt.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Erzeugen der Matrix==&lt;br /&gt;
&lt;br /&gt;
LOD besagt, dass Gegenstande in groser Entfernung mit einer niedrigeren Auflosung angezeigt werden, als nahe Objekte. Daneben werden auch bei groserer Entfernung bestimmte Teile eines Meshes mit hoherer Auflosung angezeigt, deren Oberflache besonders uneben ist, wodurch die Bildqualitat stark erhoht wird.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Oberflachenfehler===&lt;br /&gt;
&lt;br /&gt;
Fehler? Fehler?!? Will ich euch jetzt verarschen, ware doch dumm Fehler zu machen... Nein, die gemeinten Fehler besagen ausschlieslich, wie verfalscht eine Stelle in der Landschaft aussehen wurde, wenn man beim Hinuntergehen des Baumes an der aktuellen Stelle aufhort und zu rendern beginnt. Je hoher dieser Wert, desto wichtiger ist es, den Baum noch tiefer hinabzuschreiten.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_dhvalues.jpg|center]]&lt;br /&gt;
Um diese '''d2''' genannten Werte fur ein Quadree Blatt zu erhalten, errechnet man zuerst die Erhebungsunterschiede an den Mitten der 4 Seiten und an den 2 Diagonalen(Achtung: das sind unterschiedliche Werte). Der '''d2''' Wert errechnet sich daraus so:&lt;br /&gt;
&lt;br /&gt;
'''d2=(1/d)*maxi=1..6|dhi|'''&lt;br /&gt;
&lt;br /&gt;
In Delphi konnte das ganze dann so aussehen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure CalcD2Value(X, Z, Size : Longint);&lt;br /&gt;
  var&lt;br /&gt;
    HSize : LongInt; //Hälfte der eigenen Seitenlänge&lt;br /&gt;
    I : LongInt;&lt;br /&gt;
    EdgeHeights : Array[1..4] of Single; //Höhe der Ecken&lt;br /&gt;
    ExpectedHeight : Single;             //Erwartete höhe zw 2 Punkten&lt;br /&gt;
    RealHeight : Single;                 //Tatsächliche Höhe&lt;br /&gt;
&lt;br /&gt;
    DHValues : Array[1..6] of Single;    //DHWerte&lt;br /&gt;
&lt;br /&gt;
  const&lt;br /&gt;
    //Ort der Ecken des Quads&lt;br /&gt;
    Edges : Array[1..4] of Array[0..1] of ShortInt = ((+1, +1),(+1, -1),(-1,-1),(-1,+1));&lt;br /&gt;
    //Jeweils die 2 Ecken, zwischen denen ein DHWert berechnet wird&lt;br /&gt;
    DHLines : Array[1..6] of Array[0..1] of Byte =&lt;br /&gt;
      ((1,2),(2,3),(3,4),(4,1),(1,3),(2,4));&lt;br /&gt;
&lt;br /&gt;
    //Positionen der DHWerte selber&lt;br /&gt;
    DHPositions : Array[1..6] of Array[0..1] of ShortInt =&lt;br /&gt;
      ((1,0),(0,-1),(-1,0),(0,1),(0,0),(0,0));&lt;br /&gt;
&lt;br /&gt;
  begin&lt;br /&gt;
    //Höhen der 4 Ecken&lt;br /&gt;
    for I := 1 to 4 do&lt;br /&gt;
      EdgeHeights[I] := GetHeightMapHeight(X + Size * Edges[i,0],&lt;br /&gt;
                          Z + Size * Edges[i,1]);&lt;br /&gt;
&lt;br /&gt;
    //DHWerte berechen&lt;br /&gt;
    for i := 1 to 6 do&lt;br /&gt;
    begin&lt;br /&gt;
      //Erwartete Höhe zwischen 2 Punkten&lt;br /&gt;
      ExpectedHeight := (EdgeHeights[DHLines[i,0]] + EdgeHeights[DHLines[i,1]])/2;&lt;br /&gt;
      //Tatsächlich vorliegende Höhe&lt;br /&gt;
      RealHeight := GetHeightMapHeight(&lt;br /&gt;
        X + DHPositions[i,0] * Size,&lt;br /&gt;
        Z + DHPositions[i,1] * Size);&lt;br /&gt;
      //DH Wert ist |absoluter Fehler|&lt;br /&gt;
      DHValues[I] := Abs(ExpectedHeight - RealHeight)&lt;br /&gt;
    end;&lt;br /&gt;
&lt;br /&gt;
    //D2Value finden und setzen&lt;br /&gt;
    QuadMatrix[X,Z].D2Value := Trunc(1/(2*Size) * Max(DHValues));&lt;br /&gt;
&lt;br /&gt;
    //D2Values für die 4 Kinder&lt;br /&gt;
    if Size &amp;gt; 1 then&lt;br /&gt;
    begin&lt;br /&gt;
      HSize := Size div 2;&lt;br /&gt;
      CalcD2Value(X + HSize, Z + HSize, HSize);&lt;br /&gt;
      CalcD2Value(X + HSize, Z - HSize, HSize);&lt;br /&gt;
      CalcD2Value(X - HSize, Z + HSize, HSize);&lt;br /&gt;
      CalcD2Value(X - HSize, Z - HSize, HSize)&lt;br /&gt;
    end&lt;br /&gt;
  end; (*CalcD2Values*)&lt;br /&gt;
...&lt;br /&gt;
  CalcD2Value((QuadTreeLength-1) div 2, (QuadTreeLength-1) div 2,&lt;br /&gt;
    (QuadTreeLength-1) div 2);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In diesem Beispiel steht '''Size''' immer fur die Halfte der Seitenlange einer Quadtreenode. Man denke hier am Besten an den Radius eines Kreises. Die '''d2''' Werte werden auf Bytegrose komprimiert, um wertvollen Speicher einzusparen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Matrix erzeugen===&lt;br /&gt;
&lt;br /&gt;
Jetzt wollen wir uns daran machen, die furs Zeichnen unbedingt notige Matrix zu erzeugen. Gehen wir einmal davon aus, dass die Matrix bereits sauber entleert ist und damit kein Node als gesetzt gilt. Wir laufen den Quadtree wieder rekursiv hinab und entscheiden an jeder Node nach folgender Formel, ob weiter unterteilt werden muss oder nicht:&lt;br /&gt;
&lt;br /&gt;
'''f=l/(d*C*max(c*d2, 1)'''&lt;br /&gt;
&lt;br /&gt;
Ist der Wert von '''f''' kleiner 1, dann wird weiter unterteilt. Es gilt: '''C''' ist eine feste Konstante. Je hoher sie ist, desto hoher ist die Landschaft insgesamt aufgelost. '''l''' ist die Entfernung des Node Mittelpunkts zur Kamera und klein '''c''' kontrolliert die Auflosung in Bereichen, die einen hohen Oberflachenfehler aufweisen.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Schweizer Kase===&lt;br /&gt;
[[Bild:Tutorial_Terrain3_kaese.jpg|center]]&lt;br /&gt;
Das bisherige Ergebnis ist doch mehr ernuchternd als erfreulich. Es sieht alles mehr nach Schweizer Kase aus. Viele Locher, aber sonst nicht viel zu bieten. In einem Spiel kann man so ganz schnell dem Spieler den Spass verderben, wir sollten also etwas dagegen unternehmen.&lt;br /&gt;
&lt;br /&gt;
Um dieses Ziel zu erreichen, mussen wir ganz einfach die '''d2''' Werte so verandern, dass Nebeneinanderliegende Blocke keinen Levelunterschied groser als 1 aufweisen (Bedingung für das Rendern der Matrix, siehe oben). Zuerst mussen also die '''d2''' Werte einmal berechnet worden sein. Nun gehen wir den Quadtree wieder soweit herunter, bis wir genau 1 level vor dem niedrigsten sind und setzen den '''d2''' Wert der Node neu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
QuadMatrix[X,Z].D2Value := Max(QuadMatrix[X,Z].D2Value, &lt;br /&gt;
                               (d2Werte der benachbarten Nodes ein Level tiefer) * K)&lt;br /&gt;
K = C / (2 * (C - 1)); C groser 2&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure DoCrackAvoid(X, Z, Size, SizeToCheck : Longint);&lt;br /&gt;
  const&lt;br /&gt;
    Neighbours : Array[0..8] of Array[0..1] of ShortInt =&lt;br /&gt;
      ((+0,+0), (+3,+1),(+3,-1),(+1,-3),(-1,-3),(-3,-1),(-3,+1),(-1,+3),(+1,+3));&lt;br /&gt;
  var&lt;br /&gt;
    HSize : LongInt; //1/4 der Seitenlänge&lt;br /&gt;
    I : LongInt;&lt;br /&gt;
    D2Values : Array[0..8] of Byte;&lt;br /&gt;
&lt;br /&gt;
  begin&lt;br /&gt;
    Assert(Size &amp;gt; 1);&lt;br /&gt;
    //Der Baum wird rekursiv abgehandlet(nicht unbedingt die&lt;br /&gt;
    //beste Idee. Wer Lust hat, darf sich gerne daran versuchen&lt;br /&gt;
    //es einmal ohne Rekursivität zu probieren!)&lt;br /&gt;
&lt;br /&gt;
    HSize := Size div 2;&lt;br /&gt;
    //Wir haben noch nicht das gewünschte Level erreicht&lt;br /&gt;
    if Size &amp;gt; SizeToCheck then&lt;br /&gt;
    begin&lt;br /&gt;
      DoCrackAvoid(X + HSize, Z + HSize, HSize,SizeToCheck);&lt;br /&gt;
      DoCrackAvoid(X + HSize, Z - HSize, HSize,SizeToCheck);&lt;br /&gt;
      DoCrackAvoid(X - HSize, Z + HSize, HSize,SizeToCheck);&lt;br /&gt;
      DoCrackAvoid(X - HSize, Z - HSize, HSize,SizeToCheck)&lt;br /&gt;
    end&lt;br /&gt;
    else&lt;br /&gt;
    begin&lt;br /&gt;
      Assert(SizeToCheck = Size);&lt;br /&gt;
      D2Values[0] := QuadMatrix[X,Z].D2Value;&lt;br /&gt;
      for i := 1 to 8 do&lt;br /&gt;
        //Nachbarnodes holen....&lt;br /&gt;
        D2Values[i] := GetNode(X + HSize * Neighbours[i][0],&lt;br /&gt;
                               Z + HSize * Neighbours[i][1]) * K;&lt;br /&gt;
&lt;br /&gt;
      QuadMatrix[X,Z].D2Value := MaxByte(D2Values)&lt;br /&gt;
    end&lt;br /&gt;
  end; (*DoCrackAvoid*)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diesen Vorgang wiederholen wir, wobei wir immer ein Level niedriger gehen, bis wir schlieslich das Level 1 erreichen. Wenn wir nun unsere Matrix berechnen, ist unsere Bedingung erfullt und wir erhalten ein Mesh ohne Locher:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_result.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain3_wireframe.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wer glaubt hier ein paar Locher finden zu konnen liegt falsch. Die Stellen die schwarz erscheinen, werden durch das OpenGl Licht nur so unglucklich getroffen, dass sie fast schwarz erscheinen. Ist euer Monitor richtig eingestellt, sollte dagegen alles passen. Siehe dazu auch: [[Farbraum]]{{excIcon}}. Die &amp;quot;Kamera&amp;quot; befindet sich übrigens links unten im Bild, dort wo ein rotes Quad sichtbar ist.&lt;br /&gt;
&lt;br /&gt;
'''Anmerkung:''' Nach Aussage von Stefan Röttger ist diese Methode um Löcher zu entfernen nicht optimal. Es genügt bei jedem Vater Knoten alle Kinder in die Berechnung einzubeziehen. Die Nachbarn müssen nicht einbezogen werden. Genaueres findet sich in diesem [http://www.delphigl.com/forum/viewtopic.php?p=48761#48761 Forumsbeitrag].&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
&lt;br /&gt;
Wie gehts weiter?&lt;br /&gt;
Um die ganze Sache nun noch ein bischen weiter zu verbessern, sollte man uberlegen, ob man die Landschaft nicht vielleicht texturiert. Hier bietet sich sicher das [[Tutorial_Terrain2|2. Highmap Tutorial]] als guter Anfang an. Auch konnte man das &amp;quot;Popping&amp;quot; unterbinden, das auftritt, wenn man sich einer Stelle nahert und plotzlich ein paar neue Dreiecke angezeigt werden. Das ganze ist bekannt unter dem Begriff Geomorphing. &lt;br /&gt;
&lt;br /&gt;
Delphic&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_terrainclod_delphi_vcl|text=Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
* {{ArchivLink|file=tut_terrainclod_exe|text=Windows-Binary zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Terrain2]]|[[Tutorial_Skyboxen]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Tutorial3]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Terrain2&amp;diff=23930</id>
		<title>Tutorial Terrain2</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Terrain2&amp;diff=23930"/>
				<updated>2009-07-23T15:10:52Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Heightmap Texturen=&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Hi, &lt;br /&gt;
&lt;br /&gt;
dies ist ein weiteres Tutorial zu Heightmaps. Ich verrate euch heute, wie man Heightmaps ein paar interessante Texturen verpasst. Der erste Teil besteht darin, eine Procedural Texture zu erstellen, die eine Kombination aus der Heightmap und einer Wahl von Bodentexturen ist, z.B. werden die höchsten Punkte der Landschaft mit Schnee bedeckt sein, niedrigere mit Stein, Gras und zum Schluss Wasser. &lt;br /&gt;
&lt;br /&gt;
Der zweite Teil besteht darin, eine Lightmap zu Rendern. Sie enthält die Lichtintensitat der einfallenden Sonne auf der Karte. &lt;br /&gt;
Damit ihr wisst, wofür die ganze Müh erst einmal ein kleiner Teaser: &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain2_result.jpg|center|framed|Besonders zu beachten: Die Landschaft wirft Schatten auf sich selbst]]&lt;br /&gt;
&lt;br /&gt;
==Der Trick der Procedural Textures==&lt;br /&gt;
&lt;br /&gt;
Wollen wir uns zuerst den Procedural Textures widmen. Die Idee: &lt;br /&gt;
&lt;br /&gt;
Wir haben eine Heightmap. Wir wollen über diese eine Textur ziehen. Je nach Hohe soll eine andere Grundtextur gewählt werden, z.B. Hohenstufe 0 Unterwassertextur. Stufe 60 Sand, Stufe 100 Gras, 170 Stein und 255 Schnee. Daneben wollen wir erreichen, dass die Texturen ineinander übergehe, indem wir immer genau zwischen zwei Stufen die Farbwerte linear interpolieren. Die Grundtexturen werden gekachelt, damit sie nicht so hoch aufgelöst werden müssen, wie die Heightmap selbst.&lt;br /&gt;
&lt;br /&gt;
Ich habe folgende Texturen verwandt:&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{| {{Prettytable_B1}}&lt;br /&gt;
|[[Bild:Tutorial_Terrain2_underwater.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Terrain2_sand.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Terrain2_grass.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Terrain2_rock.jpg]]&lt;br /&gt;
|[[Bild:Tutorial_Terrain2_snow.jpg]]&lt;br /&gt;
|-&lt;br /&gt;
|Stufe: 0 &lt;br /&gt;
|Stufe: 60 &lt;br /&gt;
|Stufe: 100 &lt;br /&gt;
|Stufe: 170 &lt;br /&gt;
|Stufe: 255 &lt;br /&gt;
|}&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Hinweis|Wenn ihr selbst Texturen erstellen wollt, zeichnet oder fotografiert wild drauf los, und lasst einen Kachel Filter in einem Bildbearbeitungsprogramm drüberlaufen. Von Hand Kacheln erzeugen geht natürlich auch, bedarf aber deutlich mehr Aufwandt.&lt;br /&gt;
&lt;br /&gt;
Bevor wir unsere Textur rendern können, müssen wir uns eine Umgebung schaffen. Wir brauchen eine geladene Heightmap und die Grundtexturen: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
type&lt;br /&gt;
  TProcTexStage = record&lt;br /&gt;
                    Image : TImage;&lt;br /&gt;
                    ScrollBox : TScrollBox;&lt;br /&gt;
                    Stage : Byte;&lt;br /&gt;
                    StageLabel : TLabel;&lt;br /&gt;
                  end;&lt;br /&gt;
  ...&lt;br /&gt;
    HeightMap : TBitMap;&lt;br /&gt;
&lt;br /&gt;
    ProceduralTex : TBitMap;&lt;br /&gt;
    ProcTexs : Array of TProcTexStage;&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Typ '''TProcTexStage''' beinhaltet je eine Grundtextur, geladen in der '''Image''' Komponente. Die jeweilige Höhenstufe ist in '''Stage''' abgelegt. Die restlichen Objekte sind nur für die GUI gedacht und haben keine weitere Bedeutung für den Algorithmus selbst. &lt;br /&gt;
&lt;br /&gt;
Die Variable '''ProcTexs''' enhalt mehrere '''TProcTexStages'''. Sie sind bereits nach Stufen sortiert, beginnend mit der kleinsten, wobei gilt: Die niedrigste Stufe ist immer 0, die Hochste immer 255 (wird spater wichtig). Die Mindestzahl der Elemente ist demnach 2. Mehr ist kein Problem, unterschiedliche '''TProcTexStage''' sollten aber niemals die selbe Stufe haben. &lt;br /&gt;
&lt;br /&gt;
Sobal diese Annahmen erfüllt sind, können wir beginnen, jedem Pixel der '''ProceduralTex''' einen neuen Farbwert zuzuweisen. Das Grundgerüst ist wie folgt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
var&lt;br /&gt;
  X,Y, HeightMapHeight : LongInt;&lt;br /&gt;
  ...&lt;br /&gt;
begin&lt;br /&gt;
  //Texturen sind bereits sortiert...&lt;br /&gt;
  if Length(ProcTexs) &amp;lt; 2 then&lt;br /&gt;
    Exit;&lt;br /&gt;
  //Größe anpassen&lt;br /&gt;
  ProceduralTex.Width := HeightMap.Width;&lt;br /&gt;
  ProceduralTex.Height := HeightMap.Height;&lt;br /&gt;
&lt;br /&gt;
  for X := 0 to HeightMap.Width - 1 do&lt;br /&gt;
    for Y := 0 to HeightMap.Height - 1 do&lt;br /&gt;
    begin&lt;br /&gt;
      HeightMapHeight :=&lt;br /&gt;
         Trunc((HeightMap.Canvas.Pixels[X,Y]/clWhite)*255);&lt;br /&gt;
      //Farbwert zuweisen&lt;br /&gt;
      ...&lt;br /&gt;
    end&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Da wir die Stufen nicht auf bestimmte Werte festgelegt haben (z.B. alle 64 Hohenwerte eine Stufe) müssen wir zunächst das Intervall finden, in welchem die aktuelle Stufe liegt. Die jeweils niedrigere Textur wird in einer Variable '''Lower''' abgelegt, die höhere in '''Upper'''. Daneben benötigen wir noch einen Satz weiterer Variablen: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
var&lt;br /&gt;
  ...&lt;br /&gt;
  I : Integer;&lt;br /&gt;
  Upper, Lower : LongInt;&lt;br /&gt;
  LevelDifference : LongInt; //Levelunterschied zw. Upper u. Lower&lt;br /&gt;
  LowerDifference : LongInt; //Abstand HeightmapHeight - Lower&lt;br /&gt;
  LowerRGB, UpperRGB : TRGB; //RGB werte von Upper Lower&lt;br /&gt;
  Prozent : Single;          //Prozent der eingesetzten Farbwerte&lt;br /&gt;
  FinalRGB : TRGB;           //End RGB Wert&lt;br /&gt;
&lt;br /&gt;
      ...&lt;br /&gt;
      HeightMapHeight := Trunc(&lt;br /&gt;
             (HeightMap.Canvas.Pixels[X,Y]/clWhite)*255);&lt;br /&gt;
      Upper := 0;&lt;br /&gt;
      Lower := 0;&lt;br /&gt;
      //Intervall suchen, das für diese Höhenstufe interessant ist&lt;br /&gt;
      // Schonmal was von binärer Suche gehört? &lt;br /&gt;
      for I := 1 to Length(ProcTexs)-1 do&lt;br /&gt;
        if HeightMapHeight &amp;lt;= ProcTexs[I].Stage then&lt;br /&gt;
        begin&lt;br /&gt;
          Upper := I;&lt;br /&gt;
          Lower := I -1;&lt;br /&gt;
          Break&lt;br /&gt;
        end;&lt;br /&gt;
      Assert(Upper &amp;lt;&amp;gt; 0);&lt;br /&gt;
      LevelDifference := ProcTexs[Upper].Stage - ProcTexs[Lower].Stage;&lt;br /&gt;
      LowerDifference := HeightMapHeight - ProcTexs[Lower].Stage;&lt;br /&gt;
      Assert(LevelDifference &amp;lt;&amp;gt; 0);&lt;br /&gt;
      Prozent := LowerDifference / LevelDifference;&lt;br /&gt;
      ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der verwendete Typ '''TRGB''' ist ein '''Array[0..2] of Byte'''. Wenn ein '''TColor''' Wert als Ausgangsmaterial dient, wird dieser mit in ein '''TRGB''' umgewandelt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure MakeRGB(Color : TColor; var RGB : TRGB);&lt;br /&gt;
  begin&lt;br /&gt;
    Move(Color, RGB[0], 3)&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit haben wir's fast geschafft. Das einzige was noch fehlt ist die lineare Interpolation zwischen den Farbwerten der '''Upper''' und '''Lower''' Textur. Dies ist aber an sich nicht weiter schwierig. Man denke an den Mathematikunterricht zurück und erinnert sich an folgende gleichung: '''y= m * x + t''', wobei '''m''' die Steigung und '''t''' der y-Achsenabschnitt ist:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
      Prozent := LowerDifference / LevelDifference;&lt;br /&gt;
&lt;br /&gt;
      MakeRGB(ProcTexs[Lower].Image.Canvas.&lt;br /&gt;
           Pixels[X mod ProcTexs[Lower].Image.Width,&lt;br /&gt;
           Y mod ProcTexs[Lower].Image.Height],LowerRGB);&lt;br /&gt;
      MakeRGB(ProcTexs[Upper].Image.Canvas.&lt;br /&gt;
           Pixels[X mod ProcTexs[Upper].Image.Width,&lt;br /&gt;
           Y mod ProcTexs[Upper].Image.Height],UpperRGB);&lt;br /&gt;
&lt;br /&gt;
      for I := 0 to 2 do&lt;br /&gt;
        FinalRGB[I] := Trunc(&lt;br /&gt;
                    (UpperRGB[I] - LowerRGB[I])*Prozent +&lt;br /&gt;
                                 LowerRGB[I]);&lt;br /&gt;
        //    y      =       (            m            )*   x    +      t&lt;br /&gt;
      ProceduralTex.Canvas.Pixels[X,Y] := RGB(FinalRGB[0],&lt;br /&gt;
                                       FinalRGB[1],&lt;br /&gt;
                                       FinalRGB[2])&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zum Einsatz kam folgende Heightmap: &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain2_heightmap.jpg|center]]&lt;br /&gt;
 &lt;br /&gt;
Jede andere funktioniert natürlich auch, wie z.B. die, aus meinem letzten Tutorial. Der Algorithmus liefert zusammen mit den Oben gezeigten Grundtexturen dieses Bild: &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain2_proctex.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
==Das Spiel von Licht und Schatten==&lt;br /&gt;
&lt;br /&gt;
Wir könnten damit jetzt unsere Welt überziehen. Was dann aber noch fehlt ist Licht und Schatten. Wir wollen Ambient Light und Diffuse Light zum Einsatz kommen lassen. Die Typische Formel zum Berechnen ist:&lt;br /&gt;
&lt;br /&gt;
'''Intensity=Ambient + Diffuse * (L • N)'''&lt;br /&gt;
&lt;br /&gt;
'''L''' ist ein Vektor zur Lichtquelle, '''N''' die Flachennormale. '''Ambient''' und '''Diffuse''' die Stärken der jeweiligen Lichttypen. Wir wollen abermals alle Punkte der Heightmap durchgehen und unser Ergebnis in '''LightMaptex''' ablegen. Wenn ein Punkt nicht im Schatten eines anderen liegt, wird sein Farbwert mithilfe obiger Formel berechnet, ansonsten bekommt der Punkt den Farbwert des Ambient Light zugewiesen. &lt;br /&gt;
&lt;br /&gt;
===Die Normal Map===&lt;br /&gt;
&lt;br /&gt;
Bevor wir loslegen, legen wir eine Normal Map an, deren Inhalt alle Normalen der Heightmap ist. Diese Komprimieren wir gleich auf Bytes, damit sie nicht Unmengen an Platz beansprucht. Leider kann man die Normalen nur schlecht für einzelne Punkte direkt berechnen, nehmen also Flächen zur Hilfe. Damit die Sache rund wird, betrachten wir aber nicht nur eine Fläche, sondern gleich alle anliegenden und berechnen daraus einen Normalendurchschnitt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
type&lt;br /&gt;
  TNormalMap = Array of Array[0..2] of ShortInt;&lt;br /&gt;
...&lt;br /&gt;
&lt;br /&gt;
  procedure CreateNormalMap(HM : TBitMap; HeightScale : Single;&lt;br /&gt;
                               var NormalMap : TNormalMap);&lt;br /&gt;
  begin&lt;br /&gt;
    ...&lt;br /&gt;
  end;&lt;br /&gt;
...&lt;br /&gt;
var&lt;br /&gt;
  NormalMap : TNormalMap;&lt;br /&gt;
  HeightMapScale : Single;&lt;br /&gt;
  NormalMap : TNormalMap;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  Sun[0] := Cos(LightRotation.Position*Pi/180);&lt;br /&gt;
  Sun[1] := (LightHeight.Max - LightHeight.Position)/100;&lt;br /&gt;
  Sun[2] := Sin(LightRotation.Position*Pi/180);&lt;br /&gt;
  HeightMapScale := HeightScaleEdit.Value;&lt;br /&gt;
&lt;br /&gt;
  LightMapTex.Width := HeightMap.Width;&lt;br /&gt;
  LightMapTex.Height := HeightMap.Height;&lt;br /&gt;
&lt;br /&gt;
  CreateNormalMap(HeightMap, HeightMapScale, NormalMap);&lt;br /&gt;
&lt;br /&gt;
  CreateLightMap(HeightMap, HeightMapScale, NormalMap, Sun, LightMapTex,&lt;br /&gt;
    AmbientLight.Position / 100, DiffuseLight.Position/100,&lt;br /&gt;
    RaytracingCheckBox.Checked)&lt;br /&gt;
end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Dies stellt erst einmal ein Grundgerust dar. Statt einer einzelnen Beschreibung der einzelnen UI Komponenten folgendes Bild: &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain2_lightedit.jpg|center]]&lt;br /&gt;
 &lt;br /&gt;
Nun also zur Funktion '''CreateNormalMap'''. Wie gesagt berechnen wir den Durchschnitt der Anliegenden Normalen. Folgendes Schaubild soll die verwendeten Flächen verdeutlichen, wobei '''v0''' das derzeit betrachtete Vertex ist, alle anderen '''vxs''' anliegende:&lt;br /&gt;
&lt;br /&gt;
            v8&lt;br /&gt;
      v7•--•--•v1&lt;br /&gt;
        |8 /|1 /|&lt;br /&gt;
        | / | / |&lt;br /&gt;
        |/ 7|/ 2|&lt;br /&gt;
      v6•-v0•--•v2&lt;br /&gt;
        |6 /|3 /|&lt;br /&gt;
        | / | / |&lt;br /&gt;
        |/ 5|/ 4|&lt;br /&gt;
      v5•--•--•v3&lt;br /&gt;
            v4&lt;br /&gt;
&lt;br /&gt;
Mit dem Vektor Kreuzprodukt werden die Normalen für die 8 Flachen berechnet, zusammengezahlt und normiert:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure CreateNormalMap(HM : TBitMap; HeightScale : Single;&lt;br /&gt;
                               var NormalMap : TNormalMap);&lt;br /&gt;
  const&lt;br /&gt;
    VertexPoss : Array[0..8] of Array[0..1] of ShortInt =&lt;br /&gt;
      ((0,0),(1,-1),(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1),(0,-1));&lt;br /&gt;
    Faces : Array[0..7] of Array[0..2] of Byte =&lt;br /&gt;
      ((0,1,8),(0,2,1),(0,4,2),(4,3,2),(0,5,4),(0,6,5),(0,8,6),(8,7,6));&lt;br /&gt;
  var&lt;br /&gt;
    X,Z : LongInt;&lt;br /&gt;
    I : LongInt;&lt;br /&gt;
&lt;br /&gt;
    Vertieces : Array[0..8] of TVertex;&lt;br /&gt;
    Normals   : Array[0..7] of TVertex;&lt;br /&gt;
  begin&lt;br /&gt;
    SetLength(NormalMap, HM.Width*HM.Height);&lt;br /&gt;
    FillChar(Vertieces[0,0], SizeOf(Vertieces), 0);&lt;br /&gt;
    for Z := 0 to HM.Height - 1 do&lt;br /&gt;
      for X := 0 to HM.Width - 1 do&lt;br /&gt;
      begin&lt;br /&gt;
        //Vertieces holen&lt;br /&gt;
        for I := 0 to 8 do&lt;br /&gt;
        begin&lt;br /&gt;
          Vertieces[I][0] := X + VertexPoss[I][0]*VertexPosMultiply;&lt;br /&gt;
          Vertieces[I][2] := Z + VertexPoss[I][1]*VertexPosMultiply;&lt;br /&gt;
          Vertieces[I][1] := HM.Canvas.Pixels[X + VertexPoss[I][0], Z +&lt;br /&gt;
                          VertexPoss[I][1]]&lt;br /&gt;
            /clWhite*255*HeightScale&lt;br /&gt;
        end;&lt;br /&gt;
        //Normalen holen&lt;br /&gt;
        for I := 0 to 7 do&lt;br /&gt;
        begin&lt;br /&gt;
          Normals[I] := VectorCrossProduct(&lt;br /&gt;
            VectorNormalize(VectorSubtract(Vertieces[Faces[I][0]],&lt;br /&gt;
               Vertieces[Faces[I][1]])),&lt;br /&gt;
            VectorNormalize(VectorSubtract(Vertieces[Faces[I][1]],&lt;br /&gt;
               Vertieces[Faces[I][2]])));&lt;br /&gt;
          Normals[I] := VectorNormalize(Normals[I])&lt;br /&gt;
        end;&lt;br /&gt;
        //Den &amp;quot;Durchschnittsvektor&amp;quot;...&lt;br /&gt;
        for I := 1 to 7 do&lt;br /&gt;
          Normals[0] := VectorAdd(Normals[0], Normals[I]);&lt;br /&gt;
        Normals[0] := VectorScale(VectorNormalize(Normals[0]),127.0);&lt;br /&gt;
        NormalMap[Z*(HM.Height) + X][0] := Trunc(Normals[0][0]);&lt;br /&gt;
        NormalMap[Z*(HM.Height) + X][1] := Trunc(Normals[0][1]);&lt;br /&gt;
        NormalMap[Z*(HM.Height) + X][2] := Trunc(Normals[0][2])&lt;br /&gt;
      end&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Es werde Licht===&lt;br /&gt;
&lt;br /&gt;
Jetzt sind wir soweit. Wir konnen jetzt mit Hilfe unserer Formel fur jeden Punkt die Beleuchtung berechnen. Wie immer: Alle Punkte durchgehen, berechnen: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure CreateLightMap(HM : TBitMap; HeightMapScale : Single;&lt;br /&gt;
    NormalMap : TNormalMap; Sun : TVertex; LightMap : TBitMap;&lt;br /&gt;
    LightAmbient, LightDiffuse : Single; Raytracing : Boolean);&lt;br /&gt;
&lt;br /&gt;
  type&lt;br /&gt;
    TRay = record&lt;br /&gt;
             Origin, Direction : TVertex&lt;br /&gt;
           end;&lt;br /&gt;
&lt;br /&gt;
  var&lt;br /&gt;
    HeightMapData : Array of Array of byte;&lt;br /&gt;
&lt;br /&gt;
    procedure PrecacheHeightmap;&lt;br /&gt;
    var&lt;br /&gt;
      X,Z : LongInt;&lt;br /&gt;
    begin&lt;br /&gt;
      //Läd die Heightmap in ein Delphi Array&lt;br /&gt;
      SetLength(HeightMapData, HM.Width);&lt;br /&gt;
      for X := 0 to Length(HeightMapData) -1 do&lt;br /&gt;
        SetLength(HeightMapData[X], HM.Height);&lt;br /&gt;
&lt;br /&gt;
      for Z := 0 to HM.Height - 1 do&lt;br /&gt;
        for X := 0 to HM.Width - 1 do&lt;br /&gt;
          HeightMapData[X,Z] := Trunc(HM.Canvas.Pixels[X,Z]/clWhite * 255)&lt;br /&gt;
    end;&lt;br /&gt;
&lt;br /&gt;
    function RayIntersected(Ray : TRay; HM : TBitMap;&lt;br /&gt;
                                HeightMapScale : Single):Boolean;&lt;br /&gt;
    begin&lt;br /&gt;
      Result := False;&lt;br /&gt;
    end;&lt;br /&gt;
&lt;br /&gt;
  var&lt;br /&gt;
    X,Z : LongInt;&lt;br /&gt;
    Ray : TRay;&lt;br /&gt;
    n : TVertex;&lt;br /&gt;
    f : Single;&lt;br /&gt;
  begin&lt;br /&gt;
    if Raytracing then PrecacheHeightmap;&lt;br /&gt;
&lt;br /&gt;
    //Wir haben paraleles Licht, also bleibt der Richtungsvektor des&lt;br /&gt;
    //Rays immer gleich&lt;br /&gt;
    Ray.Direction := VectorNormalize(Sun);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    for Z := 0 to HM.Height - 1 do&lt;br /&gt;
      for X := 0 to HM.Width - 1 do&lt;br /&gt;
      begin&lt;br /&gt;
        Ray.Origin[0] := X;&lt;br /&gt;
        Ray.Origin[1] := HM.Canvas.Pixels[X,Z]/clWhite*255*HeightMapScale;&lt;br /&gt;
        Ray.Origin[2] := Z;&lt;br /&gt;
        if RayTracing and RayIntersected(Ray, HM, HeightMapScale) then&lt;br /&gt;
          f := LightAmbient&lt;br /&gt;
        else begin&lt;br /&gt;
          //Komprimierte Normale zurückverwandeln&lt;br /&gt;
          n[0] := NormalMap[Z*(HM.Height) + X][0];&lt;br /&gt;
          n[1] := NormalMap[Z*(HM.Height) + X][1];&lt;br /&gt;
          n[2] := NormalMap[Z*(HM.Height) + X][2];&lt;br /&gt;
&lt;br /&gt;
          f := LightAmbient+LightDiffuse*(VectorDotProduct(&lt;br /&gt;
          VectorNormalize(n),VectorNormalize(Ray.Direction)));&lt;br /&gt;
          //Zuviel licht?&lt;br /&gt;
          if f &amp;gt; 1.0 then f := 1.0;&lt;br /&gt;
          if f &amp;lt; 0.0 then f := 0.0&lt;br /&gt;
        end;&lt;br /&gt;
        LightMap.Canvas.Pixels[X,Z] := RGB(Trunc(f*255),&lt;br /&gt;
                                       Trunc(f*255),&lt;br /&gt;
                                       Trunc(f*255))&lt;br /&gt;
      end&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Argh.... Wieder so ein Monster an Code! Naja, kämpfen wir uns der Reihe mach durch... In '''HeightMapData''' wird die Heightmap geladen, um schnelleren Zugriff auf sie zu haben (zur Erinnerung an das 1. Tutorial: GDI Befehle sind arsch langsam). Die entstandenen Daten werden von '''RayIntersected''' verwendet um schneller ausführbar zu sein (glaubt mir, hier ist das wirklich nötig!). '''RayIntersected''' selbst gibt bisher immer False züruck (wir werden das spater noch ändern), was bedeutet, auf den derzeit betrachteten Punkt wird kein Schatten geworfen. &lt;br /&gt;
&lt;br /&gt;
Bevor ich weitermache erläutere ich kurz das Prinzip von Ray Tracern (z.B.: [http://www.povray.org POV-Ray]). Ein Ray ist ein Strahl, der von einem bestimmten Punkt (Origin) losgeschickt, in eine bestimmte Richtung (Direction). Das Tracing, also das abgehen des Rays wird die Funktion '''RayIntersected''' für uns übernehmen. &lt;br /&gt;
&lt;br /&gt;
Die Richtung des Rays ist fur alle Punkte gleich, da die Sonne zur Erde einen so großen Abstand hat, dass Licht parallel einfällt. Wird ein Ray geschnitten, wird dem Punkt Origin der Wert des Ambient Light zugewiesen, ansonsten wird mit der vorhin vorgestellten Formel die stärke des einfallenden Lichtes berechnet. &lt;br /&gt;
&lt;br /&gt;
Dies ist noch nichts besonderes, denn OpenGL berechnet das Licht auf ähnliche Weise. Was noch fehlt sind die Schatten. Wollen wir also ein wenig über '''RayIntersected''' nachdenken...&lt;br /&gt;
&lt;br /&gt;
===Schattenspiele===&lt;br /&gt;
&lt;br /&gt;
Wir haben also den Ray. Der Einfachheit halber, gehen wir diesen immer ein Stücken weiter, schauen ob die Höhe der Heightmap gröser ist als der Ray oder nicht, solange bis wir am Ende der Karte angelangt sind. Klingt simpel? Ist es.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    function RayIntersected(Ray : TRay; HM : TBitMap;&lt;br /&gt;
                                HeightMapScale : Single):Boolean;&lt;br /&gt;
    var&lt;br /&gt;
       Position : TVertex;&lt;br /&gt;
       Vor : TVertex;&lt;br /&gt;
    begin&lt;br /&gt;
      Result := False;&lt;br /&gt;
      Position := Ray.Origin;&lt;br /&gt;
      Vor := VectorNormalize(Ray.Direction);&lt;br /&gt;
      Position := VectorAdd(Position, Vor);&lt;br /&gt;
      while (Position[0] &amp;gt; 0) and (Position[0] &amp;lt; HM.Width - 1) and&lt;br /&gt;
        (Position[2] &amp;gt; 0) and (Position[2] &amp;lt; HM.Height - 1) do&lt;br /&gt;
      begin&lt;br /&gt;
        if HeightMapData[Trunc(Position[0]), Trunc(Position[2])]*&lt;br /&gt;
          HeightMapScale &amp;gt;= Position[1] then&lt;br /&gt;
        begin&lt;br /&gt;
          Result := True;&lt;br /&gt;
          Break&lt;br /&gt;
        end;&lt;br /&gt;
        Position := VectorAdd(Position, Vor)&lt;br /&gt;
      end&lt;br /&gt;
    end;&lt;br /&gt;
    (*Achtung: In diesem Codestück ist eine kleine Performancebremse eingebaut. &lt;br /&gt;
      Wer sie findet kommt deutlich schneller an die ersehnte Textur. &lt;br /&gt;
      Es handelt sich übrigens um eine fehlende Bedingung im while. *)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das entlanglaufen des Rays ist nich unbedingt Ideal gelöst, aber es erfüllt seinen Zweck. Starten wir einmal unseren nun fertigen Lightmap Generator und betrachten das Ergebnis: &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain2_lightmap.jpg|center]]&lt;br /&gt;
 &lt;br /&gt;
Diese kann man dann mit der Procedural Texture verknupfen... Je Heller ein Punkt in der Lightmap, desto mehr wird von den Farben der Procedural Texture genommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Terrain2_combined.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
==Nachwort==&lt;br /&gt;
Aha, du hast also durchgehalten. Ich hoffe jetzt bald viele schone Landschaften mit Schatten zu sehen. Bin jetzt etwas geschafft vom vielen Tippen.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
DelphiC&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_terrain2_src_vcl‎|text=Beispiel-Quelltext}}&lt;br /&gt;
* {{ArchivLink|file=tut_terrain2_exe‎|text=Beispiel-Programm}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_Terrain1]]|[[Tutorial_Terrain3]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Terrain2]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Terrain1&amp;diff=23929</id>
		<title>Tutorial Terrain1</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Terrain1&amp;diff=23929"/>
				<updated>2009-07-23T15:10:18Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Heightmaps - Außenlandschaften mit System=&lt;br /&gt;
&lt;br /&gt;
==Vorwort==&lt;br /&gt;
&lt;br /&gt;
Hi,&lt;br /&gt;
&lt;br /&gt;
dies Tutorial wird euch in die Basics des Terrain Rendering einweisen. Ich&lt;br /&gt;
werde euch zeigen, wie man am Besten mit Heightmaps umgeht und wie man sie&lt;br /&gt;
rendert. Daneben werde ich euch auch verraten, wie man mithilfe einer&lt;br /&gt;
[[Skybox]] der Szene etwas mehr&lt;br /&gt;
Atmosphäre verleiht.&lt;br /&gt;
&lt;br /&gt;
==Vorarbeit==&lt;br /&gt;
&lt;br /&gt;
Für dieses kleine Demo habe ich die OpenGl Bibliothek 1.2 von Mike Lischke&lt;br /&gt;
verwendet (OpenGL12.pas). Dazu eine für 3DNow! optimierte&lt;br /&gt;
Geometry.pas eingebunden, die aus der GlScene Komponentensammlung stammt&lt;br /&gt;
(alle Dateien liegen den Sources bei). Zum Laden der Textur kommt&lt;br /&gt;
noch die GlAux Library zum Einsatz, was ihr besser nicht nachmacht,&lt;br /&gt;
weils schrecklich alt ist und lang nicht mehr gepflegt wurde. Als &lt;br /&gt;
moderne Alternative wäre da z.B. [[Glbitmap_loader|Glbitmap]] zu nennen. &lt;br /&gt;
Gerendert wird im OnIdle-Event der Anwendung, aber schaut bei Fragen&lt;br /&gt;
doch einfach selbst hinein.&lt;br /&gt;
&lt;br /&gt;
===Etwas Atmosphäre bitte===&lt;br /&gt;
&lt;br /&gt;
Widmen wir uns zunächst einmal dem Himmel. Wenn gerade brauchbares Wetter&lt;br /&gt;
ist, dann schaut einfach mal hoch (Solltet ihr jetzt die Decke eines Zimmers&lt;br /&gt;
erblicken, dann hop hop, raus an die Frische Luft! Wenns geht Laptop gleich &lt;br /&gt;
mitnehmen, an der frischen Luft machts gleich dreimal soviel Spaß!).&lt;br /&gt;
Nun, was seht ihr? Ich sehe blauen Himmel, Wolken,... Nix unbekanntes&lt;br /&gt;
jedenfalls. Das wollen wir doch gleich mal in OpenGl nachbauen... Wir&lt;br /&gt;
nehmen einen Würfel (die schon angekündigte [[Skybox]]), &lt;br /&gt;
den wir von innen anschauen und bekleben den mithübschen Bildchen, &lt;br /&gt;
die unseren Himmel darstellen.&lt;br /&gt;
&lt;br /&gt;
Zum erzeugen entsprechender Bilder können wir uns einer Kamera oder einiger&lt;br /&gt;
kleiner Softwaretools bedienen. Ich mache letzteres und verweise mal &lt;br /&gt;
auf die Programme Terragenund Bryce. Was&lt;br /&gt;
wir brauchen sind sechs Bilder. Eines von oben, eines von unten und je eines&lt;br /&gt;
für die 4 Himmelsrichtungen. Macht zusammen, ganz nach Adam Riese, 6. &lt;br /&gt;
Ich habe mir die Arbeit bereits gemacht, ihr müsst euch also nicht abrackern und&lt;br /&gt;
könnt für erste Gehversuche meine Bilder nehmen,. An der Texturauflösung &lt;br /&gt;
solltet ihr nicht zu sehr sparen, immerhin ist die [[Skybox]] statisch und man&lt;br /&gt;
hat sie doch recht häufig vor der Nase. Also ruhig klotzen statt kleckern, damits&lt;br /&gt;
keine klötzchen gibt. &lt;br /&gt;
Ich habe ürsprünglich eine Auflösung von 512x512 gewählt, wobei da ruhig mit&lt;br /&gt;
der Zeit gegangen werden darf und mit jeder Grafikkartengeneration ist schließlich&lt;br /&gt;
mehr Platz im Speicher. Trotzdem kann der Einsatz von [[Textur#Kompressionen|Texturkompression]]&lt;br /&gt;
nicht schaden.&lt;br /&gt;
&lt;br /&gt;
Auf dem Einkaufszettelchen steht also: &lt;br /&gt;
* ein unbelichteter Würfel.&lt;br /&gt;
* Sechs geladene [[Textur|Texturen]]. &lt;br /&gt;
&lt;br /&gt;
Um das Verständnis meines Codes ein bischen zu erhöhen, gibts ein wenig&lt;br /&gt;
von dem Framework, in das wir unsere [[Skybox]] einpflegen wollen&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
SkyBoxTexturen : Array[0..5] of TGlUInt;&lt;br /&gt;
...&lt;br /&gt;
procedure TSkyBoxForm.ApplicationEventsIdle(Sender: TObject;&lt;br /&gt;
  var Done: Boolean);&lt;br /&gt;
&lt;br /&gt;
  procedure PaintSkyBox;&lt;br /&gt;
  begin&lt;br /&gt;
    ...&lt;br /&gt;
  end; (*PaintSkyBox*)&lt;br /&gt;
&lt;br /&gt;
var&lt;br /&gt;
  Error : LongInt;&lt;br /&gt;
begin&lt;br /&gt;
  Done := True;&lt;br /&gt;
  if not OpenGLInitialized then Exit;&lt;br /&gt;
  Done := False;&lt;br /&gt;
  glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
  glRotatef(XRotation, 1, 0,0);&lt;br /&gt;
  glRotatef(YRotation, 0, 1,0);&lt;br /&gt;
  PaintSkyBox;&lt;br /&gt;
  //Error Handler&lt;br /&gt;
  Error := glgetError;&lt;br /&gt;
  if Error &amp;lt;&amp;gt; GL_NO_ERROR then&lt;br /&gt;
  begin&lt;br /&gt;
    MessageBeep(65535);&lt;br /&gt;
    Caption := gluErrorString(Error)&lt;br /&gt;
  end;&lt;br /&gt;
  //FrameCounter&lt;br /&gt;
  Inc(Frames);&lt;br /&gt;
  if GetTickCount - StartTick &amp;gt;=1000 then&lt;br /&gt;
  begin&lt;br /&gt;
    Caption := Format('Sky Box Demo FPS: %f',&lt;br /&gt;
	[Frames/(GetTickCount - StartTick)*1000]);&lt;br /&gt;
    Frames := 0;&lt;br /&gt;
    StartTick := GetTickCount&lt;br /&gt;
  end;&lt;br /&gt;
  SwapBuffers(Canvas.Handle)&lt;br /&gt;
end; (*ApplicationEventsIdle*)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn OpenGL noch nicht initialisiert wurde, wird&lt;br /&gt;
abgebrochen. Ansonsten werden die [[glClear|Puffer geleert]] und die [[glLoadIdentity|Einheitsmatrix]]&lt;br /&gt;
geladen, die [[Tutorial_Kamera1|Kamera]] gedreht, die Skybox gemalt, auf Fehler geprüft und&lt;br /&gt;
die Leistung gemessen.&lt;br /&gt;
&lt;br /&gt;
Und wie zeichnen wir jetzt die [[Skybox]]? Zuerst sollten wir festlegen, wie&lt;br /&gt;
die [[Textur|Texturen]] in unserem Array abgelegt werden. Und weil ich hier&lt;br /&gt;
der Capo bin, entscheide ich unumstürzlich: Norden, Osten, Süden, &lt;br /&gt;
Westen, Oben und Unten. Mit diesen&lt;br /&gt;
[[Textur|Texturen]] wird ein Würfel der Kantenlänge 4 bemalt. &lt;br /&gt;
Eine Länge von 2 wäre bescheiden, da in der Demo die nahe Clipping Plane &lt;br /&gt;
eine Entfernung von 1 zum Betrachter hat und mir ist es im echten Leben noch&lt;br /&gt;
nie passiert, dass der Himmel abgeschnitten erscheint. Warum also sollte ich das&lt;br /&gt;
dann in einem OpenGl_Programm provozieren? Zum Zeichnen &lt;br /&gt;
definieren wir uns ein Array, welches die 4 Vertices jeder Wand des Würfels&lt;br /&gt;
beschreibt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure PaintSkyBox;&lt;br /&gt;
  const&lt;br /&gt;
    QuadPosition : Array[0..5] of Array[0..3] of Array[0..2] of Single =&lt;br /&gt;
      (((2.005,2.005,-1.995),(2.005,-2.005,-1.995),(-2.005,-2.005,-1.995),&lt;br /&gt;
          (-2.005,2.005,-1.995)),     //Nordseite&lt;br /&gt;
       ((1.995,2.005,2),(1.995,-2.005,2),(1.995,-2.005,-2),&lt;br /&gt;
          (1.995,2.005,-2)),         //Ostseite&lt;br /&gt;
       ((-2.005,2.005,1.995),(-2.005,-2.005, 1.995),(2.005,-2.005,1.995),&lt;br /&gt;
          (2.005,2.005,1.995)),          //Südseite&lt;br /&gt;
       ((-1.995,2.005,-2),(-1.995,-2.005,-2),(-1.995,-2.005,2),&lt;br /&gt;
          (-1.995,2.005,2)),      //Westseite&lt;br /&gt;
       ((-2,2,-2),(-2,2,2),(2,2,2), (2,2,-2)), //Oberseite&lt;br /&gt;
       ((2,-2,-2),(2,-2,2),(-2,-2,2),(-2,-2,-2))); //Unterseite&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was erzählt jetzt der für einen Mist? Das ist kein anständiger Würfel, der kann&lt;br /&gt;
doch wohl nicht die Ecken alle so unsystematisch wählen. Oder doch? Schau mer&lt;br /&gt;
nochmal genauer hin:&lt;br /&gt;
Die etwas abgearteten Werte sind alle nahe an 2. Sie sind nötig,&lt;br /&gt;
da OpenGL sich ein klein wenig &amp;quot;verrechnet&amp;quot;, was bei genauen Werten Streifen erzeugen&lt;br /&gt;
kann. Um dies zu umgehen, werden die vier Himmelrichtungen etwas&lt;br /&gt;
näher an den Betrachter gezogen und gleichzeitig etwas gestreckt. Jetzt&lt;br /&gt;
noch Texturkoordinaten pro Vertex und einige andere Variablen&lt;br /&gt;
definieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
   TexturePos : Array[0..3] of Array[0..1] of Single = ((1,1),(1,0),(0, 0),(0, 1));&lt;br /&gt;
  var&lt;br /&gt;
    Side, Vertex : Integer;&lt;br /&gt;
  begin&lt;br /&gt;
    ...&lt;br /&gt;
  end; (*PaintSkyBox*)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und jetzt hat unsere Arraysammelwut doch noch etwas Gutes: Das Zeichnen&lt;br /&gt;
geht in einer for-Schleife ganz einfach von der Hand.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glBegin(GL_QUADS);&lt;br /&gt;
    for Side := 0 to 5 do&lt;br /&gt;
    begin&lt;br /&gt;
      //Textur aktivieren&lt;br /&gt;
      glBindTexture(GL_TEXTURE_2D, SkyBoxTexturen[Side]);&lt;br /&gt;
      //Ecken und Texturkoordinaten übergeben&lt;br /&gt;
      for Vertex := 3 downto 0 do&lt;br /&gt;
      begin&lt;br /&gt;
        glTexCoord2fv(@TexturePos[Vertex][0]);&lt;br /&gt;
        glVertex3fv(@QuadPosition[Side][Vertex][0])&lt;br /&gt;
      end;&lt;br /&gt;
    end&lt;br /&gt;
    glEnd()&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und voilà. Schon fertig&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Heightmaps-Aussenlandschaften_mit_System_skyboxdemo.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Das System der Heightmaps==&lt;br /&gt;
&lt;br /&gt;
Das ist jetzt alles schön und toll, aber durch eine 3D-Landschaft kann man&lt;br /&gt;
wandeln. In Unserer Skybox dürfen wir uns nur drehen, wie langweilig. Darum&lt;br /&gt;
wollen wir uns um eine etwas &amp;quot;tiefergehende&amp;quot;, weniger flache Landschaft bemühen. &lt;br /&gt;
&lt;br /&gt;
Heightmaps sind Graustufenkarten einer Landschaft, topologische Karten sozusagen. &lt;br /&gt;
Je weißer ein Pixel ist, desto höher ist der Punkt in der Landschaft. Die Punkte&lt;br /&gt;
wollen wir mit Dreiecken verbinden, die wir schließlich zeichnen wollen.&lt;br /&gt;
&lt;br /&gt;
===Die Sache mit dem Bitmap===&lt;br /&gt;
&lt;br /&gt;
Also her mit so einer Karte! Die könnten wir mit einem Generator wie&lt;br /&gt;
[[Perlin Noise]] erzeugen oder, für die ganz wilden, mit einem &lt;br /&gt;
Bildbearbeitungsprogramm selbst zeichnen.&lt;br /&gt;
Ich packe dagegen eine Heightmap einer echten Landschaft aus, welches ich irgendwo&lt;br /&gt;
im Netz aufgetrieben habe:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Heightmaps-Aussenlandschaften_mit_System_YU14H.jpg]]&lt;br /&gt;
&lt;br /&gt;
Da das Auslesen der Pixeldaten direkt aus einem Bitmap mithilfe eines&lt;br /&gt;
TBitmap eine wirklich sehr,&lt;br /&gt;
sehr langsame Angelegenheit ist, sollten wir die Daten zuerst in einem&lt;br /&gt;
wesentlich schnelleren Delphi Array zwischenspeichern. Die Größe des Arrays&lt;br /&gt;
wählen wir (86+1)x(86+1), ein Viertel der Größe des Bitmaps. Das sollte uns&lt;br /&gt;
eigentlich genügen, allein schon, da höhere Auflösungen mehr Rechenzeit&lt;br /&gt;
beanspruchen - hey, das Tutorial ist schon ein wenig älter! &lt;br /&gt;
Wir sollten auch überlegen, auf welche Größe wir unsere Karte&lt;br /&gt;
strecken wollen (eigentlich ist das nicht nötig, will man aber die Auflösung&lt;br /&gt;
der Umgebung später erhöhen, ohne dabei die Größe der Map zu verändern, &lt;br /&gt;
ist das sinnvoll). Fügen wir also unserem&lt;br /&gt;
Code folgende Zeilen hinzu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  MapSize = 1024;&lt;br /&gt;
  MapResolution = 86;&lt;br /&gt;
&lt;br /&gt;
type&lt;br /&gt;
  TMapDaten = Array[0..MapResolution, 0..MapResolution] of Byte;&lt;br /&gt;
&lt;br /&gt;
  TSkyBoxForm = class(TForm)&lt;br /&gt;
  ...&lt;br /&gt;
  private&lt;br /&gt;
  ...&lt;br /&gt;
    MapDaten : TMapDaten;&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Bevor wir anfangen können zu rendern, müssen wir die Daten aus dem Bitmap&lt;br /&gt;
auch noch laden. Ein guter Zeitpunkt dafür wäre im OnShow-Ereignis, in dem&lt;br /&gt;
bereits OpenGL initialisiert wird. Fügen wir dort also eine neue Prozedur&lt;br /&gt;
ein, die ein Bitmap öffnet und die für uns interessanten Daten in den&lt;br /&gt;
MapDaten ablegt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure LoadHeightMap;&lt;br /&gt;
  var&lt;br /&gt;
    Bmp : TBitMap;&lt;br /&gt;
    X,Z : LongInt;&lt;br /&gt;
  begin&lt;br /&gt;
    Bmp := TBitMap.Create;&lt;br /&gt;
    try&lt;br /&gt;
      Bmp.LoadFromFile('YU14H.bmp');&lt;br /&gt;
      //Bitmap in MapDaten laden...&lt;br /&gt;
      for X := 0 to MapResolution do&lt;br /&gt;
        for Z := 0 to MapResolution do&lt;br /&gt;
          MapDaten[X,Z] := Trunc(Bmp.Canvas.Pixels&lt;br /&gt;
                             [Trunc(X/MapResolution*Bmp.Width),&lt;br /&gt;
                             Trunc(Z/MapResolution*Bmp.Height)]&lt;br /&gt;
                             / clWhite * 255)&lt;br /&gt;
    except&lt;br /&gt;
      MessageDlg('Fehler beim laden der Heightmap', mtError, [mbOk], 0)&lt;br /&gt;
    end;&lt;br /&gt;
    Bmp.Free&lt;br /&gt;
  end; (*LoadHeightMap*)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Benutzt man die Scanline Funktion von TBitmap, ein bischen &lt;br /&gt;
Pointerarithmetik und ein fest vorgegebenes Pixelformat im Bitmap, &lt;br /&gt;
dann kann man das noch billiger haben.&lt;br /&gt;
&lt;br /&gt;
Ich denke, das meiste erklärt sich bereits von selbst. Die Zeile&lt;br /&gt;
MapDaten[X,Z] := ... bedarf möglicherweise etwas genaueren Erläuterungen. Da&lt;br /&gt;
jeder Eintrag in MapDaten genau ein Byte groß ist, dürfen die eingesetzten&lt;br /&gt;
Werte nur im Bereich 0 bis 255 liegen. Wenn wir uns aber die Farbe eines&lt;br /&gt;
Pixels aus dem Bitmap holen, sind in ihm Werte für Blau, Rot und Grün&lt;br /&gt;
enthalten (Für jede Farbe wird 1 Byte verwendet. Das sind dann 3 Byte, nicht&lt;br /&gt;
1). Durch Teilen durch clWhite erhalten wir den Weißheitsgrad in Prozent.&lt;br /&gt;
Multiplizieren wir den erhaltenen Wert mit 255, landen wir im gewünschten&lt;br /&gt;
Bereich zwischen 0 und 255. Da der Wert jetzt aber noch ein Single ist, wir&lt;br /&gt;
aber ein Byte brauchen, schneiden wir den nichtganzzahligen Anteil einfach ab. &lt;br /&gt;
Beim Zugriff auf das Pixel machen wirs wieder genauso. Da hat sichs dann wieder&lt;br /&gt;
gerächt, daß MapDaten eine andere Auflösung hat, als das Bitmap. Das merken&lt;br /&gt;
wir uns dann gleich mal für später geschriebene Heightmap-Renderer, gell?&lt;br /&gt;
&lt;br /&gt;
===Rendern der Heightmap===&lt;br /&gt;
&lt;br /&gt;
Ach ja, gezeichnet werden will der Kram ja jetzt auch noch. Wie war das?&lt;br /&gt;
Dreiecke wollten wir nehmen? Die Höhen können wir ja jetzt aus MapDaten&lt;br /&gt;
nehmen, sonst hätte sich der Aufwandt da oben mal echt nicht gelohnt.  &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Heightmaps-Aussenlandschaften_mit_System_triangle-grid.gif]]&lt;br /&gt;
&lt;br /&gt;
Grid abgehen, Dreiecke zeichnen, nächster Gridpunkt..., danach siehts&lt;br /&gt;
jedenfalls aus.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure PaintHeightMap;&lt;br /&gt;
  const&lt;br /&gt;
    VertPos : Array[0..3] of Array[0..1] of Byte =&lt;br /&gt;
      ((0,0),(0,1),(1,1),(1,0));&lt;br /&gt;
  var&lt;br /&gt;
    X,Z,I : LongInt;&lt;br /&gt;
    Vertieces : Array[0..3] of TVertex;&lt;br /&gt;
&lt;br /&gt;
    procedure PaintTriangle(V1, V2, V3 : Integer);&lt;br /&gt;
    var&lt;br /&gt;
      Normale : TVertex;&lt;br /&gt;
    begin&lt;br /&gt;
      Inc(Triangles);&lt;br /&gt;
      //Flächennormale berechnen&lt;br /&gt;
      Normale := VectorCrossProduct(&lt;br /&gt;
	  			 VectorSubtract(Vertieces[V1], Vertieces[V2]),&lt;br /&gt;
                 VectorSubtract(Vertieces[V2], Vertieces[V3]));&lt;br /&gt;
      NormalizeVector(Normale);&lt;br /&gt;
      //Dreieck zeichnen&lt;br /&gt;
      glNormal3fv(@Normale[0]);&lt;br /&gt;
      glBegin(GL_TRIANGLES);&lt;br /&gt;
        glVertex3fv(@Vertieces[V1][0]);&lt;br /&gt;
        glVertex3fv(@Vertieces[V2][0]);&lt;br /&gt;
        glVertex3fv(@Vertieces[V3][0]);&lt;br /&gt;
      glEnd()&lt;br /&gt;
    end; (*PaintTriangle*)&lt;br /&gt;
&lt;br /&gt;
  begin&lt;br /&gt;
    for X := 0 to MapResolution - 1 do&lt;br /&gt;
      for Z := 0 to MapResolution - 1 do&lt;br /&gt;
      begin&lt;br /&gt;
        //Alle Vertieces erzeugen&lt;br /&gt;
        for I := 0 to 3 do&lt;br /&gt;
        begin&lt;br /&gt;
          Vertieces[I][0] := (X + VertPos[I][0])/MapResolution*MapSize;&lt;br /&gt;
          Vertieces[I][2] := (Z + VertPos[I][1])/MapResolution*MapSize;&lt;br /&gt;
          Vertieces[I][1] := MapDaten[X + VertPos[I][0],Z + VertPos[I][1]]&lt;br /&gt;
        end;&lt;br /&gt;
        PaintTriangle(0,1,3);&lt;br /&gt;
        PaintTriangle(1,2,3)&lt;br /&gt;
      end&lt;br /&gt;
  end; (*PaintHeightMap*)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Was passiert genau? Die Gridpunkte werden der Reihe nach&lt;br /&gt;
abgegangen. An jedem werden die Orte der vier anliegenden Vertices berechnet&lt;br /&gt;
und schließlich mit PaintTriangle zwei Dreiecke gezeichnet, welches zuerst die&lt;br /&gt;
Flächennormale fürs [[Tutorial_Lektion_8|Licht]] berechnet und dann die Koordinaten an&lt;br /&gt;
OpenGL weiterreicht. Und nicht vergessen, die [[Skybox]] verträgt das Licht nicht ganz&lt;br /&gt;
so gut, weil deren Licht ist ja bereits durch die Texturen bestimmt.&lt;br /&gt;
Was wir noch bedenken müssen ist, daß nach dem Aufruf von PaintSkyBox der [[Tiefenpuffer]] geleert&lt;br /&gt;
werden muss. Alternativ könnten wir vor dem Zeichnen der [[Skybox]] auch mit [[glDepthMask]] das Schreiben&lt;br /&gt;
in den Tiefenpuffer unterbinden und danach wieder anschalten.&lt;br /&gt;
&lt;br /&gt;
Der Lohn der Müh::&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Heightmaps-Aussenlandschaften_mit_System_ergebnis.jpg]]&lt;br /&gt;
&lt;br /&gt;
==Workshop==&lt;br /&gt;
&lt;br /&gt;
Um euer Hirn noch ein wenig zu belasten, habe ich noch eine Idee zur Erweiterung des kleinen Programms:&lt;br /&gt;
Die Landschaft kann mit einer Textur überzogen werden, dann ist sie nicht ganz so langweilig&lt;br /&gt;
grau. Details? [[Tutorial_Terrain2|Hier]]!&lt;br /&gt;
&lt;br /&gt;
Und jetzt? Kann ich mich nur noch verabschieden...&lt;br /&gt;
Euer&lt;br /&gt;
&lt;br /&gt;
Delphic&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_terrain1_src_vcl|text=Beispiel-Quelltext (Delphi)}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|-|[[Tutorial_Terrain2]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Terrain1]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23928</id>
		<title>Tutorial Nachsitzen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Nachsitzen&amp;diff=23928"/>
				<updated>2009-07-23T15:09:55Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Vorwort==&lt;br /&gt;
Immer wieder muss ich feststellen, dass viele, die (mit OpenGl) 3D Anwendungen schreiben, nichts mit der Mathematik dahinter anfangen können. Um das Ein oder Andere zu verstehen oder sich selbst überlegen zu können, ist dieses Wissen aber unabdingbar. Ich möchte mit diesem Artikel helfen, diesen Zustand zu beenden und entsprechends Wissen unter euch verbreiten. Dies und &lt;br /&gt;
das werded ihr aus der Schule kennen, wenn ihr also etwas überspringen wollt, orientiert euch an den Überschriften.&lt;br /&gt;
&lt;br /&gt;
==Trigonometrie am rechtwinkligen Dreieck==&lt;br /&gt;
Man stelle sich vor, man hat einen Kreis, mit Radius 1. Der Mittelpunkt des Kreises befindet sich auf dem Koordinatensystem Ursprung. An der X-Achse ist ein Winkel ß angetragen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_einheitskreis.gif]]&lt;br /&gt;
&lt;br /&gt;
An der x-Achse bildet sich dann ein rechter Winkel (wichtig für normale Trigonometrie). Die diesem Winkel gegenüberliegende Seite(r) nennt man Hypotenuse. Die am Winkel ß anliegende Seite(x) ist die Ankathete. Die dem Winkel gegenüberliegende Seite(y) heißt Gegenkathete. Man definiert folgende Funktionen:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = Gegenkathete / Hypotenuse&lt;br /&gt;
cos(ß) = Ankathete / Hypotenuse&lt;br /&gt;
tan(ß) = Gegenkathete / Ankathete&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Im Einheitskreis(und nur dort) gilt:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(ß) = y&lt;br /&gt;
cos(ß) = x&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
da die Länge der Hypotenuse 1 ist(Kreisradius).&lt;br /&gt;
&lt;br /&gt;
Die Umkehrfunktionen dazu sind (in Pascal):&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
ß = arcsin(sin(ß))&lt;br /&gt;
ß = arccos(cos(ß))&lt;br /&gt;
ß = arctan(tan(ß))&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
für ß im Bereich 0° - 90°. In den anderen Quadranten des Koordinatensystems, sind die Umkehrfunktionen nicht für alle Winkel eindeutig zurückzurechnen, hier muss man also ein wenig aufpassen, z.B. gibt arcsin(sin(ß)) im Bereich 90°-180° den Winkel 180° - ß aus. Im übrigen ist darauf zu achten, dass die FPU im Bogen- und nicht im Gradmaß rechnet. Umgerechnet werden kann wie folgt:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Lineare_Algebra_deg2rad.png]]&lt;br /&gt;
&lt;br /&gt;
Für den Umgang mit Sinus und Cosinus gibt es noch ein paar spezielle Formeln, die einem Arbeit abnehmen können:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
sin(-ß) = - sin(ß)&lt;br /&gt;
cos(-ß) = cos(ß)&lt;br /&gt;
&lt;br /&gt;
sin(90° - ß) = cos (ß)&lt;br /&gt;
cos(90° - ß) = sin (ß)&lt;br /&gt;
&lt;br /&gt;
sin²(ß) + cos²(ß) = 1&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Bei Bedarf stehen weitere in jeder brauchbaren Formelsammlung, aber meist kommt man mit diesen aus.&lt;br /&gt;
&lt;br /&gt;
Wozu das? Im Kapitel über [[Matrix|Matrizen]] werden wir sehen, dass sich die drei genannten trigononmetrischen Funktionen dazu nutzen lassen, das Koordinatensystem zu drehen; außerdem kann man mithilfe der genannten Formeln sin(ß) = y und cos(ß) = x ganz einfach Kreise zeichnen. Wenn man sich dann überlegt, daß [[Kugel|Kugeln]] im Prinzip nichts anderes sind, als Kreise, die entlang der Z-Achse orthogonal (rechtwinklig zur z-Achse) gezogen werden und die Aussenpunkte dieser Kreise (als Radius gezogen auf der x/y-Ebene), bei entfernter Betrachtung, selbst wieder einen Kreis (hier blau gezeichnet) beschreiben... &lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_KreisKugel.png]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch viele weitere Anwendungsmöglichkeiten, gerade die Umkehrfunktionen. So kann man mit Hilfe von Trigonometrie berechnen, um wieviel Grad ein Objekt weiter gedreht werden muss, um in eine bestimmte Richtung zu zeigen. Dreiecke sind generell auch Verdächtige beim Einsatz von Trigonometrie.&lt;br /&gt;
&lt;br /&gt;
==Die Welt der Matrizen==&lt;br /&gt;
Matrizen gelten als das Handwerkszeugs eines 3D Programmierers. Sie sind, wenn man sie einmal verstanden hat, ein mächtiges Hilfsmittel, das man irgendwann nicht mehr missen mag und kann! Vorher sollten wir aber noch einmal Vertieces in OpenGl (bei D3D läuft es im Prinzip genauso) betrachten und uns erst dann auf Matrizen stürzen.&lt;br /&gt;
&lt;br /&gt;
===Vertices und ihr Ursprung===&lt;br /&gt;
&lt;br /&gt;
Ein Vertex beschreibt einen Punkt im 3D Raum. Man könnte nun annehmen, dass ein Vertex durch 3 Koordinaten x,y,z beschrieben wird. Falsch gedacht, denn die meisten 3D APIs verwenden '''4-Dimensionale''' Vertices(x/y/z/w)?!?&lt;br /&gt;
&lt;br /&gt;
Ich denke, zu den 3 ersten Koordinaten muss ich nichts weiter sagen, zur w-Koordinate hingegen schon: w ist normalerweise immer 1.0. Mit glVertex4 kann bei Bedarf auch ein anderer Wert zugewiesen werden. Ist w ungleich Null, so wird ein Vertex als folgender 3-Dimensionaler Punkt interpretiert: (x/w, y/w, z/w). Im Normalfall sollte der Wert für w aber auf 1.0 belassen werden, es sei denn man hat eine interessante Idee, die sich mit einem w ungleich 1.0 besonders schön realisieren lässt. Wen die w-Koordinate interessiert, sollte in der OpenGl Spezifikation unter Coordinate Transformations nachschauen.&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel für die Effekt beim Einsatz von w Koordinaten: Beim ersten Dreieck ist im oberen Punkt w = 1.0, im 2. ist w = 0.5:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_wcoord.jpg]]&lt;br /&gt;
&lt;br /&gt;
===Einstieg in Matrizen===&lt;br /&gt;
Beginnen wir am Anfang mit einer allgemeinen Definition einer Matrix:&lt;br /&gt;
&lt;br /&gt;
'''Definition''':Eine m x n Matrix ist eine Tabelle aus Werten mit n Spalten und m Zeilen.&lt;br /&gt;
&lt;br /&gt;
Die in Direct3D und OpenGl Verwendung findenen Matrizen sind generell 4x4 Matrizen, mit Singles als Elemente:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4.png]]&lt;br /&gt;
&lt;br /&gt;
===Anwendung der Matrix auf einen Vektor===&lt;br /&gt;
&lt;br /&gt;
Hat man nun ein 3-Dimensionales Vertex (w=1.0) und möchte diesen durch die Matrix schicken, so rechnet man:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_Matrix4x4MulVec.png]]&lt;br /&gt;
&lt;br /&gt;
Bzw:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
          {Koeffizienten aus der ersten Zeile der Matrix}&lt;br /&gt;
y_neu := x*a[2,1] + y*a[2,2] + z*a[2,3] + w*a[2,4]&lt;br /&gt;
          {Koeffizienten aus der zweiten Zeile der Matrix}&lt;br /&gt;
z_neu := x*a[3,1] + y*a[3,2] + z*a[3,3] + w*a[3,4]&lt;br /&gt;
          {Koeffizienten aus der dritten Zeile der Matrix}&lt;br /&gt;
w_neu := x*a[4,1] + y*a[4,2] + z*a[4,3] + w*a[4,4]&lt;br /&gt;
          {Koeffizienten aus der letzten Zeile der Matrix}&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wer nun ein Wenig darüber nachdenkt, kommt auf ein Ergebnis:&lt;br /&gt;
:'''Die Spalten sind die Bilder der Einheitsvektoren'''&lt;br /&gt;
Die Bedeutung dürfte noch nicht klar sein, aber das kommt bald.&lt;br /&gt;
&lt;br /&gt;
Ist (wie fast immer) w=1, dann beschreibt die letzte Spalte der Matrix eine Verscheibung der Punkte, denn in der obigen Gleichung steht dann&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := ... + a[1,4]&lt;br /&gt;
y_neu := ... + a[2,4]&lt;br /&gt;
z_neu := ... + a[3,4]&lt;br /&gt;
w_neu := ... + a[4,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Es wird dadurch die letzte Spalte auf das Vertex aufaddiert. Für alle hier genannten Matrixoperatoren gilt außerdem, dass a[4,1] = a[4,2] = a[4,3] = 0. Und für a[4,4] und w_neu:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
w_neu = a[4,4] = 1.&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Klar ist also, dass die w-Koordinate unverändert bleibt - nur Projektionsmatrizen halten sich nicht an diese Regel, aber da liegt genau deren Trick.&lt;br /&gt;
&lt;br /&gt;
===Die Identitätsmatrix, oder der Ursprung von glLoadIdentity===&lt;br /&gt;
&lt;br /&gt;
Eine der wichtigsten Matrizen ist die, die nichts macht. Also ein Vertex dorthin Projeziert, wo es sich bereits am Anfang befand:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
Matrix * V = V&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Schauen wir zurück, wie eine Matrix auf ein Vertex angewendet wird:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*a[1,1] + y*a[1,2] + z*a[1,3] + w*a[1,4]&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Unser Ziel ist, dass x_neu gleich x ist. Das lässt sich immer erreichen, indem wir den Koeffizienten a[1,1] = 1.0 setzen und die restichen = 0. Dann steht da nämlich:&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x_neu := x*1 + y*0 + z*0 + w*0 { = x }&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
Die gleiche Überlegung kann man auch für die Anderen 3 Elemente y,z und w machen. Jede dieser Überlegungen ergibt eine Zeile der Identitätsmatrix. Das Ergebnis:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_IdentityMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ausgehend von dieser Matrix kann man sich jetzt weitere Matrizen überlegen:&lt;br /&gt;
&lt;br /&gt;
===Welten verschieben===&lt;br /&gt;
&lt;br /&gt;
Überlebenswichtig in 3D Anwendungen dürften die Translationsmatrizen sein, die ein Vertex verschieben - aber das haben wir ja schon ein paar Zeilen weiter oben geklärt, wie man das durch w=1 und der letzten Spalte der Matrix anstellt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_MoveMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
===Um den Ursprung drehen===&lt;br /&gt;
&lt;br /&gt;
Ein Porsche, den man vor zurück, links, rechts hoch und runterbewegen kann, ist schon was tolles. Deutlich mehr Klasse bekommt er, wenn man ihn auch noch aus verschiedenen Blickwinkeln anschauen und frei drehen kann. Den meisten dürfte damit schon klar sein, worauf ich hinaus will: Drehungen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotz.gif]]&lt;br /&gt;
| &lt;br /&gt;
====Drehen um die Z-Achse====&lt;br /&gt;
&lt;br /&gt;
Rotationen zusammenstöpseln geht einfach. Erinnern wir uns an den Satz: &amp;quot;Die Spalten sind die Bilder der Einheitsvektoren&amp;quot;. Mit dieser Hilfe können wir uns jetzt selbst überlegen, wie eine Rotationsmatrix, die um die Z-Achse mit dem Winkel ß dreht, auszusehen hat.&lt;br /&gt;
&lt;br /&gt;
Gehen wir die Einheitsvektoren der Reihe nach ab:&lt;br /&gt;
&lt;br /&gt;
Der Z-Achsen Einheitsvektor(0.0, 0.0, 1.0) bleibt bei unserer 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? So sollte es zumindest sein, ansonsten habt ihr ein anatomisches Problem ;-). 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.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;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x := cos(ß)&lt;br /&gt;
y := sin(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
womit wir den Inhalt der ersten Spalte der Matrix kennen: (cos(ß); sin(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Das lässt sich jetzt genauso auf den Y-Achsen Einheitsvektor(0.0, 1.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;pascal&amp;quot;&amp;gt;&lt;br /&gt;
x = -sin(ß)&lt;br /&gt;
y = cos(ß)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
So ergibt sich für die zweite Spalte: (-sin(ß); cos(ß); 0; 0)&lt;br /&gt;
&lt;br /&gt;
Und schließlich können wir eine Matrix für die Drehung um die Z-Achse mit dem Winkel ß beschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotZMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_roty.gif]] &lt;br /&gt;
|&lt;br /&gt;
&lt;br /&gt;
====Drehen um die Y-Achse====&lt;br /&gt;
&lt;br /&gt;
Wenn man nun auf die gleiche Weise an die weiteren Drehachsen herangeht, so wird man auf dieses Ergebnis kommen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotYMatrix.png]]&lt;br /&gt;
|- valign=&amp;quot;top&amp;quot; &lt;br /&gt;
| [[Bild:Tutorial_Nachsitzen_rotx.gif]]&lt;br /&gt;
|&lt;br /&gt;
====Drehen um die X-Achse====&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_RotXMatrix.png]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Matrixoperationen===&lt;br /&gt;
&lt;br /&gt;
Fürs Arbeiten mit Matrizen gibt es ein paar wichtige Operationen. Ohne diese macht das Arbeiten wenig Spass und würde einem auch wenig bringen.&lt;br /&gt;
&lt;br /&gt;
Ich möchte hier keine genaue Erläuterung über die Funktionsweise dieser Operationen geben, aber erklären, was sie tun und was man damit anstellen kann. Wer diese Operationen verwenden möchte, sollte mal auf Mike Lischkes Homepage vorbeischaun. Dort findet ihr eine Geometry.pas, die diese Funktionen und noch viele mehr beinhaltet. Eine etwas verbesserte und immer wieder aktualisierte Variante liegt dem glScene Projekt bei. Mathematische Details findet ihr in unseren Wiki-Artikeln [[Matrix]] und [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
===Matrixmultiplikation===&lt;br /&gt;
&lt;br /&gt;
Eine wichtige Operation ist die Matrixmultiplikation. Sie verbindet zwei Matrizen zu einer so, dass sie nacheinander ausgeführt werden. Dabei ist zu bedenken, dass die Reihenfolge einen Unterschied macht: erst drehen und dann verschieben ist ungleich erst verschieben und dann drehen, aber das solltet ihr bei der Verwendung von glRotate und glTranslate längst bemerkt haben.&lt;br /&gt;
&lt;br /&gt;
Nun wie multipliziert man Matrizen miteinander? Wie wollen M mit M' multiplizieren. Die Spalten von M' kann man als Vektoren auffassen. Also wendet man einfach M auf die Spalten von M' und bekommt dabei 4 Vektoren. Diese setzt man wieder in einer neuen Matrix nebeneinander und schon hat man M mit M' multipliziert. Ausführlicher wie gesagt im [[Matrix]] Artikel.&lt;br /&gt;
&lt;br /&gt;
===Matrixinversion===&lt;br /&gt;
&lt;br /&gt;
Eine invertierte Matrix macht genau das Gegenteil der ursprünglichen Matrix. Verschiebt die ursprüngliche ein Vertex um 3 nach rechts, so schiebt die intervtierte Matrix ein Vertex um 3 nach links (Achtung: nicht alle Matrizen sind invertierbar, Rotations- und Translationsmatrizen lassen sich jedoch immer invertieren). Dies lässt sich sinnvoll bei Kameras einsetzen:&lt;br /&gt;
&lt;br /&gt;
Man hat ein Objekt, dessen Rotation durch eine Matrix beschrieben wird, was generell sinnvoll ist, wenn das Objekt voneinander abhängige Drehungen vollführen soll oder man das lokale Koordinatensystem des Objekts benötigt. Jedenfalls will man nun das Objekt nicht von aussen bestaunen, sondern sich in die Ansicht des Objekts selbst hineinversetzen, so kann man dessen Rotationsmatrix einfach invertieren und schon hat man sein Ziel erreicht. Wen ähnliches interessiert, sollte sich jetzt einmal an mein [[Tutorial_Kamera1|Kamera Tutorial]] wagen und schauen, dass er's versteht.&lt;br /&gt;
&lt;br /&gt;
Für allgemeine Matrizen ist die nötige Rechnerei leider nicht ganz harmlos. Ich empfehle hierzu einen Blick in die Wikipedia unter Inverse Matrix oder bessere Matheformelsammlungen bzw. Geometrie oder Lineare Algebra Skripte. Ist die Matrix dagegen ein Produkt aus Verschiebungen und Rotationen, dann langt bereits der Artikel [[Techniken_zur_Matrixinversion]].&lt;br /&gt;
&lt;br /&gt;
==OpenGl, Direct3D, IrixGl, MesaGl,... und das Thema Matrizen==&lt;br /&gt;
&lt;br /&gt;
Wie hat man sich gefreut, als man glaubt Matrizen endlich ein wenig verstanden zu haben und dann das! Die ersten Versuche mit [[glLoadMatrix]] und [[glMultMatrix]] müssen zwingend schiefgehen. Immer, wenn man nicht vorgewarnt wird. Wer glaubt seine Matrizen einfach mit einem 2 Dimensionalen Array beschreiben zu können irrt. Die Idee ist zwar nicht schlecht, aber aus Performancegründen liegen die OpenGl Matrizen nicht zeilenweise, sondern spaltenweise im Speicher:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Nachsitzen_GlMatrix.png]]&lt;br /&gt;
&lt;br /&gt;
Ich persönlich bevorzuge meist, statt dass ich in einem 2D-Array immer mit den Zugriffsvariablen herumwurschtle, den Zugriff auf die Matrix mit einem eindimensionalen Array. Die obige Tabelle hilft, die passene Zelle zu finden.&lt;br /&gt;
&lt;br /&gt;
==Kopfschmerzen?==&lt;br /&gt;
&lt;br /&gt;
Ahh, wieder eines meiner schrecklichen Tutorials überlebt. Ich hoffe, dass wenigstens ein paar Leute unter euch das ein oder andere Verstanden haben und ich das alles nicht umsonst geschrieben habe (wenns nur einer Verstanden hat, bin ich schon glücklich ;-) ). Ein paar weitere, spannende Hilfsmittel, die hier nicht unerwähnt bleiben sollten, sind das [[Standard_Skalarprodukt|Punktprodukt]] und das [[Vektorprodukt]], welche Hilfsmittel in der Vektorrechung sind. Defizite dort gleicht das Tutorial über [[Tutorial_Lineare_Algebra|Lineare Algebra]] aus.&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
Delphic&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| [[Tutorial Lineare Algebra]] | [[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Nachsitzen]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Abseits_eckiger_Welten&amp;diff=23927</id>
		<title>Tutorial Abseits eckiger Welten</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Abseits_eckiger_Welten&amp;diff=23927"/>
				<updated>2009-07-23T15:09:26Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Abseits eckiger Welten =&lt;br /&gt;
== Einführung ==&lt;br /&gt;
&lt;br /&gt;
Unsere Welt ist, schlecht, eintönig und eckig. Wirklich? Eckig? Schauen wir uns noch einmal um. An vielen Stellen ja, aber nicht überall. Rundungen sind sogar recht häufig anzutreffen. Ein Blick um mich herum offenbart es. Maus, Lampe, Joystick,... Vieles hat Rundungen. Ein Blick auf das was bisher bei DGL zu sehen war, zeigt: alles eckig :-(. Das muss geändert werden. Runden wir unsere Virtuellen Welten ein wenig ab - unser Hilfsmittel: Curved Surfaces&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Von Linien und Kurven ==&lt;br /&gt;
&lt;br /&gt;
Dies Kaptitel basiert auf [http://www.gamasutra.com/features/19990611/bezier_01.htm Curved Surfaces Using Bézier Patches von Gabe Kruger]. Mit freundlicher Genehmigung übersetzt ins deutsche und natürlich mit der ein oder anderen Änderung.&lt;br /&gt;
&lt;br /&gt;
=== Prozedurale Linien ===&lt;br /&gt;
&lt;br /&gt;
Gerade Strecken lassen sich allein durch die Angabe eines Start und Endpunktes beschreiben. Mit einer Liniengleichung lassen sich beliebig viele Punkte auf dieser Strecke berechnen. Eine solche Gleichung ist z.B.:&lt;br /&gt;
&lt;br /&gt;
    Q(t) = (1 - t)*P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; + t*P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Parameter t hat dabei Werte von 0 bis 1. P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; und P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; sind die Endpunkte der Strecke. Setzt man den Parameter t = 0 ein, so ist das Ergebnis P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;. Setzt man 1 ein ist das Ergebnis P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;.&lt;br /&gt;
Die Gleichung könnte man etwas umschreiben:&lt;br /&gt;
&lt;br /&gt;
    Q(t) = B&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;(t)*P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; + B&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;(t)*P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wobei gilt:&lt;br /&gt;
&lt;br /&gt;
    B&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;(t) = 1 - t&lt;br /&gt;
    B&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;(t) = t&lt;br /&gt;
&lt;br /&gt;
Man nennt B&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt;(t) und B&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;(t) die Basis Funktionen der Liniengleichung. Ändern wir diese Gleichung nochmals ein wenig ab:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_linearsum.gif]]&lt;br /&gt;
&lt;br /&gt;
Dies ist die analytisch bearbeitete Fassung der Liniengleichung, die meisten Beschreibungen parametrischer '''Kurven''' werden in dieser Form gezeigt. Kurven? Klingt so als wären wir bereits am Ziel? Fast.&lt;br /&gt;
&lt;br /&gt;
=== Evolution zu Bezier Kurven ===&lt;br /&gt;
&lt;br /&gt;
Wie erzeugen wir nun eine Kurve in parametrischer Form, ählich der obigen? Wir wollen eine Kurve beschreiben, die durch die Endpunkte geht und dazwischen sich einem anderen Punkt annähert:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_linesconnected.gif]]&lt;br /&gt;
&lt;br /&gt;
P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; und P&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; sind die Endpunkte, P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; ist der Kontrollpunkt, dem wir uns annähern wollen. Man könnte nun einen Punkt P&amp;lt;sub&amp;gt;a&amp;lt;/sub&amp;gt;(t) zwischen P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; und P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; interpolieren und das gleiche mit einem Punkt P&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt;(t) zwischen P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; und P&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;. Der gewünschte Punkt Q(t) auf der Kurve kann dann errechnet werden, durch interpolieren zwischen den Punkten P&amp;lt;sub&amp;gt;a&amp;lt;/sub&amp;gt; und P&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_interpolated.gif]]&lt;br /&gt;
&lt;br /&gt;
In mathematischen Formeln ausgedrückt:&lt;br /&gt;
&lt;br /&gt;
    P&amp;lt;sub&amp;gt;a&amp;lt;/sub&amp;gt;(t) = (1 - t)P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; + t * P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;&lt;br /&gt;
    P&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt;(t) = (1 - t)P&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; + t * P&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
    Q(t)  = (1 - t)P&amp;lt;sub&amp;gt;a&amp;lt;/sub&amp;gt;(t) + tP&amp;lt;sub&amp;gt;b&amp;lt;/sub&amp;gt;(t) =&lt;br /&gt;
          = (1 - t)²P&amp;lt;sub&amp;gt;0&amp;lt;/sub&amp;gt; + 2(1 - t)tP&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; + t²P&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der Lohn der Mühen:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_quadraticbezier.gif]]&lt;br /&gt;
&lt;br /&gt;
Wir können nun die Gleichung von oben umschreiben:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_quadraticsum.gif]]&lt;br /&gt;
&lt;br /&gt;
Nun haben wir eine Definition einer quadratischen Bézier Kurve entwickelt. Es gibt eine einfache Formel für die Basis Funktionen von Bezier Kurven für einen beliebigen Grad. n ist der Grad, i beziffert die Basis Funktion und reicht damit von 0 bis n:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_basisfunctions.gif]]&lt;br /&gt;
&lt;br /&gt;
Ein Beispiel einer solchen Kurve mit dem Grad 3:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_kubikbezier.gif]]&lt;br /&gt;
&lt;br /&gt;
== Evaluators ==&lt;br /&gt;
&lt;br /&gt;
Wir können jetzt Bezier Kurven von Hand berechnen und, mit etwas Umsicht das ganze von 2D auf 3D transformieren. Das kann man vielseitig einsetzen und man kann gleichzeitig auf Detaileinstellungen in einem Programm reagieren - je höher der Detailgrad, desto feiner werden die Kurven aufgelöst. Ebenso kann man sie schön für Kamerafahrten verwenden.&lt;br /&gt;
&lt;br /&gt;
Interessant ist jedoch, dass OpenGl auch die Möglichkeit besitzt, solche Kurven selber zu rendern. In reinem OpenGl kann man hier Evaluators verwenden. &lt;br /&gt;
&lt;br /&gt;
=== Erster Versuch: Evaluator Kurve ===&lt;br /&gt;
&lt;br /&gt;
Als erstes wollen wir versuchen einen kubischen Bézier mit OpenGL Evaluators zu zeichnen. Definieren wir zuerst einmal 4 Kontrollpunkte:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    const&lt;br /&gt;
      ctrlpoints : Array[0..3] of Array[0..2] of TGlFloat =&lt;br /&gt;
       ((-4.0, 2.0, 0.0),(-2.0, 4.0, 0.0),(2.0, -4.0, 0.0),(4.0, 2.0, 0.0));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Der nächste Schritt ist das Übergeben der Punkte an OpenGL:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glMap1f(GL_MAP1_VERTEX_3, 0, 1.0, 3, 4, @ctrlpoints[0,0]);&lt;br /&gt;
    glEnable(GL_MAP1_VERTEX_3);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Kleine Erklärung von '''[[glMap1]]f''':&lt;br /&gt;
&lt;br /&gt;
Die 1 steht dafür, dass wir eine Linie beschreiben wollen. Eine 2, also '''[[glMap2]]f''' stünde für eine Fläche. Der erste Parameter beschreibt den Typ an Daten, den wir übergeben - in unserem Fall also dreidimensionale Vertexkoordinaten. Die nächsten 2 Parameter u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; und u&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; beschreiben den Start- und Endwert unserer Kurve. Sie beschreiben sozusagen die Werte, die der Parameter t aus dem vorigen Kapitel haben muss, um eine komplette Kurve zu beschreiben. Der Parameter stride sagt aus, wie viele Floats vom Startfloat des einen Kontroll- bis zum Startfloat des nächsten Kontrollpunkts liegen. In unserem Fall also 3(Wegen Array[0..2] - hat 3 Elemente). Der vorletzte Parameter order sagt aus, wie viele Kontrollpunkte wir übergeben wollen. Zu guter Letzt noch ein Pointer auf die Kontrollpunkte, und wir haben unsere Schuldigkeit getan. &lt;br /&gt;
&lt;br /&gt;
Wir haben nun zwei Möglichkeiten unseren Evaluator zu zeichnen. Die erste:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    var&lt;br /&gt;
      i : Integer;&lt;br /&gt;
      ...&lt;br /&gt;
      glBegin(GL_LINE_STRIP);&lt;br /&gt;
        for i := 0 to 30 do&lt;br /&gt;
          glEvalCoord1f(i/30);&lt;br /&gt;
      glEnd;&lt;br /&gt;
      ...&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''[[glEvalCoord]]1f''' erzeugt die Vertexdaten, die wir mittels [[glMap1]]f genauer definiert haben (diesmal also nur Vertexpositionen, keine Farben, keine Texturkoordinaten, etc.). Als Parameter werden Werte zwischen u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; und u&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; eingesetzt.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_openglcurve.gif]]&lt;br /&gt;
&lt;br /&gt;
Es gibt noch eine andere Methode, mit der man die Daten in einem Rutsch an OpenGL weitergeben kann:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glMapGrid1f(30, 0.0, 1.0);&lt;br /&gt;
    //...&lt;br /&gt;
    glEvalMesh1(GL_LINE, 0, 30);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Mit [[glMapGrid]]1f stellen wir ein, in wieviele Segmente wir unsere Linie unterteilen wollen und übergeben gleichzeitig den Bereich in der Kurve u&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; und u&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[[glEvalMesh]]1 zeichnet nun unser gutes Stück als Linie. Gezeichnet werden alle Segmente von 0 bis 30.&lt;br /&gt;
&lt;br /&gt;
=== Von Linien zu Flächen ===&lt;br /&gt;
&lt;br /&gt;
Die bisherigen Ergebnisse sind noch nicht wirklich überzeugend. Unser Ziel war es immerhin Oberflächen zu zeichnen und keine Linien. Aber weit entfernt sind wir nicht mehr. Beginnen wir damit, wieder unsere Kontrollpunkte zu definieren:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  var&lt;br /&gt;
    CtrlPoints2D : Array[0..3] of Array[0..3] of Array[0..2] of TGlFloat;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Diesmal eine Variable? Ist er krank? Seit wann benutzt er Variablen? Nun ich kanns euch erklären: Ich habe mit mehreren unterschiedlichen Flächen herumgespielt und wollte nicht ständig dabei am Code herumbasteln, also habe ich mir fix eine Routine zum Laden der Punkte geschrieben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    procedure LoadCtrlPoints;&lt;br /&gt;
    var&lt;br /&gt;
      u, v : Integer;&lt;br /&gt;
      F : Text;&lt;br /&gt;
    begin&lt;br /&gt;
      AssignFile(F, 'surface.txt');&lt;br /&gt;
      Reset(F);&lt;br /&gt;
      FillChar(CtrlPoints2D[0,0,0], SizeOf(CtrlPoints2D), 0);&lt;br /&gt;
      for u := 0 to 3 do&lt;br /&gt;
        for v := 0 to 3 do&lt;br /&gt;
          ReadLn(F, CtrlPoints2D[u,v,0], CtrlPoints2D[u,v,1], CtrlPoints2D[u,v,2]);&lt;br /&gt;
      CloseFile(F)&lt;br /&gt;
    end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Ist die billigste Variante, ohne jeglichen Fehlerschutz, aber fürs herumspielen sollte das genügen. Sobald wir unsere Kontrollpunkte geladen haben, sollten wir sie an OpenGL übergeben:  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    LoadCtrlPoints;&lt;br /&gt;
    glMap2f(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, @CtrlPoints2D[0,0,0]);&lt;br /&gt;
    glEnable(GL_MAP2_VERTEX_3);&lt;br /&gt;
    glEnable(GL_AUTO_NORMAL);&lt;br /&gt;
    glEnable(GL_NORMALIZE);&lt;br /&gt;
    glMapGrid2f(40, 0.0, 1.0, 40, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die [[glMap2]]f Funktionen haben jetzt ein paar neue Parameter erhalten. Dies sind an sich die gleichen Parameter wie bei den [[glMap1]]f Funktionen, nur dass sie nun doppelt vorhanden sind, für die v Richtung.&lt;br /&gt;
&lt;br /&gt;
Schlussendlich wollen wir noch unsere Oberflächen anzeigen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glEvalMesh2(GL_FILL, 0, 40, 0, 40);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Hat die Datei &amp;quot;surface.txt&amp;quot; nun folgenden Inhalt:&lt;br /&gt;
&lt;br /&gt;
    -1.5 2.0 -1.5&lt;br /&gt;
    -0.5 -1.0 -1.5&lt;br /&gt;
    0.5 -1.0 -1.5&lt;br /&gt;
    1.5 -2.0 -1.5&lt;br /&gt;
    -1.5 2.0 -0.5&lt;br /&gt;
    -0.5 1.0 -0.5&lt;br /&gt;
    0.5 -2.0 -0.5&lt;br /&gt;
    1.5 0.0 -0.5&lt;br /&gt;
    -1.5 0.0 0.5&lt;br /&gt;
    -0.5 0.0 0.5&lt;br /&gt;
    0.5 0.0 0.5&lt;br /&gt;
    1.5 0.0 0.5&lt;br /&gt;
    -1.5 1.0 1.5&lt;br /&gt;
    -0.5 0.0 1.5&lt;br /&gt;
    0.5 -1.0 1.5&lt;br /&gt;
    3.0 -2.0 1.5&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
dann könnte das enstehende Bild so aussehen:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_owncurve.gif]]&lt;br /&gt;
&lt;br /&gt;
=== Texturen und anderes Feintuning ===&lt;br /&gt;
&lt;br /&gt;
Es ist schon bemerkenswert, wie leicht man Curved Surfaces in OpenGL zeichnen kann. Was fehlt, ist die Möglichkeit, die Flächen, die man erzeugt hat, auch noch zu texturieren. Jedem dürfte klar sein, was das für Vorteile hat.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_Abseits_eckiger_Welten_texturedcurve.gif]]&lt;br /&gt;
&lt;br /&gt;
Das schöne ist, dass man die Texturierung mit den gleichen Mitteln lösen kann, wie die Oberflächen selbst - mit Evaluators. Definieren wir uns also zuerst einmal ein paar Kontrollpunkte:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    const&lt;br /&gt;
      TexCoords : Array[0..1, 0..1, 0..1] of TGlFloat =&lt;br /&gt;
        (((0.0, 0.0),(0.0, 1.0)), ((1.0, 0.0),(1.0, 1.0)));&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
und übergeben die Koordinaten an OpenGL:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    LoadCtrlPoints;&lt;br /&gt;
    glMap2f(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, @CtrlPoints2D[0,0,0]);&lt;br /&gt;
&lt;br /&gt;
    LoadDevilTexture('flowers256.tga');&lt;br /&gt;
    glEnable(GL_TEXTURE_2D); &lt;br /&gt;
&lt;br /&gt;
    glMap2f(GL_MAP2_TEXTURE_COORD_2, 0.0, 1.0, 2, 2, 0.0, 1.0, 4, 2, @TexCoords[0,0,0]);&lt;br /&gt;
    glEnable(GL_MAP2_TEXTURE_COORD_2);&lt;br /&gt;
    &lt;br /&gt;
&lt;br /&gt;
    glEnable(GL_MAP2_VERTEX_3);&lt;br /&gt;
    glEnable(GL_AUTO_NORMAL);&lt;br /&gt;
    glEnable(GL_NORMALIZE);&lt;br /&gt;
    glMapGrid2f(40, 0.0, 1.0, 40, 0.0, 1.0);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn wir jetzt mittels glEvalMesh2(GL_FILL, 0, 40, 0, 40) die Szene rendern, bekommen wir das obige Bild. Simpel, nicht?&lt;br /&gt;
&lt;br /&gt;
Noch viel schöner wirds, wenn man feststellt, dass das gleiche nicht nur mit Texturkoordinaten funktioniert. Hier mal eine kleine Übersicht über die Parameter von glMapxf:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot;&lt;br /&gt;
! Konstante:&lt;br /&gt;
! Parameter:&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_VERTEX_3 || x,y,z Vertex-Koordinaten&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_VERTEX_4 || x,y,z,w Vertex-Koordinaten&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_INDEX || Farb-Index Werte&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_COLOR_4 || R,G,B,A Farbwerte&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_NORMAL || Normalen-Richtungen&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_TEXTURE_COORD_1 || s Textur-Koordinaten&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_TEXTURE_COORD_2 || s,t Textur-Koordinaten&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_TEXTURE_COORD_3 || s,t,r Textur-Koordinaten&lt;br /&gt;
|-&lt;br /&gt;
| GL_MAPx_TEXTURE_COORD_4 || s,t,r,q Textur-Koordinaten&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== NURBs ==&lt;br /&gt;
&lt;br /&gt;
Die OpenGL NURBs sind Teil der GL Utilities und damit bei jeder OpenGL-Implementation dabei. Im Redbook finden sich einige sehr schöne Beispiele, die die Verwendung von Nurbs zeigen. Eine Sache, die die NURBs interessant macht, ist die Möglichkeit sie trimmen zu können. Darunter fällt z.B. das Schneiden von Löchern mitten in die Fläche. Eine genaue Besprechung von NURBs würde den Rahmen dieses kleinen Tutorials sicher bei weitem sprengen, so dass ich beschließe hier meine kleine Einführung in das Thema Curved Surfaces zu beenden.&lt;br /&gt;
&lt;br /&gt;
[[Benutzer:Delphic|Delphic]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION| - | [[Tutorial_Renderpass]] }}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|Abseits eckiger Welten]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_8&amp;diff=23926</id>
		<title>Tutorial Lektion 8</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_Lektion_8&amp;diff=23926"/>
				<updated>2009-07-23T15:08:49Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Das Wesen von Hell und Dunkel - Licht =&lt;br /&gt;
&lt;br /&gt;
== Licht an ==&lt;br /&gt;
&lt;br /&gt;
Hi,&lt;br /&gt;
und wieder melde ich mich mit einem neuen Tutorial zurück. Heutiges Thema: Licht. Ohne Licht wäre die Umwelt dunkel und kein Pflänzchen könnte Zucker mittels Photosynthese erzeugen. Gäbe es kein Licht, so gäbe es die Welt nicht, wie wir sie kennen. Um in den eigenen OpenGL Programmen eine auch nur annähernd realistische Atmosphäre zu erzeugen ist Licht entsprechend unabdingbar. Man kann Szenen dadurch einen düsteren, geheimnisvollen oder auch einen farbenfrohen, fast kitschigen Stil verleihen.&lt;br /&gt;
&lt;br /&gt;
== Arten des Lichts ==&lt;br /&gt;
&lt;br /&gt;
In OpenGL gibt es unterschiedliche Arten des Lichts. Umgebungs-Licht ('''Ambient''') ist eine Art des Lichts, dessen Richtung nicht zu erkennen ist. Es entsteht durch mehrfache Reflexion an Wänden oder anderen Flächen. Entsprechend gut vertreten ist es in Räumen, aber auch in der freien Natur umgibt uns nicht zu wenig davon. An sich ist es das am schwierigsten zu berechnende, aber in vielen Szenen reicht es aus, eine Konstante vorzugeben - so macht es jedenfalls OpenGL.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Diffuses&amp;quot; Licht ('''Diffuse''') dagegen lässt die Richtung aus der es kommt erkennen. Je stärker eine Seite in das Licht gehalten wird, desto heller erscheint die Oberfläche. Je weiter man eine Fläche vom Licht abwendet, desto dunkler wird die Oberfläche. Die eintreffenden Lichtstrahlen werden in alle Richtungen verteilt, so dass die Oberfläche von allen Augenpositionen gleich hell erscheint.&lt;br /&gt;
&lt;br /&gt;
Glanz ('''Specular''') kommt aus einer bestimmten Richtung und tendiert dazu, in einer bestimmten Richtung besonders hell zu erscheinen. Plastik, gebürstetes oder nicht matt lackiertes Metall oder auch geschliffene Edelsteine haben einen hohen Glanzanteil, während Holz, Kohle und Wandfarbe so gar nicht glänzen wollen.&lt;br /&gt;
&lt;br /&gt;
== Materialeigenschaften ==&lt;br /&gt;
&lt;br /&gt;
Der vom Licht erzeugte Eindruck hängt aber nicht nur vom Licht selbst ab, sondern auch vom beleuchteten Material. Eine Kohleplatte wirkt im selben Licht anders, als eine polierte Edelstahloberfläche oder das Blech eines lackierten Autos. Deshalb gibt es in OpenGL die sog. Materialeigenschaften. Sie entsprechen denen des Lichts selbst, nur geben sie den Reflexionsgrad und nicht die Intensität wieder. {{Hinweis|Hier im Wiki findet ihr in der [[Materialsammlung]] eine Auswahl von Parameterwerten.}}&lt;br /&gt;
&lt;br /&gt;
Objekte können nun aber auch selbst Licht emittieren. Deshalb befindet sich unter den Materialeigenschaften zusätzlich noch ein Emissionswert. Ein Objekt mit Emission ist also auch bei kompletter Dunkelheit noch sichtbar, so z.B. die grüne Leuchtdiode an meinen Boxen, wenn ich die Rollläden geschlossen habe. Schade nur, dass OpenGL dieses emittierte Licht nicht auch auf andere Objekte überträgt :-(.&lt;br /&gt;
&lt;br /&gt;
== Normalen ==&lt;br /&gt;
&lt;br /&gt;
OpenGL berechnet die Farbe des Lichts, das auf ein Objekt trifft mit Hilfe der Richtung aus der das Licht kommt und der Ausrichtung der Oberfläche eines Vertex. Nun stellt sich die Frage: in welche Richtung zeigt denn die Oberfläche? Wir können bei der Übergabe der Vertexdaten einfach mit [[glNormal]]x die Normalen angeben. Die Länge des Normalenvektors sollte 1 sein. Bei einer Kugel entspricht die Normale übrigens immer der Richtung des Mittelpunktes zum betrachteten Vertex. Für kompliziertere Gegenstände gibt es weiter unten ein paar Tipps zum Berechnen der Normalen auf &amp;quot;Nachbarschaftsbasis&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Erste Lichtstrahlen ==&lt;br /&gt;
&lt;br /&gt;
=== Licht an ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_test.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Es wird Zeit. Machen wir erste Gehversuche mit OpenGL Licht! Wir brauchen dazu nicht viel zu tun. Mit glEnable(GL_LIGHTING) schalten wir die Lichtberechnung scharf und müssen dann eine Lichtquelle aktivieren. Das geht mit glEnable(GL_LIGHTx) (Zur Information: OpenGL Implementationen müssen 8 Lichter unterstützen. Es gibt aber Implementationen, die hier mehr zu bieten haben. Um Zugriff auf alle vorhandenen Lichter zu erhalten, genügt es zu GL_LIGHT0 einen entsprechenden Wert zu addieren. GL_LIGHT0+8 wäre dann z.B. das 9. Licht).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glEnable(GL_LIGHTING);&lt;br /&gt;
  glEnable(GL_LIGHT0);&lt;br /&gt;
  glEnable(GL_COLOR_MATERIAL);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Sonnenbrand erzeugen ===&lt;br /&gt;
&lt;br /&gt;
Der nächste Schritt besteht darin, die Eigenschaften der Lichtquelle(n) an OpenGL weiterzureichen. Dies läuft immer mit der Funktion '''[[glLight]]x'''. Sie nimmt 3 Parameter: '''light''': Die Lichtquelle die gerade eingestellt wird. '''pname''': Die Eigenschaft, die wir manipulieren möchten. '''params''': Der neue Wert der Eigenschaft.&lt;br /&gt;
&lt;br /&gt;
Mit '''pname''' dürfen wir aus einer ganzen Sammlung von Eigenschaften schöpfen:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! Eigenschaft&lt;br /&gt;
! Standard Wert&lt;br /&gt;
! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| GL_AMBIENT || 0.0, 0.0, 0.0, 1.0 || Ambienter RGBA Anteil des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_DIFFUSE || 1.0, 1.0, 1.0, 1.0 || Diffuser RGBA Anteil des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPECULAR || 1.0, 1.0, 1.0, 1.0 || Glanz RGBA Anteil des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_POSITION || 0.0, 0.0, 1.0, 0.0 || Koordinaten des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPOT_DIRECTION || 0.0, 0.0, -1.0 || Richtung des Spotlights&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPOT_EXPONENT || 0.0 || Spotlight-Exponent&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPOT_CUTOFF || 180.0 || Spotlight Sperrwinkel&lt;br /&gt;
|-&lt;br /&gt;
| GL_xxx_ATTENUATION || ... || Abschwächung des Lichtes mit der Entfernung&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Materialeigenschaften übergeben ===&lt;br /&gt;
&lt;br /&gt;
Das gleiche Spielchen müssen wir mit den Materialeigenschaften treiben. Diesmal ist die Funktion '''[[glMaterial]]x''' der Dreh und Angelpunkt. Die Parameterfolge ist die gleiche wie bei '''[[glLight]]x'''.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! Eigenschaft&lt;br /&gt;
! Standard Wert&lt;br /&gt;
! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| GL_AMBIENT || 0.2, 0.2, 0.2, 1.0 || RGBA Reflexionsgrad von ambientem Licht&lt;br /&gt;
|-&lt;br /&gt;
| GL_DIFFUSE || 0.8, 0.8, 0.8, 1.0 || RGBA Reflexionsgrad von diffusem Licht&lt;br /&gt;
|-&lt;br /&gt;
| GL_SPECULAR || 0.0, 0.0, 0.0, 1.0 || RGBA Glanzreflexionsgrad des Lichtes&lt;br /&gt;
|-&lt;br /&gt;
| GL_SHININESS || 0.0 || Glanz-Exponent&lt;br /&gt;
|-&lt;br /&gt;
| GL_EMISSION || 0.0, 0.0, 0.0, 1.0 || RGBA Emission des Materials&lt;br /&gt;
|-&lt;br /&gt;
| GL_COLOR_INDEXES || 0, 1, 1 || Ambient, diffuse, specular Farbindices&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Beispiellicht ===&lt;br /&gt;
&lt;br /&gt;
Das Beispiel mit den Kugeln wurde mit folgendem Code erzeugt:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  procedure TStationarySphereState.RenderState;&lt;br /&gt;
  const&lt;br /&gt;
    mat_specular   : Array[0..3] of GlFloat = (1.0, 1.0, 1.0, 1.0);&lt;br /&gt;
    mat_shininess  : Array[0..0] of GlFloat = (50.0);&lt;br /&gt;
    mat_ambient    : Array[0..3] of GlFloat = (0.4, 0.4, 0.4, 1.0);&lt;br /&gt;
    mat_diffuse    : Array[0..3] of GlFloat = (0.4, 0.8, 0.4, 1.0);&lt;br /&gt;
&lt;br /&gt;
    light_position : Array[0..3] of GlFloat = (10.0, 10.0, 0.0, 1.0);&lt;br /&gt;
    light_ambient  : Array[0..3] of GlFloat = (0.8, 0.8, 0.8, 1.0);&lt;br /&gt;
    light_diffuse  : Array[0..3] of GlFloat = (0.8, 0.8, 0.8, 1.0);&lt;br /&gt;
&lt;br /&gt;
  begin&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_SPECULAR,  @mat_specular[0]);&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_SHININESS, @mat_shininess[0]);&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_AMBIENT,   @mat_ambient[0]);&lt;br /&gt;
    glMaterialfv(GL_FRONT, GL_DIFFUSE,   @mat_diffuse[0]);&lt;br /&gt;
&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_AMBIENT,  @light_ambient[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  @light_diffuse[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_POSITION, @light_position[0]);&lt;br /&gt;
&lt;br /&gt;
    glEnable(GL_COLOR_MATERIAL);&lt;br /&gt;
    glEnable(GL_LIGHTING);&lt;br /&gt;
    glEnable(GL_LIGHT0);&lt;br /&gt;
     ...Szene Rendern...&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Etwas schwächer bitte ==&lt;br /&gt;
&lt;br /&gt;
Viele Lichtquellen werden mit der Entfernung schwächer. Bei unserer Sonne tritt dieser Effekt so gut wie nicht auf, bei kleinen Funzeln dagegen ist recht bald die maximale Leuchtweite erreicht. Diesen Effekt können wir auch mit OpenGL nachahmen.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_attenuation.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Auf diesem Bild ist schön zu erkennen, dass die Kugeln rechts oben heller sind als die links unten, welche weiter von der Lichtquelle entfernt sind (wer nichts sieht, spiele doch mal bitte mit dem [[Farbraum#Grundlegende_Bildschirmkalibrierung|Kontrast und der Helligkeit]] des Monitors - ich kann nicht versprechen, dass der Effekt auf jedem Monitor so schön wie auf meinem herauskommt). Wie wird nun dieser Effekt erzeugt?&lt;br /&gt;
&lt;br /&gt;
OpenGL kennt einen sog. Attenuation Factor:&lt;br /&gt;
&lt;br /&gt;
Attenuation Factor = 1 / (k&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; + k&amp;lt;sub&amp;gt;l&amp;lt;/sub&amp;gt;*d + k&amp;lt;sub&amp;gt;q&amp;lt;/sub&amp;gt;*d*d)&lt;br /&gt;
&lt;br /&gt;
* d = Entfernung zwischen dem berechneten Vertex und der Lichtquelle&lt;br /&gt;
* k&amp;lt;sub&amp;gt;c&amp;lt;/sub&amp;gt; = GL_CONSTANT_ATTENUATION&lt;br /&gt;
* k&amp;lt;sub&amp;gt;l&amp;lt;/sub&amp;gt; = GL_LINEAR_ATTENUATION&lt;br /&gt;
* k&amp;lt;sub&amp;gt;q&amp;lt;/sub&amp;gt; = GL_QUADRATIC_ATTENUATION&lt;br /&gt;
&lt;br /&gt;
Dieser wird Faktor bei der Lichtberechnung einfach mit den Lichtstärken multipliziert, so dass das Licht stärker oder schwächer wird. Übergeben werden die Werte wieder mittels '''[[glLight]]x''':&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0);&lt;br /&gt;
  glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.001);&lt;br /&gt;
  glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.004);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Das Positionsproblem ==&lt;br /&gt;
&lt;br /&gt;
Lichter sind unterschiedlich - Manche sind fest an den Kopf des Betrachters gekoppelt, andere irgendwo in der Szene platziert und wieder andere sind unendlich weit entfernt und ihr Licht trifft parallel auf die Gegenstände. All dies will simuliert werden. OpenGL hält es parat. Uns kommt auch noch zugute, dass OpenGL die Übergabe der Licht Position genauso behandelt wie die eines Vertex und entsprechend durch die Modelview Matrix jagt.&lt;br /&gt;
&lt;br /&gt;
=== Unendlich weit entfernte Lichter ===&lt;br /&gt;
&lt;br /&gt;
Das Universum, die Milchstraße, der äußere Ring, unser Sonnensystem, die Sonne und unsere Erde. Das Licht, das unsere Sonne ausstrahlt und bei uns auf der Erde ankommt, trifft uns in nahezu parallelen Lichtstrahlen. Damit verhält sich die Sonne wie eine unendlich entfernte Lichtquelle. Wenn wir eine solche Lichtquelle angeben wollen, ist also nicht ihre Position interessant (wobei das auch ginge), sondern allein die Richtung aus der das Licht kommt. Wie? Wir setzen die w-Koordinate(=die letzte Koordinate) der Position auf 0. Unsere unendlich weit entfernte Lichtquelle ist komplett. Sinnigerweise ist dann im übrigens auch Attenuation abgeschaltet.&lt;br /&gt;
&lt;br /&gt;
=== Stationäre Lichtquellen ===&lt;br /&gt;
&lt;br /&gt;
Lichtquellen, die an einer bestimmten Stelle in der Szene stehen, müssen mit der Kamerabewegung mitgeschoben werden. Entsprechend wird das Licht angegeben werden, bevor die Modelviewmatrix durch Objekte verschoben wird, aber nachdem die Kamera initialisiert wurde.&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
  //..glRotatef, glTransaltef.. für die Kamera&lt;br /&gt;
  glLightfv(GL_LIGHT0, GL_POSITION, @position[0]);&lt;br /&gt;
  glPushMatrix;&lt;br /&gt;
    //..glRotatef, glTransaltef.. für die Objekte&lt;br /&gt;
    DrawObjekts;&lt;br /&gt;
  glPopMatrix;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Relatives Licht ===&lt;br /&gt;
&lt;br /&gt;
Wollen wir stattdessen unsere Lichtquelle relativ zu einem bestimmten Objekt bewegen, so müssen wir ein wenig anders vorgehen: Erst die Modelviewmatrix so bearbeiten, dass wir das Objekt zeichnen könnten, vor dem Zeichen selbst jedoch die Matrixfunktion für das Licht ausführen und die Lichtposition übergeben:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  //..glRotatef, glTransaltef, glMultMatrix, etc...&lt;br /&gt;
  glPushMatrix;&lt;br /&gt;
    glRotatef(Drehung, 0.0, 1.0, 0.0);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_POSITION, @position[0]);&lt;br /&gt;
  glPopMatrix;&lt;br /&gt;
  DrawObject;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Lichtquellen, die an der Kamera kleben ===&lt;br /&gt;
&lt;br /&gt;
Wenn eine Lichtquelle immer relativ zum Betrachter sein soll(wenn also das Licht z. B. feste am Kopf montiert ist, wie bei einem Minenarbeiter), so langt es die Position des Lichts zu definieren, bevor die Modelviewmatrix mit der Kameraposition und Drehung bearbeitet wurde:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
  glLoadIdentity;&lt;br /&gt;
  glLightfv(GL_LIGHT0, GL_POSITION, @position[0]);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Spot an! ==&lt;br /&gt;
&lt;br /&gt;
Wer kennt sie nicht, die Spotlights? Im Fernsehen und Theater oft gebraucht, aber auch im realen Leben, z.B. bei Taschenlampen, Suchscheinwerfern (etwa noch keinen in der Hand gehabt? Ich schon :-) ), etc. oft zu sehen. Leider benötigt man nicht selten eine ganze Schar von ihnen, wozu sich die OpenGL Lichter nur schlecht eignen - aus der Patsche hilft da oft [[Blending]] oder andere Techniken. Wenn man mit entsprechenden Projektions-Techniken noch keine Erfahrungen hat, müssen die OpenGL-Lichter dann aber doch wieder herhalten.&lt;br /&gt;
&lt;br /&gt;
=== Parameter setzen ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_spotlight.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Schauen wir uns die Lichtparameter für Spotlights an: '''GL_SPOT_DIRECTION''' gibt die Richtung an, in die das Spotlicht zeigt. Diese lässt sich wieder mit Hilfe geschickter Platzierung im Code durch die Modelviewmatrix jagen um den gewünschten Effekt zu erzielen - wie immer eben. '''GL_SPOT_CUTOFF''' gibt den Winkel an, der zwischen Richtung und max. Auswurf besteht. Zuletzt gibt es noch den '''GL_SPOT_EXPONENT''', der beschreibt, wie stark die Lichtstärke nach außen hin abnimmt.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
const&lt;br /&gt;
    light_position : Array[0..3] of GlFloat = (0.0, 10.0, 0.0, 1.0);&lt;br /&gt;
    light0_ambient  : Array[0..3] of GlFloat = (0.8, 0.0, 0.0, 1.0);&lt;br /&gt;
    light0_diffuse  : Array[0..3] of GlFloat = (0.8, 0.0, 0.0, 1.0);&lt;br /&gt;
  var&lt;br /&gt;
    LightDirection : Array[0..2] of GlFloat;&lt;br /&gt;
  begin&lt;br /&gt;
    LightDirection[0] := Sin(Position)/2;&lt;br /&gt;
    LightDirection[1] := -1.0;&lt;br /&gt;
    LightDirection[2] := 0.0;&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, @LightDirection[0]);&lt;br /&gt;
&lt;br /&gt;
    glLightf(GL_LIGHT0, GL_SPOT_CUTOFF, 10.0);&lt;br /&gt;
    glLightf(GL_LIGHT0, GL_SPOT_EXPONENT, 50.0);&lt;br /&gt;
&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_AMBIENT,  @light0_ambient[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_DIFFUSE,  @light0_diffuse[0]);&lt;br /&gt;
    glLightfv(GL_LIGHT0, GL_POSITION, @light_position[0]);&lt;br /&gt;
    glEnable(GL_LIGHT0);&lt;br /&gt;
    glEnable(GL_LIGHTING);&lt;br /&gt;
    //...&lt;br /&gt;
  end;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Zur besseren Illustration ein Bild&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_spots_highres.gif|center]]&lt;br /&gt;
&lt;br /&gt;
== glLightModel? ==&lt;br /&gt;
&lt;br /&gt;
Bislang haben wir einen Befehl völlig ausser Acht gelassen: '''[[glLightModel]]x'''. Er nimmt zwei Parameter: '''pname''' und '''param''':&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; align=&amp;quot;center&amp;quot;&lt;br /&gt;
! Eigenschaft&lt;br /&gt;
! Standard Wert&lt;br /&gt;
! Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
| GL_LIGHT_MODEL_AMBIENT&lt;br /&gt;
| 0.2, 0.2, 0.2, 1.0&lt;br /&gt;
| Abientes RGBA Licht der gesamten Szene&lt;br /&gt;
|-&lt;br /&gt;
| GL_LIGHT_MODEL_LOCAL_VIEWER&lt;br /&gt;
| 0.0 oder GL_FALSE&lt;br /&gt;
|Lokaler oder unendlicher Viewport. Wirkt bei Specular Reflexionen:&lt;br /&gt;
;GL_FALSE: Die Richtung von Betrachter zu Vertex wird nur 1 mal berechnet und bleibt damit für alle Vertices konstant.&lt;br /&gt;
;GL_TRUE: Die Richtung Betrachter zu Vertex wird für jedes Vertex neu berechnet, was in einem realistischeren Anblick endet.&lt;br /&gt;
|-&lt;br /&gt;
| GL_LIGHT_MODEL_TWO_SIDE&lt;br /&gt;
| 0.0 oder GL_FALSE&lt;br /&gt;
| Einseitiges oder doppelseitiges Lighting&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Das Vertexproblem ==&lt;br /&gt;
&lt;br /&gt;
Die Benutzung von Licht muss bislang auf euch sehr einfach gewirkt haben. Aber der eine oder andere wird es vielleicht schon herausgelesen haben: OpenGL Licht wird per Vertex und nicht per Pixel berechnet. Das Problem dabei ist, dass sich mit der Auflösung des Objekts das Aussehen des Lichts stark ändern kann. Bei diffusem und ambientem Licht spielt das kaum eine Rolle. Specular und Spotlights reagieren empfindlich. Die schönen Rundungen, die diese Lichtarten häufig ausbilden, können  verschandelt werden. Die Ergebnisse sind nicht mehr wirklich rund, vielmehr eckig und kantig. Ihr glaubt mir nicht? Dann schaut nicht zu genau hin:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_spots_lowres.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Und was lernen wir draus? Schönes Licht braucht viele Vertices.&lt;br /&gt;
&lt;br /&gt;
== Normalen die 2. ==&lt;br /&gt;
&lt;br /&gt;
=== Länge = 1? ===&lt;br /&gt;
&lt;br /&gt;
Kommen wir also nun wie versprochen noch einmal zu den Normalen zurück. Normalen, die mit [[glNormal|glNormalx]] angegeben werden, werden, abgesehen von Verschiebungen, wie Vertices mit der Modelview Matrix multipliziert. Normalen sollten für korrekte Lichtberechnung normiert sein, dass heißt die Länge 1 haben (ist sie länger, so erscheint das Objekt heller, ist sie kürzer, so wird das Objekt dunkler). Ist mit der Multiplikation mit der Modelviewmatrix auch eine Skalierung verbunden, so haben wir ein Problem, denn die Länge ist nicht mehr 1. Um das zu beheben, kann vermittels '''[[glEnable]](GL_NORMALIZE)''' OpenGL angewiesen werden, die Normalen selbst auf Länge eins zu skalieren. Aber Achtung: Das kostet Rechenleistung. Allerdings kostet selber berechnen vermutlich noch mehr.&lt;br /&gt;
&lt;br /&gt;
=== Einfache Normalen ===&lt;br /&gt;
&lt;br /&gt;
Manchmal ist die Berechnung von Normalen ganz einfach. So bei Kugeln. Die Richtung die der Mittelpunkt zu irgendeinem Vertex auf der Oberfläche beschreibt, ist gleich der Richtung der Normalen - sie muss nur noch normiert werden. Bei Flächen auf den Achsen muss unsereins auch nicht groß nachdenken, wie denn die passende Normale auszusehen hat. Aber wie ist es, wenn unser betrachteter Körper keine so einfache Oberfläche hat? Was dann?&lt;br /&gt;
&lt;br /&gt;
=== Normalenberechnung per Dreieck ===&lt;br /&gt;
&lt;br /&gt;
Will man anhand von Dreiecksdaten Normalen erzeugen, so muss man mal wieder zur Mathematik rüberschauen - die haben das ideale Werkzeug dafür: Das [[Vektorprodukt|Vektor-Kreuzprodukt]]. Um die Normale der Fläche beschrieben durch die 3 Ecken V&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt;, V&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;, V&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt; zu bekommen, braucht man nur zu rechnen:&lt;br /&gt;
&lt;br /&gt;
N = (V&amp;lt;sub&amp;gt;1&amp;lt;/sub&amp;gt; - V&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt;)x(V&amp;lt;sub&amp;gt;2&amp;lt;/sub&amp;gt; - V&amp;lt;sub&amp;gt;3&amp;lt;/sub&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
Wenn wir das für jedes Polygon durchziehen, dann können wir für jeweils 3 Vertices die Normale angeben. Das schaut ein bisschen eckig aus, bringt uns unserem Ziel aber gewaltig näher. Erinnert irgendwie an die ersten Spiele, die mit Licht arbeiteten... Flatshading war schon was schönes, aber OpenGL kann mehr, wie wir bereits an den Kugeln gesehen haben.&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_normalen_flat.gif|center]]&lt;br /&gt;
&lt;br /&gt;
'''Und nicht vergessen:''' Die Normalen sollten noch auf die Länge 1 gebracht werden, siehe [[Normale]].&lt;br /&gt;
&lt;br /&gt;
=== Normalen glätten ===&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_normalen_smooth.gif|center]]&lt;br /&gt;
&lt;br /&gt;
Um die Polygone nun ein wenig unsichtbarer zu machen, gibt es ein einfaches Hilfsmittel: Man nehme die direkt anliegenden Flächennormalen um ein Vertex, bilde den Durchschnitt und voilà: Unser Objekt schaut schon runder aus. An einigen Stellen sollte man damit aber vorsichtig walten: Geht es einmal wirklich scharf um eine spitze Kante, so schaut diese Abrundung vermutlich etwas seltsam und abnormal aus. Also: Nicht einfach drauflos abrunden. Da bei komplexeren Objekten jeder vermutlich sowieso einen 3D Modeller verwendet, bei dem man das etwas feinfühlig kontrollieren kann, sollte das kein größeres Problem sein - jeder der seinen eigenen Modeller schreibt, muss sich natürlich etwas einfallen lassen - nützlich erweist sich hier das [[Standard_Skalarprodukt|Skalarprodukt]], da man damit den Winkel zwischen zwei Normalen bestimmen kann. Ist der Winkel zu groß, kann es sich nicht um eine Rundung handeln und wir haben es mit einer Kante zu tun - zumindest solange unsere Polygondaten halbwegs fein aufgelöst sind.&lt;br /&gt;
&lt;br /&gt;
== Das etwas andere Licht ==&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_RoteRinge.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Mit OpenGL's Standardmethode einen Beleuchtungseffekt zu erzielen, ist natürlich nicht der Weisheit letzter Schluss. Ein anderer Trick drängt sich bei entsprechendem Wissen über die Möglichkeiten geradezu auf: Environment Mapping, oder im folgendem speziell Sphere Mapping. Den entstehenden Effekt kann man mit einer perfekten Spiegelung vergleichen. Das einzige was wir tun müssen, ist OpenGL anzuweisen, die Texturkoordinaten selbst zu berechnen:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);&lt;br /&gt;
    glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);&lt;br /&gt;
    glEnable(GL_TEXTURE_GEN_S);&lt;br /&gt;
    glEnable(GL_TEXTURE_GEN_T);&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das wars schon, wir benötigen nur noch eine Sphere Map:&lt;br /&gt;
&lt;br /&gt;
[[Bild:Tutorial_lektion8_lightmap.jpg|center]]&lt;br /&gt;
&lt;br /&gt;
Wenn man das ganze nun noch mit [[Multitexturing]] verknüpft, so kann man eine Texturlage für die normale Textur verwenden und die 2. für das Licht. Eine rote Spheremap erzeugt aber rotes Licht, gell... Happy Coding ;-)&lt;br /&gt;
&lt;br /&gt;
== Licht aus ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;&lt;br /&gt;
    glDisable(GL_LIGHTING)&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Und wieder ist eines meiner Tutorials am Ende. Wenn ich mich nicht irre ists die Nummer 11. Wer gibt mir den verdienten Schnaps aus? Na? Keine Freiwilligen? Schade :-( . In jedem Fall hast Du es jetzt erst einmal hinter Dir und kannst Dich ganz entspannt zurücklehnen - oder, was mir besser gefallen würde: Ein paar OpenGL Programme mit Lichtunterstützung schreiben und uns das Ergebnis als IOTW oder als solches einsenden. Ersatzweise tuts auch etwas freundliches Feedback - das lasst ihr nämlich allesamt immer sehr missen, was das Team zurecht schade findet. Also lasst uns nicht hängen, sondern gebt von euch, was euch an den Tutorials gefällt und was nicht.&lt;br /&gt;
&lt;br /&gt;
und jetzt:&lt;br /&gt;
&lt;br /&gt;
...have a lot of fun!&lt;br /&gt;
&lt;br /&gt;
'''[[Benutzer:Delphic|Delphic]]&lt;br /&gt;
&amp;amp; Co-Autor [[Benutzer:Traude|Traude]]'''&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION | [[Tutorial Lektion 7]] | [[Tutorial 2D]] }}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Team&amp;diff=23925</id>
		<title>Team</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Team&amp;diff=23925"/>
				<updated>2009-07-23T15:07:59Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Vorwort =&lt;br /&gt;
&lt;br /&gt;
Auf dieser Seite befindet sich eine Auflistung der Personen, die momentan aktiv daran arbeiten, dass DGL Euch wie gewohnt im Netz mit Informationen versorgt. Bitte beachtet, dass die meisten der Personen nur einen begrenzten Vorrat an Zeit haben. Überlegt daher bitte sorgsam, an wen Ihr Euch wendet.&lt;br /&gt;
&lt;br /&gt;
Im unteren Teil dieser Seite sind die verschiedenen Bereiche von DGL und deren Betreuer aufgelistet. Bitte wendet auch an den passenden Ansprechpartner.&lt;br /&gt;
&lt;br /&gt;
Diese Seite ersetzt nicht das '''[http://www.delphigl.com/launcher.php?em=impressum IMPRESSUM]'''.&lt;br /&gt;
&lt;br /&gt;
= Das Team im Ganzen =&lt;br /&gt;
In diesen Abschnitt ist aufgelistet '''wer''' bei [[DelphiGL]] Verantwortung für einen Teil übernommen hat, und '''was''' genau er macht.&lt;br /&gt;
== Moderatoren ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;80%&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Forumsname&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Email&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Aufgabenbereich&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Phobeus|Phobeus]] &lt;br /&gt;
|{{eMail|Phobeus|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*Technische Pflege des Wikis (Wartung/Updates)&lt;br /&gt;
*Betreuung der Hardware&lt;br /&gt;
*Freischalten von Usern für das Forum&lt;br /&gt;
*Freischalten von Usern für das Wiki&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
*&amp;quot;der Chef&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Flash|Flash]] &lt;br /&gt;
|{{eMail|Flash|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*Inhaltliche Pflege des Wikis&lt;br /&gt;
*DGL-Poll pflegen&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle im Forum&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Delphic|Delphic]] &lt;br /&gt;
|{{eMail|delphic|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*Freischalten von Usern für das Forum&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Lossy eX|Lossy eX]] &lt;br /&gt;
|{{eMail|Lossy|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*dglOpenGL.pas&lt;br /&gt;
*Freischalten von Usern für das Forum&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Flo|Flo]]&lt;br /&gt;
|{{eMail|Flo|DelphiGL.com}}&lt;br /&gt;
|&lt;br /&gt;
*Freischalten von Usern für das Wiki&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:I0n0s|i0n0s]] &lt;br /&gt;
|{{eMail|i0n0s|DelphiGL.com}}&lt;br /&gt;
|&lt;br /&gt;
*DGLSDK&lt;br /&gt;
*Freischalten von Usern für das Forum&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Sascha Willems|Sascha Willems]] &lt;br /&gt;
|{{eMail|webmaster|delphigl.de}}&lt;br /&gt;
|&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Magellan|Magellan]] &lt;br /&gt;
|{{eMail|Magellan|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*News eintragen&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:La Boda|La Boda]] &lt;br /&gt;
|{{eMail| -pdl-|web.de}}&lt;br /&gt;
|&lt;br /&gt;
*allgemeine inhaltliche Kontrolle&lt;br /&gt;
*News eintragen&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Gruppen =&lt;br /&gt;
In diesem Teil findet ihr detailierte Informationen, wer für welchen Bereich zuständig ist.&lt;br /&gt;
== DGLSDK ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;80%&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Forumsname&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Email&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Aufgabenbereich&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:I0n0s|i0n0s]] &lt;br /&gt;
|{{eMail|i0n0s|DelphiGL.com}}&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== DGLOpenGL.pas ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;80%&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Forumsname&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Email&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Aufgabenbereich&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Lossy eX|Lossy eX]] &lt;br /&gt;
|{{eMail|Lossy|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*Weiterentwicklung, Debugging&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Webseite ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;80%&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Forumsname&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Email&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Aufgabenbereich&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Phobeus|Phobeus]] &lt;br /&gt;
|{{eMail|Phobeus|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*Technische Pflege des Seite (Wartung/Updates)&lt;br /&gt;
*Coding (Integrieren von Neuerungen)&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Flash|Flash]] &lt;br /&gt;
|{{eMail|Flash|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*DGL-Poll pflegen&lt;br /&gt;
|-&lt;br /&gt;
|Alle Anderen &lt;br /&gt;
|(siehe oben)&lt;br /&gt;
|&lt;br /&gt;
*News&lt;br /&gt;
*Sorgen für angemessene Umgangsformen&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Wiki ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;80%&amp;quot;&lt;br /&gt;
!width=&amp;quot;20%&amp;quot;|Forumsname&lt;br /&gt;
!width=&amp;quot;30%&amp;quot;|Email&lt;br /&gt;
!width=&amp;quot;50%&amp;quot;|Aufgabenbereich&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Flash|Flash]] &lt;br /&gt;
|{{eMail|Flash|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*Inhaltliche Pflege des Wikis&lt;br /&gt;
*Koordinierung&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:Phobeus|Phobeus]] &lt;br /&gt;
|{{eMail|Phobeus|delphigl.com}}&lt;br /&gt;
|&lt;br /&gt;
*Technische Pflege des Wikis (Wartung/Updates)&lt;br /&gt;
*Betreuung der Hardware&lt;br /&gt;
|-&lt;br /&gt;
|[[Benutzer:La Boda|La Boda]]&lt;br /&gt;
|{{eMail| -pdl-|web.de}}&lt;br /&gt;
|&lt;br /&gt;
*Inhaltliche Pflege des Wikis&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=DelphiGL&amp;diff=23924</id>
		<title>DelphiGL</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=DelphiGL&amp;diff=23924"/>
				<updated>2009-07-23T15:07:23Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{|&lt;br /&gt;
|Dieser Artikel beschäftigt sich mit [http://DelphiGL.com DelphiGL.com].&amp;lt;br&amp;gt; &lt;br /&gt;
DelphiGL ist die Website welche dieses Wiki betreibt und das angeschlossene Forum ist der feste Hafen für deutschsprachige OpenGL-Programmierer im sturmumtosten GrafikAPI-Ozean.&lt;br /&gt;
&lt;br /&gt;
Informationen zum Team findet ihr im Artikel [[Team]].&lt;br /&gt;
|&amp;lt;div align=&amp;quot;right&amp;quot;&amp;gt;[http://delphiGL.com http://delphigl.com/gfx/banner/banner256x64.gif]&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;small&amp;gt;Falls Ihr auf DelphiGL.com oder das DGL-Wiki verlinken wollt, findet ihr die nötigen Banner '''[[DelphiGL_Banner|hier]]'''.&amp;lt;/small&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Mitgliederentwicklung==&lt;br /&gt;
[[Bild:DGL_Mitgliederzahlen.jpg|center|framed|&lt;br /&gt;
Monatliches Wachstum der DGL Community (Angemeldete User im Forum):&amp;lt;br&amp;gt;&lt;br /&gt;
- insgesamt: 19,57 Mitglieder.&amp;lt;br&amp;gt;&lt;br /&gt;
- letzten 12 Monate: 18 Mitglieder.&amp;lt;br&amp;gt;&lt;br /&gt;
- letzten 6 Monate: 15,66 Mitglieder.]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Für Liebhaber von Statistiken: &lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}}&lt;br /&gt;
|+Halbjährliche Mitgliederentwicklung&lt;br /&gt;
!Zeitraum&lt;br /&gt;
!durchschnittlicher Zuwachs&lt;br /&gt;
|-&lt;br /&gt;
|01.06.02 - 01.11.02&lt;br /&gt;
|13&lt;br /&gt;
|-&lt;br /&gt;
|01.12.02 - 01.05.03&lt;br /&gt;
|13.5&lt;br /&gt;
|-&lt;br /&gt;
|01.06.03 - 01.11.03&lt;br /&gt;
|17.66&lt;br /&gt;
|-&lt;br /&gt;
|01.12.03 - 01.05.04&lt;br /&gt;
|16&lt;br /&gt;
|-&lt;br /&gt;
|01.06.04 - 01.11.04&lt;br /&gt;
|18&lt;br /&gt;
|-&lt;br /&gt;
|01.12.04 - 01.05.05&lt;br /&gt;
|19.5&lt;br /&gt;
|-&lt;br /&gt;
|01.06.05 - 01.11.05&lt;br /&gt;
|19.83&lt;br /&gt;
|-&lt;br /&gt;
|01.12.05 - 01.05.06&lt;br /&gt;
|31&lt;br /&gt;
|-&lt;br /&gt;
|01.06.05 - 01.11.06&lt;br /&gt;
|21.67&lt;br /&gt;
|-&lt;br /&gt;
|01.12.06 - 01.05.07&lt;br /&gt;
|26.83&lt;br /&gt;
|-&lt;br /&gt;
|01.06.07 - 01.11.07&lt;br /&gt;
|21.16&lt;br /&gt;
|-&lt;br /&gt;
|01.12.07 - 01.05.08&lt;br /&gt;
|21.33&lt;br /&gt;
|-&lt;br /&gt;
|01.06.08 - 01.11.08&lt;br /&gt;
|15.83&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Geschichte von DelphiGL.com==&lt;br /&gt;
===Die frühsten Anfänge===&lt;br /&gt;
Blickt man insbesondere vor das Jahr 2000 war die Grafikprogrammierung unter Delphi eine ziemlich frustrierende Angelegenheit. Nur sehr wenige Quellen waren überhaupt verfügbar, ganz zu schweigen von notwendigen Headern. Ein erste Etappe dieser Durststrecke war vermutlich das Erscheinen von DelphiX, dass sich binnen kurzer Zeit einer sehr großen Popularität erfreute. Der gemeinsame Treffpunkt hierfür war das alte Forum auf www.neobrothers.de. Prinzipiell machte die Community bis zu diesem Zeitpunkt nichts anderes als langsam zu wachsen und alle Varianten der Grafikprogrammierung durchzugehen. Vermutlich gab es damals kaum jemanden der nicht DelphiX, WdirectX oder diverse andere Header durchprobierte.&lt;br /&gt;
&lt;br /&gt;
Anfang 2002 kam es dann im Neobrothers-Forum zu einer Umfrage, ob man nicht ein Unterforum für OpenGL einrichten sollte. Zu diesem Zeitpunkt war mir (Phobeus) der Begriff OpenGL noch kaum ein Begriff. Da ich zu diesem Zeitpunkt jedoch zunehmend unzufriedener mit Direct3D wurde (Ständige Wechsel der API, zuviel Code für zu wenig Ergebnis etc.) riskierte ich einen Blick auf OpenGL und begann, mich damit auseinander zu setzen. Die Seite erster Wahl war damals für den OpenGL-Programmierer definitiv NeHe und erlaubte es mir, mich relativ schnell in OpenGL einzuarbeiten. Das Ergebnis beeindruckte mich: Wenige Wochen und man konnte fast das gleiche machen wie mit Direct3D, allerdings oftmals mit erheblich weniger Code und alleine die Tatsache, dass man mit ein paar glVertex-Aufrufen schnell Figuren bilden konnte, beeindruckte mich sehr.&lt;br /&gt;
&lt;br /&gt;
Zeitgleich nahm die Umfrage im Neobrothers-Forum ein Ende und mit nur wenigen Stimmen Vorsprung siegte die Direct3D-Fraktion und es wurde abgelehnt ein entsprechendes Unterforum einzurichten. Ich selbst war zu diesem Zeitpunkt über das Ergebnis ziemlich enttäuscht. Ebenso ein weiteres Mitglied aus dem Forum namens Sebo, den man streng genommen als geistigen Vater von DGL nennen muss.&lt;br /&gt;
&lt;br /&gt;
Ich selbst besaß damals ausreichend Webspace und unterhielt dort eine kleine Seite für einige Projekte meinerseits. Er fragte mich, ob man nicht dort dann ein Unterforum einrichten könnte. Ich selbst war ziemlich skeptisch darüber, da ich nicht glaubte, dass ein kleines Unterforum in meinem „Gästebuch“ wirklich Interessierte anlocken könnte. Ich wollte Nägel mit Köpfen machen und es wurde mir hier erstmals bewußt, dass ich unlängst OpenGL als meine künftige API gewählt habe und definitiv nicht mehr zu Direct3D zurück wollte. Nach einer kurzen Sammlung von Ideen, Plänen und dem Entschluss auch Tutorials anbieten zu wollen, ging am 1. April 2002 die Webseite http://dgl.thechaoscompany.net/ (nicht mehr im Besitz) ans Netz. Inhalt war eine kleinere rote Webseite (http://www.phobeus.de/hosting/olddgl/) mit einem Forum auf einem Lycos-Account. Das Projekt wurde DGL genannt (ist Jemandem schon aufgefallen wie unsinnig der Name ist? Deutsche/Delphi Gomputer/Graphic Libary/Community? *sg) und wurde allgemein mit einem herzhaften Lachen aufgenommen. Die Tatsache, dass ein Direct3D-Programmierer plante, mit einer neuen OpenGL-Seite am ersten April ans Netz zu gehen, schien etwas belustigendes zu haben.&lt;br /&gt;
&lt;br /&gt;
Was man über die Grafik-Community von Delphi im Jahre 2002 wissen sollte ist, dass Neobrothers.de ein zentrales Forum war in dem sich die Leute zum Sprechen trafen. Die Projekte selbst waren jedoch meist dezentral und jeder Entwickler / jedes Team werkelte im Stillen an seiner Arbeit herum. In der Tat beobachtete ich damals, dass viele Leute mehr Arbeit in Ihre Webseiten steckten als in die eigentliche Programmierung. DGL sollte anderes sein und ein wirkliches Portal sein. Warum muss jeder eine Webseite haben, die nur spärlich verlinkt ist, wenn es doch einen zentralen Ort geben kann an dem man das Wissen einfach zusammenträgt?&lt;br /&gt;
&lt;br /&gt;
Bereits Ende April hatte DGL rund 20 Besucher täglich und lag damit weit über dem, was wir anfangs geschätzt hatten. Die Folge davon war, dass das Forum auf Grund des „hohen“ Traffic oftmals abends bereits gar nicht mehr erreichbar war. PHP-Webspace war damals noch recht teuer. Also kam es u.a. dazu, dass das Forum von DGL zwischenzeitlich bei Untergrund-Spiele (dem alten unter Krawall-Hosting), quellcodes.de und einem Cobal-Server lag. Ganz vereinzelt findet man noch in sehr alten Dateien unsere alte URL: http://dgl.quellcodes.de/. Keine dieser Seiten existiert heute noch so.&lt;br /&gt;
&lt;br /&gt;
Bereits im Mai 2002 bekam ich eine ziemlich ernüchternde Mail von einem Entwickler, der mir bis dahin in der Szene nicht bekannt war: Lithander. Er ließ sich über das schreckliche Design der roten Seite aus und dass man da doch sicherlich etwas besser machen könnte. Tja... dauerte keinen Tag, da hatte er einen neuen Job und es entstand das Design von DGL, das bis heute auf dem Server liegt – wenngleich die Technik dahinter mehrfach überarbeitet wurde. Kurze Zeit darauf erhielt ich eine E-Mail von Delphic, der mir anbot ein Tutorial über Landschafts-Rendering zu schreiben. Kaum zu glauben, aber ich habe damals (auf Grund bisheriger Erfahrungen) das ganze für einen schlechten Scherz gehalten und bin umso mehr überrascht gewesen, als plötzlich wirklich ein Tutorial bei mir im Postfach lag. Bereits zu dieser Zeit war Sebo nicht mehr wirklich für DGL aktiv (deswegen findet man auch kaum etwas von ihm), allerdings wurden Lithander und Delphic ins Team aufgenommen.&lt;br /&gt;
&lt;br /&gt;
Von da an wuchs DGL mit einer ziemlichen Geschwindigkeit. Ich selbst kann nur darüber schmunzeln, dass wir einst mit 10 MB Traffic am Tag Probleme hatten, ein Jahr später wurde bereits die 1,5 GB-Grenze gesprengt. Inzwischen kommt das gesamte DGL-Netz auf knapp 20 GB Traffic. Oftmals blicke ich mit einer Träne im Auge zurück auf das alte DGL, das sehr familiär gewesen ist – bei dem sich die Mitglieder fast alle mehr oder minder noch persönlich kannten. Dies ist inzwischen wohl kaum mehr möglich und der logistische Aufwand für die Community ist erheblich gestiegen. Dennoch ist es schön zu sehen, dass auch noch bei einer solch großen Seite sehr viele Leute da sind, die ebenso wie zur Gründungszeit bereit sind etwas für die Community beizutragen.&lt;br /&gt;
&lt;br /&gt;
DGL ist eine Community die aus einer Laune heraus entstanden ist, als April-Scherz abgetan wurde und dennoch etwas sinnvolles wurde ;)&lt;br /&gt;
&lt;br /&gt;
===Legendäre Threads===&lt;br /&gt;
&lt;br /&gt;
Im DGL Forum wurden bereits viele interessante Themen diskutiert. Diese wurden im Artikel [[BestOfDGL]] gesammelt. Ein Blick hinein lohnt sich sicherlich.&lt;br /&gt;
&lt;br /&gt;
===Aprilscherze===&lt;br /&gt;
DGL selbst wurde ursprünglich selbst als Aprilscherz angesehen. Mittlerweile weiß man, dass es mehr war als ein Scherz.&lt;br /&gt;
Die Aprilscherze behalten aber ihren Stellenwert in der Community. Zwischen 0.00 und 1.00 Uhr erscheint an jedem 1. April ein erschreckender Newsbeitrag von Phobeus, der den Untergang des Abendlandes, zumindest aber sämtlicher Menschenrechte prophezeit bzw. als bereits vollzogen darstellt. Die News wird immer mit vielen Links zu echten Ereignissen und Schlagwörtern wie &amp;quot;CIA&amp;quot;, &amp;quot;NSA&amp;quot;, &amp;quot;EU-Kommission&amp;quot;, aber immer auch mit Bezug auf die OpenGL-Entwicklung (&amp;quot;GL_ARB_QAIDA&amp;quot;) gewürzt, so dass es einem zuerst beim Lesen, und dann nach der Auflösung und Präsentation der erschreckend harten Fakten kalt den Rücken herunterläuft.&lt;br /&gt;
&lt;br /&gt;
====Bisherige April-News====&lt;br /&gt;
1. April 2008: [http://www.delphigl.com/forum/viewtopic.php?t=7374 Breaking News: OpenGL heißt nun FGF] &lt;br /&gt;
:Phobeus verkündet die tolle Nachricht, dass sich Microsoft entschlossen habe DirectX mit OpenGL zusammen zu führen.&lt;br /&gt;
&lt;br /&gt;
1. April 2007: [http://www.delphigl.com/forum/viewtopic.php?t=6495 Investment opportunity für DGL] &lt;br /&gt;
:Phobeus entschließt sich DGL kostenpflichtig zu machen. Denn &amp;quot;Es kann [...] nicht sein, dass ich für meine Ausbildung bezahlen muss und gleichzeitig frei Wissen weitergebe&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
1. April 2006: [http://www.delphigl.com/forum/viewtopic.php?t=5398 Sicherheitsrichtlinie im Schnellverfahren]  &lt;br /&gt;
:Die NSA platziert Backdoors in fast allen Systemen, darunter die OpenGL-Extension &amp;quot;GL_ARB_QAIDA&amp;quot; - alle persönlichen Daten sollen im Klartext zu entsprechenden Stellen weitergeleitet werden...&lt;br /&gt;
&lt;br /&gt;
1. April 2005: [http://www.delphigl.com/forum/viewtopic.php?t=3993 Ein schwarzer Tag...] &lt;br /&gt;
:Softwarepatente machen fast alle Internetangebote von Open-Source-Gruppen illegal. Erste Homepages gehen bereits vom Netz.&lt;br /&gt;
&lt;br /&gt;
1. April 2003: [http://www.delphigl.com/forum/viewtopic.php?t=1745 Phobeus erklärt Rücktritt] &lt;br /&gt;
:Die Seite fabriziert zuviel Stress für Phobeus. Deshalb erklärte er seinen Rücktritt als Admin und wollte sich von nun an seiner neuen Leidenschaft &amp;quot;Datenbanken&amp;quot; zuwenden und dafür eine neue Comunity gründen: Die &amp;quot;Deutsche Datenbank-Programmierer Community&amp;quot; DDPC.&lt;br /&gt;
&lt;br /&gt;
===Die Community aktuell===&lt;br /&gt;
Seit Mitte 2005 kam neben '''OpenGL''' vor allem '''SDL''' als Thema in der DGL Community auf. Plattformunabhängige Programmierung wurde dadurch zunehmend häufiger ein Ziel der DGLer, was im Start der Übersetzung der [[SDL-Funktionsübersicht|SDL-Dokumentation im DGL-Wiki]] gipfelte.&lt;br /&gt;
&lt;br /&gt;
Des weiteren entwickelte sich DGL von einer &amp;quot;Randgruppen-Randgruppe&amp;quot; (Zitat: Phobeus) hin zu einem OpenGL-Forum, unabhängig welcher Sprache man den Vorzug gibt. Zwar sind die '''Delphi'''- bzw. '''FPC'''-Programmierer immer noch in der Überzahl (ca.60% Jan.2009), aber auch '''C++'''ler, '''C#'''- und '''Java'''-Programmierer sieht man häufiger. Neben der Vielfalt an Programmiersprachen herrscht auch eine große &amp;quot;kulturelle&amp;quot; Vielfalt. Neben 13jährigen Schülern, Mathematikstudenten und Berufsinformatikern aus Deutschland findet man auch Mitglieder aus dem deutsch und nichtdeutschsprachigen Ausland.&lt;br /&gt;
&lt;br /&gt;
2009 wurden erstmals die [[DGL_Award|DelphiGL Awards]] verliehen, um die Mitglieder auszuzeichnen, welche besonders gute Projekte, Projektpflege oder Communityarbeit geleistet haben.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
DGL ist aber nicht nur als Forum aktiv. Zur Zeit bestreitet DelphiGL.com 3 Großprojekte:&lt;br /&gt;
*'''[[Hauptseite|DGL-Wiki]]'''&lt;br /&gt;
:Das DGL-Wiki ist das wohl '''größte Projekt''' der DGL, denn es bündelt das Wissen vieler OpenGLer und stellt es in deutscher Sprache Interessierten zur Verfügung. (Sie befinden sich gerade im DGL-Wiki ;-)) Neben diesem altruistischen Effekt hilft das Wiki auch, die Wartbarkeit zu erhöhen. Folge dessen ist, dass Fehler, die von unseren Mitgliedern gefunden werden, sofort berichtigt werden können.&lt;br /&gt;
&lt;br /&gt;
:Im DGL-Wiki findet man unsere [[Tutorial]]s, [[OpenGL-Funktionsübersicht|OpenGL Funktionen]], [[Hintergrundwissen]], [[Link]]s und vieles vieles mehr. Auch eine Sammlung mit [[Shadersammlung|Shadern]] und [[Materialsammlung|Materialien]] ist vorhanden.&lt;br /&gt;
&lt;br /&gt;
*'''[[DGLSDK]]'''&lt;br /&gt;
:Der DGLSDK ist das '''hilfreichste Projekt''' der DGL-Comunity. Bereits 2003 war eine erste Version verfügbar, entwickelte sich aber nicht wie erhofft. Seit 2005 ist nun eine verbesserte und aktualisierte Version verfügbar, die Einsteigern in die OpenGL-Programmierung mit Delphi bzw. FPC alle nötigen Werkzeuge nicht nur an die Hand gibt, sondern auch gleich noch einrichtet. Mit dabei ist unter anderem der [[DGLOpenGL.pas|DGL-OpenGL Header]] welcher dem Delphi eigenen Header unbedingt vorzuziehen ist.&lt;br /&gt;
&lt;br /&gt;
*'''[[DGLOpenGL.pas]]'''&lt;br /&gt;
:Das '''nützlichste Projekt''' und gleichzeitig unser Aushängeschild ist der DGL OpenGL Header. Dieser ist innerhalb der Delphiszene für seine Aktualität und Nutzerfreundlichkeit bekannt. Seit Jahren bietet der DGL Header die Funktionen, die der original Delphi Header von Borland nie bieten konnte. Insbesondere unser Mitglied '''Lossy eX''' hat sich neben Anderen um die Weiterentwicklung und Pflege verdient gemacht.&lt;br /&gt;
&lt;br /&gt;
===Rund um DelphiGL===&lt;br /&gt;
&lt;br /&gt;
====DGL-Chat====&lt;br /&gt;
Schnelle Hilfe und ab und an auch Themenabende gibt es im DGL-Chat. Datailierte Informationen wo ihr ihn findet stehen im Artikel '''[[DGL-Chat]]'''. Für alle Chat unerprobten welche keinen IRC-Client auf ihrem Rechner haben, bietet DelphiGL.com auch einen browsergestützten Chatclient an.&lt;br /&gt;
&lt;br /&gt;
====Projekteecke====&lt;br /&gt;
Was herauskommen kann, wenn die Mitglieder von DelphiGL.com in die Tasten hauen, kann in der [[DGL Projekte|'''DGL Projekteecke''']] betrachtet werden. Auch wenn die Übersicht nur einen Teil der entstandenen Arbeiten zeigt, sind doch einige recht schöne Ergebnisse dabei.&lt;br /&gt;
&lt;br /&gt;
====DelpiGL kämpft gegen AIDS und Krebs====&lt;br /&gt;
DelphiGL hilft mit beim [http://www.worldcommunitygrid.org/ World Community Grid]. Diese Organisation stellt eine Software bereit mit der man seine ungenutzte Rechenzeit der Wissenschaft spenden kann. Das Programm läuft im Hintergrund und berechnet z.B. Wirkstoffmolekülstrukturen für AIDS-Medikamente. Das beste aber ist: euer Rechner läuft dadurch nicht langsammer, denn es wird nur ungenutzte Rechenzeit benutzt. Ladet euch doch einfach auch das Tool herunter.&lt;br /&gt;
&lt;br /&gt;
Nachdem ihr euch beim WCG registriert habt könnt ihr einem Team beitreten. Als DelphiGL-Supporter seid ihr in unserem Team (TeamID: &amp;quot;DGL&amp;quot;) natürlich herzlich willkommen. Wer sich für die '''Teamstatistik''' interessiert kann diese [http://www.worldcommunitygrid.org/team/viewTeamInfo.do?teamId=81JW9RQQGQ1 hier] finden.&lt;br /&gt;
&lt;br /&gt;
Mittlerweile wird DGL beim World Community Grid als &amp;quot;Partner&amp;quot; geführt.&lt;br /&gt;
&lt;br /&gt;
===Historie im Überblick===&lt;br /&gt;
Die nachfolgende Tabelle versucht, aus den Newsmeldungen die im Forum von DelphiGL.com zu finden sind, zumindest ausschnittsweise die Geschichte von DelphiGL.com zu rekonstruieren.&lt;br /&gt;
&lt;br /&gt;
[[Bild:DGL_Map.jpg|right|framed|Die [http://www.frappr.com/delphigl '''Original DGL-Map'''] gibt euch einen Überblick, wo die DGL-Mitglieder wohnen.]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} &lt;br /&gt;
!Datum||Mitglieder&amp;lt;br&amp;gt; bis ''Datum''||Veränderungen/Ereignisse &amp;lt;br&amp;gt; bis ''Datum''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.04.2002||0||DelphiGL wird gegründet&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.06.2002||13||Forum geht online&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.07.2002||22||erste OpenGL &amp;lt;-&amp;gt; Direct3D Schlammschlacht&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.08.2002||31||Member Forum&amp;lt;br&amp;gt;&lt;br /&gt;
Erste Idee Page ins englische zu übersetzen (per McClaw)&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.09.2002||42||Erster Umzug von DGL&amp;lt;br&amp;gt;&lt;br /&gt;
Spruch des Tages&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.10.2002||58||SchodMC wird Mod&amp;lt;br&amp;gt;&lt;br /&gt;
DGL-Upload-Center&amp;lt;br&amp;gt;&lt;br /&gt;
Poll&amp;lt;br&amp;gt;&lt;br /&gt;
Recent Uploads&amp;lt;br&amp;gt;&lt;br /&gt;
Featured Sites&amp;lt;br&amp;gt;&lt;br /&gt;
Bild der Woche&amp;lt;br&amp;gt;&lt;br /&gt;
Snippets&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.11.2002||78||TexturenTutorial&amp;lt;br&amp;gt;&lt;br /&gt;
Foren FAQ&lt;br /&gt;
&amp;lt;br&amp;gt;Poll Archiv&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.12.2002||87||DelphiGL.com Domain&amp;lt;br&amp;gt; &lt;br /&gt;
Kommentare zu Newsmeldungen&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.01.2003||106||Neues DGL Logo&amp;lt;br&amp;gt;&lt;br /&gt;
'''''100 Mitglieder-Marke erreicht'''''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.02.2003||123||Umzug auf neuen Server&amp;lt;br&amp;gt;&lt;br /&gt;
Sascha Willems (SonOfSatan / SOS) wird Mod&amp;lt;br&amp;gt;&lt;br /&gt;
Tutorials als CHM-Version&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.03.2003||136||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.04.2003||147||Bomberman Tutorial 2&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.05.2003||159||Projekteforum eingerichtet&lt;br /&gt;
&amp;lt;br&amp;gt;Phobeus stellt Firefox vor (damals Firebird)&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.06.2003||175||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.07.2003||196||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.08.2003||212||IE erkennt DGL als nicht vertrauensvoll ;-)&amp;lt;br&amp;gt;&lt;br /&gt;
Flooding durch MS-Bots&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.09.2003||223||Ausfall der Domain&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.10.2003||245||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.11.2003||265||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.12.2003||277||Erster IRC-Chat&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.01.2004||296||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.02.2004||308||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.03.2004||323||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.04.2004||347||Borland Developer Network und &lt;br /&gt;
Code Central News&amp;lt;br&amp;gt;&lt;br /&gt;
W32.Beagle.J@MM Wurm nimmt DGL-Identität an.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.05.2004||361||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.06.2004||378||dglOpenGL.pas - Version 1.4&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.07.2004||403||'''DGL Wiki gestartet'''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.08.2004||421||Atom Feed&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.09.2004||438||dglOpenGL.pas - Version 1.4B&amp;lt;br&amp;gt;'''DGL Wiki hat 100 Artikel'''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.10.2004||451||dglOpenGL.pas goes FreePascal&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.11.2004||469||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.12.2004||493||.Net Forum&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.01.2005||512||dglOpenGL.pas - Version 1.6&amp;lt;br&amp;gt;&lt;br /&gt;
'''''500 Mitglieder-Marke erreicht'''''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.02.2005||531||dglOpenGL.pas - Version 1.7&amp;lt;br&amp;gt;'''DGL Wiki hat 250 Artikel'''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.03.2005||552||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.04.2005||570||Sascha Willems (&amp;gt;4000 Beiträge) verabschiedet sich aus dem Forum.&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.05.2005||586||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.06.2005||604||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.07.2005||617||DGLSDK 2005.1&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.08.2005||635||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.09.2005||661||Quake3Delphi&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.10.2005||677||Diskussion zum Thema &amp;quot;Windows Vista &amp;amp; OpenGL&amp;quot;&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.11.2005||705||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.12.2005||729|| '''DGL Wiki hat 500 Artikel'''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.01.2006||767|| '''DGL Wiki Phasen 1 u. 2 abgeschlossen'''&amp;lt;br&amp;gt; Weihnachtsaktion: Portierung der DGL-Tutorials ins Wiki &amp;lt;br&amp;gt; DGL-Mitglieder starten DGL-Map bei &amp;quot;Frappr.com&amp;quot;&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.02.2006||797||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.03.2006||832|| Borland will sich von seiner IDE-Sparte trennen&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.04.2006||863|| Windows Vista soll nun doch OpenGL voll unterstützen&amp;lt;br&amp;gt;'''Wiki Phase III abgeschlossen''' &amp;lt;br&amp;gt; '''Wiki Phase V vorzeitig abgeschlossen'''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.05.2006||891|| SGI beantragt Gläubigerschutz&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.06.2006||912|| Neuer DGL Poll&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.07.2006||933|| DGLSDK 2006.1&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.08.2006||950|| Serverumzug (größte Wartungsarbeiten seit Gründung von DGL)&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.09.2006||977|| Änderungen im DelphiGL Team&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.10.2006||991|| Turbodelphi erscheint&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.11.2006||1021|| DGL wird Partner des World Community Grids&amp;lt;br&amp;gt;&lt;br /&gt;
'''''1000 Mitglieder-Marke erreicht'''''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.12.2006||1045||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.01.2007||1067|| Tutorial Raytracing Grundlagen&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.02.2007||1106|| Tutorial Raytracing Grundlagen 2 &amp;lt;br&amp;gt; DOS Angriff auf DelphiGL&amp;lt;br&amp;gt;'''Wiki Phase VI vorzeitig abgeschlossen'''&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.03.2007||1131|| SDL_Rwops Tutorial&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.04.2007||1164||  [[DGL_Projekte]]&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.05.2007||1182|| DGLOpenGL.pas V 2.1&amp;lt;br&amp;gt;[[BestOfDGL]]&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.06.2007||1201|| &lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.07.2007||1223||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.08.2007||1248||&amp;quot;Spekulationen über OpenGL3.0&amp;lt;br&amp;gt;Tutorial_Softwareentwicklung3&amp;quot;&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.09.2007||1261||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.10.2007||1284||'''DGL Wiki hat 750 Artikel'''&amp;lt;br&amp;gt;Tutorial_Kollisionserkennung&amp;lt;br&amp;gt;Tutorial Framebufferobject&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.11.2007||1309||Forenstruktur überarbeitet&amp;lt;br&amp;gt;Tutorial Wassereffekt&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.12.2007||1330||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.01.2008||1347||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.02.2008||1372||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.03.2008||1393||DGL Suche für Firefox&amp;lt;br&amp;gt;1. Kollisionstutorial&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.04.2008||1411||Bundesverfassungsgericht erklärt Sicherheit gespeicherter Daten zum Grundrecht&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.05.2008||1437||2. Kollisionstutorial&amp;lt;br&amp;gt;OpenAL Übersicht offiziell als Wikiteil vorgestellt&amp;lt;br&amp;gt;UTF8 Umstellung des Forums gescheitert&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.06.2008||1452||Borland verkauft seine Entwicklungstools (CodeGear)&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.07.2008||1466||3. Kollisionstutorial&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.08.2008||1479||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.09.2008||1499||Erste Lebenszeichen von OpenGL3.0&amp;lt;br&amp;gt;Shadersammlung im Wiki&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.10.2008||1514||SGI stellt OpenGL Quellcode unter echte OSS Lizenz&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.11.2008||1532||&lt;br /&gt;
|- align = &amp;quot;center&amp;quot;&lt;br /&gt;
|01.12.2008||1546||Start der Überarbeitung/Aktualisierung der Einsteigertutorials&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Links==&lt;br /&gt;
[[DGLOpenGL.pas|Link zum OpenGL Header von DelphiGL.]]&lt;br /&gt;
&lt;br /&gt;
[http://www.delphiGL.com http://www.DelphiGL.com - Heimat der DGLer]&lt;br /&gt;
&lt;br /&gt;
[http://www.frappr.com/delphigl Link zur DGL_Map]&lt;br /&gt;
&lt;br /&gt;
[[DGL Projekte|Link auf die DGL Projekteecke]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial_StereoSehen&amp;diff=23923</id>
		<title>Tutorial StereoSehen</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial_StereoSehen&amp;diff=23923"/>
				<updated>2009-07-23T15:06:17Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Stereo einmal sehen statt hören=&lt;br /&gt;
[[Bild:Tutorial_Stereo_anaglyph.jpg|center]]&lt;br /&gt;
==Einleitung==&lt;br /&gt;
Viele Tiere haben mit dem Menschen eins gemein: Zwei Augen. Dies kann unterschiedliche Vorteile haben, etwa in zwei Richtungen gleichzeitig sehen zu können, oder, was viel häufiger ist, um räumlich sehen zu können. Die Welt aus zwei leicht unterschiedlichen Blickwinkeln zu sehen ermöglicht es dem Gehirn Abstände und Geschwindigkeiten besser einzuschärtzen, als mit einem Auge. Das es uns auch mit einem Auge gelingt, erkennt man dran, dass das in begrenztem Umfang auch bei Fotos gelingt und wenn wir mit einem geschlossenem Auge durch ein Zimmer laufen trotzdem nicht überall anstossen. Das funktioniert sogar so gut, dass Menschen, die nur stark eingeschränkt oder gar nicht räumlich sehen können, dies gar nicht so selten erst bei Routineuntersuchungen von Augenärzten oder im Verlauf ihrer Musterung erfahren.&lt;br /&gt;
&lt;br /&gt;
An einer Stelle ist es jedoch egal, ob wir räumlich sehen können oder nicht - beim Spielen und Arbeiten am Computer. Aber 3D Spiele wollen doch gerade eines: uns die Welt möglichst realistisch vor Augen führen. Leider hat der Computer meist nur einen Monitor, wir aber zwei Augen... Und damit Good Bye räumliches Sehen? Nein, nein, so einfach dürfen wir uns nicht geschlagen geben. Tatsächlich fallen mir gleich eine Reihe von Möglichkeiten ein: Stereogramme, wie sie eine Zeit lang modern waren, und in vielen Büchern vorkommen: langes Stieren auf stylisch eingefärbte Buchseiten. Bei 3D-Spielen waren eine Zeit lang 3D-Shutterbrillen beliebt, bei denen jeweils ein Auge abgedunkelt wird, auf dem Monitor für das Auge ein Bild angezeigt und dann gewechselt wird. Zeigt man für jedes Auge ein leicht versetztes Bild an und wechselt die Bilder häufig genug, entsteht für den Betrachter ein 3-Dimensionales Bild der Szenerie. Leider benötigt man für diese Technik schnell schaltende Röhrenmonitore - mit aktuellen TFT Monitoren ist dies, wegen ihrer langsamen Schaltgeschwindigkeiten nicht möglich und statt eines 3D-Bildes entsteht irgend ein wenig aussagekräftiges Geschmiere.&lt;br /&gt;
&lt;br /&gt;
Das ist noch immer kein Grund, entmutigt zu sein: In Kinofilmen wird noch heute oft die Technik der Anaglyphe eingesetzt. Dabei muss der Betrachter eine 3D-Brille aufsetzen, die vor jedes Auge einen anderen Farbfilter setzt, etwa rot und grün. Bei der Filmaufnahme werden dann zwei überkreuzt filmende Kameras verwendet.&lt;br /&gt;
&lt;br /&gt;
Der 3D Effekt stellt sich bei den meisten Menschen schnell ein, bei Anderen dauert es ein wenig oder erfordert etwas Übung. Den Effekt gar nicht geniessen können üblicherweise nur stark Schielende, Einäugige und Blinde. Eine wesentliche Einschränkung bei diesem Verfahren ist jedoch, dass das entstehende Bild meist einfarbig, ähnlich einem s/w Film, ist. Der entstehende 3D Effekt gleicht dieses Manko meiner Ansicht nach auf alle Fälle aus - und da wir möglichst Niemanden ausschliessen möchten, unsere Programme zu bestaunen, werden wir unsere Programme sowohl für &amp;quot;normale&amp;quot; Grafikausgabe als auch für 3D-Brillen vorbereiten.&lt;br /&gt;
&lt;br /&gt;
==Die 3D-Brille==&lt;br /&gt;
Jeder der weitermachen möchte, sollte sich spätestens hier eine 3D-Brille besorgen. Diese gibts z.B. beim Optiker und sollte möglichst einen roten und einen grünen Filter besitzen. Zur Not tuts auch rot-blau, ist jedoch wegen den stark auseinanderliegenden Wellenlängen des roten und blauen Lichtes weniger gut geeignet. Einigen Büchern zu optischen Täuschungen liegen ebenfalls Brillen bei. Solltet ihr keine passende, vorgefertigte Brille finden, könnt ihr sie auch mit etwas Pappe oder Karton und Farbfolien aus dem Bastelladen selbst bauen - oder ganz nobel: mit Filtern aus dem Fotoladen statt ordinären Farbfolien. &lt;br /&gt;
[[Bild:Tutorial_Stereo_brille.png|center]]&lt;br /&gt;
&lt;br /&gt;
==Projektionen==&lt;br /&gt;
Bei der üblichen, perspektivischen Projektion ist die Sache einfach: Man hat ein Auge, einen Öffnungswinkel für die Kamera und die Entfernung für die nahe Clipping-Ebene: &lt;br /&gt;
[[Bild:Tutorial_Stereo_perspektivisch.png|center]]&lt;br /&gt;
&lt;br /&gt;
Beim Stereo-Sehen wird die Sache ein Wenig komplizierter. Da man mit Beiden Augen auf die Projektionsebene Bildschirm schaut, ist diese für beide Augen identisch, jedoch sind die Blickkegel nicht mehr gerade, sondern schief:&lt;br /&gt;
[[Bild:Tutorial_Stereo_stereo.png|center]]&lt;br /&gt;
&lt;br /&gt;
Zu allem überfluss können wir unsere Augen auch noch auf eine bestimmte Entfernung ausrichten, d.h. die Ebene, auf die die Augen eingestellt sind, muss nicht der Entfernung der nahen Clippling-Plane entsprechend - das Problem können wir jedoch ganz einfach mithilfe der Strahlensätze lösen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;...&lt;br /&gt;
var&lt;br /&gt;
  zNear, zFar, Oeffnungswinkel, Augenabstand, Zielweite : Single;&lt;br /&gt;
...&lt;br /&gt;
const&lt;br /&gt;
  PBufSize = 1024; //Seitenläne des PBuffers&lt;br /&gt;
var&lt;br /&gt;
  SVerh, ROeffnung : Single;&lt;br /&gt;
  Breitenhaelfte, NeardZielweite : Single;&lt;br /&gt;
  left, right, top, bottom : Single;&lt;br /&gt;
&lt;br /&gt;
  procedure CalcValues;&lt;br /&gt;
  begin&lt;br /&gt;
    ROeffnung := DegToRad(Oeffnungswinkel / 2); //Halber Öffnungswinkel in RAD&lt;br /&gt;
    Breitenhaelfte := zNear * Tan(ROeffnung); //Halbe Breite der Proj. Ebene&lt;br /&gt;
    NeardZielweite := zNear / Zielweite; &lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
begin&lt;br /&gt;
  if Opt.Stereo then //Stereo Modus&lt;br /&gt;
  begin&lt;br /&gt;
    glViewport(0, 0, ClientWidth, ClientHeight);&lt;br /&gt;
    //Projektionsmatrix resetten&lt;br /&gt;
    glMatrixMode(GL_PROJECTION);&lt;br /&gt;
    glLoadIdentity();&lt;br /&gt;
&lt;br /&gt;
    SVerh := ClientWidth/ClientHeight; //Breite zu Höhe&lt;br /&gt;
    CalcValues;&lt;br /&gt;
    &lt;br /&gt;
    //Ränder der Projektionsebene für glFrustum&lt;br /&gt;
    left := - SVerh * Breitenhaelfte - 0.5 *Augenabstand*NeardZielweite;&lt;br /&gt;
    right := SVerh * Breitenhaelfte - 0.5 *Augenabstand*NeardZielweite;&lt;br /&gt;
    top := Breitenhaelfte;&lt;br /&gt;
    bottom := -Breitenhaelfte;&lt;br /&gt;
    glFrustum(left, right, bottom, top, zNear, zFar);&lt;br /&gt;
&lt;br /&gt;
    glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
&lt;br /&gt;
    //PBuffer erzeugen und aktivieren, wenn noch nicht geschehen&lt;br /&gt;
    if not Assigned(PBuffer) then&lt;br /&gt;
    begin&lt;br /&gt;
      PBuffer := TPixelBuffer.Create(PBufSize, PBufSize, DC, RC, Self);&lt;br /&gt;
      wglShareLists(RC, PBuffer.RC);&lt;br /&gt;
      PBuffer.Enable;&lt;br /&gt;
      InitGl;&lt;br /&gt;
    end&lt;br /&gt;
    else&lt;br /&gt;
      PBuffer.Enable;&lt;br /&gt;
&lt;br /&gt;
    glViewport(0, 0, PBufSize, PBufSize);&lt;br /&gt;
    //Projektionsmatrix resetten&lt;br /&gt;
    glMatrixMode(GL_PROJECTION);&lt;br /&gt;
    glLoadIdentity();&lt;br /&gt;
&lt;br /&gt;
    //Diesmal das Frustum in die andere Richtung schiefstellen(+ statt -)&lt;br /&gt;
    left := - SVerh * Breitenhaelfte + 0.5 *Augenabstand*NeardZielweite;&lt;br /&gt;
    right := SVerh * Breitenhaelfte + 0.5 *Augenabstand*NeardZielweite;&lt;br /&gt;
    top := Breitenhaelfte;&lt;br /&gt;
    bottom := -Breitenhaelfte;&lt;br /&gt;
    glFrustum(left, right, bottom, top, zNear, zFar);&lt;br /&gt;
&lt;br /&gt;
    glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
&lt;br /&gt;
    PBuffer.Disable;&lt;br /&gt;
  end&lt;br /&gt;
  else&lt;br /&gt;
  begin&lt;br /&gt;
    //Normale Ansicht&lt;br /&gt;
    glViewport(0, 0, ClientWidth, ClientHeight);&lt;br /&gt;
    //Projektionsmatrix resetten&lt;br /&gt;
    glMatrixMode(GL_PROJECTION);&lt;br /&gt;
    glLoadIdentity();&lt;br /&gt;
    //Perspektivische Darstellung&lt;br /&gt;
    SVerh := ClientWidth/ClientHeight;&lt;br /&gt;
    CalcValues;&lt;br /&gt;
    //Hier wird nichts verschoben&lt;br /&gt;
    left := - SVerh * Breitenhaelfte;&lt;br /&gt;
    right := SVerh * Breitenhaelfte;&lt;br /&gt;
    top := Breitenhaelfte;&lt;br /&gt;
    bottom := -Breitenhaelfte;&lt;br /&gt;
    glFrustum(left, right, bottom, top, zNear, zFar);&lt;br /&gt;
&lt;br /&gt;
    glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
&lt;br /&gt;
  end;&lt;br /&gt;
end;&lt;br /&gt;
...&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Und Rendern?==&lt;br /&gt;
Nun müssen wir nur noch zwei Bilder anzeigen. Die einfachste Möglichkeit dürfte sein, ein Bild für das linke Auge in einen PBuffer oder sonstige Textur zu rendern, dann das Bild für das rechte Auge in den Hintergrundpuffer. Der Inhalt des PBuffers wird dann mittels Blending auch in den Hintergrundpuffer gezeichnet und voila. Wir haben zwei verschiedene Bilder auf dem Schirm. Zu beachten ist noch, dass die Farben mittels [[glColorMask]] beim Rendern maskiert werden müssen - wir wollen ja für die beiden Augen unterschiedliche Farben anzeigen. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source lang=&amp;quot;pascal&amp;quot;&amp;gt;procedure TStereoForm.Render;&lt;br /&gt;
  procedure RenderScene;&lt;br /&gt;
  begin&lt;br /&gt;
    //kein glLoadIdentity am Anfang! Das muss vorher gemacht worden sein -&lt;br /&gt;
    //für die Augen muss ja bereits verschoben worden sein. Also Achtung.&lt;br /&gt;
    //Brav mit Push und Pop Matrix arbeiten.&lt;br /&gt;
    ...&lt;br /&gt;
  end;&lt;br /&gt;
&lt;br /&gt;
var&lt;br /&gt;
  Error : glUInt;&lt;br /&gt;
begin&lt;br /&gt;
  if (Opt.Stereo) and (Assigned(PBuffer)) then&lt;br /&gt;
  begin&lt;br /&gt;
    //Stereo Modus&lt;br /&gt;
    PBuffer.Enable;&lt;br /&gt;
    glClearColor(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
    glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
    glTranslatef(Augenabstand/2, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    //linkes Auge bekommt grün und blau - das sollte über Optionen wählbar sein&lt;br /&gt;
    glColorMask(false, true, true, true);&lt;br /&gt;
    RenderScene;&lt;br /&gt;
    PBuffer.Disable;&lt;br /&gt;
&lt;br /&gt;
    glClearColor(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
    glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
    glTranslatef(-Augenabstand/2, 0, 0);&lt;br /&gt;
&lt;br /&gt;
    //rechtes Auge bekommt nuir rot&lt;br /&gt;
    glColorMask(true, false, false, true);&lt;br /&gt;
    RenderScene;&lt;br /&gt;
&lt;br /&gt;
    //Und zusammenblenden&lt;br /&gt;
    glColorMask(true, true, true, true);&lt;br /&gt;
    glDepthFunc(GL_ALWAYS);&lt;br /&gt;
    glMatrixMode(GL_PROJECTION);&lt;br /&gt;
      glPushMatrix;&lt;br /&gt;
      glLoadIdentity;&lt;br /&gt;
      glOrtho(0, 1, 1, 0, -1.0, 1.0);&lt;br /&gt;
&lt;br /&gt;
      glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
      glLoadIdentity;&lt;br /&gt;
&lt;br /&gt;
      glDisable(GL_LIGHTING);&lt;br /&gt;
      glEnable(GL_TEXTURE_2D);&lt;br /&gt;
      PBuffer.Bind;&lt;br /&gt;
      glEnable(GL_BLEND);&lt;br /&gt;
      glBlendFunc(GL_ONE, GL_ONE);&lt;br /&gt;
      glBegin(GL_QUADS);&lt;br /&gt;
        glTexCoord2f(1, 0); glVertex2f(1,1);&lt;br /&gt;
        glTexCoord2f(1, 1); glVertex2f(1,0);&lt;br /&gt;
        glTexCoord2f(0, 1); glVertex2f(0,0);&lt;br /&gt;
        glTexCoord2f(0, 0); glVertex2f(0,1);&lt;br /&gt;
      glEnd();&lt;br /&gt;
      glDisable(GL_BLEND);&lt;br /&gt;
&lt;br /&gt;
      glEnable(GL_LIGHTING);&lt;br /&gt;
      glDisable(GL_TEXTURE_2D);&lt;br /&gt;
      PBuffer.Release;&lt;br /&gt;
&lt;br /&gt;
      glMatrixMode(GL_PROJECTION);&lt;br /&gt;
      glPopMatrix;&lt;br /&gt;
    glMatrixMode(GL_MODELVIEW);&lt;br /&gt;
    glDepthFunc(GL_LESS);&lt;br /&gt;
  end&lt;br /&gt;
  else&lt;br /&gt;
  begin&lt;br /&gt;
    //&amp;quot;Mono&amp;quot; Modus&lt;br /&gt;
    glClearColor(0.0, 0.0, 0.0, 0.0);&lt;br /&gt;
    glClear(GL_DEPTH_BUFFER_BIT or GL_COLOR_BUFFER_BIT);&lt;br /&gt;
&lt;br /&gt;
    glLoadIdentity;&lt;br /&gt;
    RenderScene;&lt;br /&gt;
  end;&lt;br /&gt;
  ...&lt;br /&gt;
end;&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Und 3D-Shutterbrillen?==&lt;br /&gt;
Wer eine 3D-Sutterbrille und entsprechendes Equipment zuhause hat, kann seine Anwendungen auch für diese anpassen. Einige Grafikkarten haben bereits passende Treiber, die die Ausgabe der Programme automatisch anpassen. Wer das nicht will, sollte sich einmal mit Stereo-OpenGl auseinandersetzen. Bei der dglOpenGl genügt es, den Rendering Context mit der Option opStereo zu erstellen. Mit [[glDrawBuffer]]('''GL_BACK_LEFT'''/'''GL_BACK_RIGHT''') kann dann für jedes Auge in einen anderen Puffer gerendert werden.&lt;br /&gt;
&lt;br /&gt;
==Abschluss==&lt;br /&gt;
Ich hoffe euch hat dieser kleine Exkurs gefallen. Vielleicht läuft einem ja mal das eine oder andere Programm über den Weg, wo man die Wahl zwischen Tiefensehen und normaler Ansicht hat - mich würde es jedenfalls freuen, zumal es ja nicht wirklich schwer ist, seine Programme entsprechend anzupassen und es doch ein wesentlich anderes Gefühl der Szene erzeugt, als üblicherweise vor dem Computer. Ich bin jedenfalls gespannt, erwarte mir aber nicht allzuviel - bislang war das Feedback und eure Demos ja sehr bescheiden. Wo ich da nur immer die Motivation hernehme, euch mit ein paar neuen Ideen zu versorgen? ;-D&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Euer Delphic&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Kleine Anmerkung am Rande==&lt;br /&gt;
Nach Fertigstellung des Tutorials wurde ich darauf aufmerksam gemacht, daß man um den Einsatz des P-Buffers herumkommt - was Geschwindigkeit und Kompatibilität erhöht. Man muss nur zwischen den glColorMask Befehlen einmal den Tiefenpuffer leeren. In etwa läuft das ganze dann wie folgt:&lt;br /&gt;
&lt;br /&gt;
         private void RenderMono()&lt;br /&gt;
         {&lt;br /&gt;
             RenderSettings rs = new RenderSettings();&lt;br /&gt;
             rs.Mono(RenderPanel.ClientRectangle.Width, RenderPanel.ClientRectangle.Height);&lt;br /&gt;
 &lt;br /&gt;
             GL.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);&lt;br /&gt;
             //Szene Rendern&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         private void RenderStereo()&lt;br /&gt;
         {&lt;br /&gt;
             GL.Clear(GL.COLOR_BUFFER_BIT | GL.DEPTH_BUFFER_BIT);&lt;br /&gt;
 &lt;br /&gt;
             RenderSettings rs = new RenderSettings();&lt;br /&gt;
             rs.Stereo(true, RenderPanel.ClientRectangle.Width, RenderPanel.ClientRectangle.Height);&lt;br /&gt;
             GL.ColorMask(1, 0, 0,1);&lt;br /&gt;
             //Szene Rendern&lt;br /&gt;
 &lt;br /&gt;
             rs.Stereo(false, RenderPanel.ClientRectangle.Width, RenderPanel.ClientRectangle.Height);&lt;br /&gt;
             GL.Clear(GL.DEPTH_BUFFER_BIT);&lt;br /&gt;
             GL.ColorMask(0, 1, 1,1);&lt;br /&gt;
             //Szene Rendern&lt;br /&gt;
 &lt;br /&gt;
 &lt;br /&gt;
             if (GL.GetError() != GL.NO_ERROR)&lt;br /&gt;
             {&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
         private void Render()&lt;br /&gt;
         {&lt;br /&gt;
             if (rc != null)&lt;br /&gt;
             {&lt;br /&gt;
                 GL.PushAttrib(GL.ALL_ATTRIB_BITS);&lt;br /&gt;
                 GL.ClearColor(0.0f, 0f, 0f, 1f);&lt;br /&gt;
                 if (stereo)&lt;br /&gt;
                     RenderStereo();&lt;br /&gt;
                 else&lt;br /&gt;
                     RenderMono();&lt;br /&gt;
                 rc.SwapBuffers();&lt;br /&gt;
                 GL.PopAttrib();&lt;br /&gt;
             }&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
Die rs.stereo(true/false, ...) Befehle laden die benötigten Matrizen für das linke bzw. rechte Auge.&lt;br /&gt;
&lt;br /&gt;
== Dateien ==&lt;br /&gt;
* {{ArchivLink|file=tut_stereo_delphi_vcl|text=Delphi-VCL-Quelltext zum Tutorial}}&lt;br /&gt;
&lt;br /&gt;
{{TUTORIAL_NAVIGATION|[[Tutorial_StencilSpiegel]]|[[Tutorial_Alphamasking]]}}&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:Tutorial|StereoSehen]]&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	<entry>
		<id>https://wiki.delphigl.com/index.php?title=Tutorial&amp;diff=23922</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://wiki.delphigl.com/index.php?title=Tutorial&amp;diff=23922"/>
				<updated>2009-07-23T15:05:36Z</updated>
		
		<summary type="html">&lt;p&gt;Delphic: -&amp;gt;Delphic&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Auf dieser Seite findet ihr alle Tutorials die DelphiGL.com zu bieten hat. Falls ihr zu einem Thema kein Tutorial findet könnt ihr noch einen Blick auf die [[Techniken und Algorithmen]] werfen. Diese enthalten weitere Artikel zu bestimmten Techniken.&lt;br /&gt;
&lt;br /&gt;
=Hinweise=&lt;br /&gt;
Bitte tragt selbst '''keine''' eigenen Tutorials ohne Absprache mit [[Benutzer:Flash (Kevin Fleischer)|Flash]] bzw. [[Benutzer:Phobeus|Phobeus]] hier ein. Tutorials werden prinzipiell vom DGL-Team gegengelesen, ''bevor'' sie veröffentlicht werden.&lt;br /&gt;
&lt;br /&gt;
Wer mit dem Gedanken spielt, ein Tutorial für DGL zu schreiben, sollte sich bereits bei der Themenwahl mit dem DGL-Team absprechen. DGL ist sehr an neuen Tutorials interessiert. Nur sollte man beachten, dass nichts doppelt geschrieben wird, bzw. dass nicht 2 Mann zur selben Zeit das selbe Thema beackern.&lt;br /&gt;
&lt;br /&gt;
==Hinweis für alle Programmieranfänger==&lt;br /&gt;
Falls ihr OpenGL nutzen wollt aber noch keinerlei Programmiererfahrung habt, so solltet ihr zuerst eine Programmiersprache lernen.&lt;br /&gt;
&lt;br /&gt;
DGL kann folgende Tutorials empfehlen:&lt;br /&gt;
&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!Link&lt;br /&gt;
!Sprache&lt;br /&gt;
!Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
|[http://www.delphi-treff.de/tutorials/ Delphitutorials bei www.delphi-treff.de]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Delphi Source der Delphi Treff entstand durch den Zusammenschluss von Delphi-Source und dem Delphi-Treff und wurde mittlerweile wieder in Delphi-Treff umbenannt. Diese Community verfügt über eine ausgezeichnete Sammlung von Tutorials zum Thema &amp;quot;Delphiprogrammierung&amp;quot;. Es werden nicht nur die Grundlagen erklärt sondern nahezu alle Bereiche der Programmierung mit Delphi. Außerdem verfügt diese Community über ein Forum welches mit seiner ''Bastelecke'' auch für Anfänger geeignet ist.&lt;br /&gt;
|-&lt;br /&gt;
|[http://crashkurs.christian-stelzmann.de/ Crashkurs von Christian Stelzmann]&lt;br /&gt;
|{{Deutsch}}&lt;br /&gt;
|Der Crashkurs von Christian erklärt neben den Grundlagen zur und über die Sprache auch die IDE anhand von zahlreichen einfachen Beispielen, die den Einstieg in Delphi stark vereinfachen und so eine einfache Einführung in die Arbeit mit Delphi bieten.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
''Wer sehen möchte was DGLer aus dem hier Gelernten und ihrer Kreativität so machen, findet Beispiele davon in der [[DGL_Projekte]]-Ecke.''&lt;br /&gt;
&lt;br /&gt;
=Tutorials=&lt;br /&gt;
{{Hinweis|Alle Tutorials sind der [[:Kategorie:Tutorial]] zugeordnet.}}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Schwierigkeitsgrad&lt;br /&gt;
!Bedeutung&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_1}} &lt;br /&gt;
|Jeder Schritt wird ausführlich erklärt. Absolut Einsteigertauglich.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_2}} &lt;br /&gt;
|Verständnis der Grundprinzipien wird vorraus gesetzt. Die Materie bleibt aber einfach.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_3}}&lt;br /&gt;
|Ihr wisst um was es geht. Es wird erwartet, dass ihr selbst das Thema weiterdenkt.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_4}}  &lt;br /&gt;
|Das Tutorial bietet euch einen Einstieg. Es wird erwartet, dass ihr euch selbst noch eingehender mit den beschriebenen Techniken befasst. Für Fragen steht unser Forum zur Verfügung.&lt;br /&gt;
|-&lt;br /&gt;
|{{Level_5}}  &lt;br /&gt;
|Um das Tutorial zu verstehen werden Kenntnisse auf dem entsprechenden Gebiet vorrausgesetzt, welche über Grundwissen hinausgehen. Es wird erwartet, dass ihr euch eingehender mit dem Thema auseinandersetzt und auch andere Quellen lest/gelesen habt. Für Fragen steht unser Forum zur Verfügung.&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Einsteiger-Tutorials ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{{Hinweis|Die Einsteiger-Tutorials wurden auf [[SDL]] umgestellt. Dadurch wurde das Laden von Texturen erleichtert, vor allem aber ermöglicht SDL plattformunabhängig zu programmieren. Ihr benötigt deshalb die ''SDL.pas''. Diese Datei und alle anderen benötigten Dateien findet ihr im '''[[DGLSDK]]'''}}&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Quickstart]] (VCL)&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion1.gif|right]] &amp;quot;Quickstart: OpenGL &amp;amp; Delphi&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Für alle, die einen schnellen Einstieg in die OpenGL Programmierung mit Delphi suchen, hat Flash hier einen Einstieg geschaffen. Neben dem erstellen eines eigenen OpenGL-Templates hat er für alle, die Großes mit OpenGL vorhaben, am Ende noch einige Hinweise bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
''In diesem Tutorial wird eine Codevorlage für OpenGL-Projekte geschaffen. Diese basiert allerdings auf Borlands Visual Component Library (VCL) und nicht auf SDL. '''Unabhängig davon beherbergt dieses Tutorial im 2. Teil einige allgemeingültige Hinweise für OpenGL-Anfänger.''' Wer nicht mit SDL arbeitet weil z.B. Plattformunabhängigkeit nicht gewünscht oder durch die Sprache bereits gegeben ist, kann diese Codebasis leicht auf seine Sprache übertragen.''&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 1]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion1.gif|right]] &amp;quot;Nicht zu weit aus dem Fenster lehnen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Dieses Tutorial von Magellan ist für alle Neueinsteiger gedacht. Hier werden Grundlagen von &amp;quot;Was ist OpenGL&amp;quot; bis zu &amp;quot;Wie initialisiere ich OpenGL?&amp;quot; besprochen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 2]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion2.jpg|right]] &amp;quot;Entdeckung einer neuen Welt&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Unter dieser Überschrift empängt euch Phobeus zu eurem ersten OpenGL Tutorial welches sich mit der Anwendung der OpenGL-API befasst.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 3]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion3.gif|right]] &amp;quot;Eine Welt des Grauens?&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Hinter diesem Titel verbirgt sich ein Einsteigertutorial zum Thema Matrizen in OpenGL. Wiederum führt euch Phobeus durch den Stoff.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 4]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion4.png|right]] &amp;quot;Texturen, Tapeten und Ihre Tücken&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Wie bekomme ich ein Bild auf meine Primitiven? Wer sich diese Frage bei den vorigen Tutorials gestellt hat, der bekommt hier nun von Phobeus die Antworten.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 5]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion5.jpg|right]] &amp;quot;Artenvielfalten und Ihre Folgen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial geht Phobeus auf weitere Zeichentechniken und Methoden zur Verbesserung der Performance unter OpenGL ein.&lt;br /&gt;
|-&lt;br /&gt;
!''Tutorial Lektion 6 ''&lt;br /&gt;
|[[Bild:Tutorial_na.jpg|right]] &amp;quot;Dark Engine&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Dieses Tutorial wurde geplant aber niemals umgesetzt. Heute hätte es auch keine Relevanz mehr, da die Dark Engine nicht gepflegt wurde. Falls ihr ein gutes Einsteigertutorial als Ersatz vorschlagen wollt, könnt ihr dies im Feedback-Forum von DelphiGL.com tun.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 7]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion7.png|right]] &amp;quot;Verblendet!&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Wenn man halbdurchsichtige Fensterscheiben, Lightmaps oder etwas ähnliches in sein Projekt einbauen will, dann kommt man um Blending nicht herum. Wie man das ganze Nutzen kann ist in diesem Tutorial von Phobeus erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lektion 8]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion8.gif|right]] &amp;quot;Das Wesen von hell und dunkel - Licht&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Ohne Beleuchtung sieht selbst jede 3D-Umgebung platt aus. In diesem Tutorial wird primär der richtige Gebrauch des OpenGL-Lichtes beschrieben. Darüberhinaus wird noch die Berechnung von Normalen erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial 2D]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_2D.jpg|right]] &amp;quot;2D mit OpenGL&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
OpenGL ist zwar primär eine 3D-API, eignet sich aber, nicht zuletzt dank seiner leistungsstarken Hardwarebeschleunigung und der damit verbundenen Features, auch sehr gut für reine 2D-Anwendungen. Dieses Tutorial von Sascha Willems geht sehr ausführlich auf die Nutzung von OpenGL für 2D-Anwendungen ein.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Matrix2]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Matrix2.png|right]] &amp;quot;Matrix2 - Matrizen und Matrixmanipulationen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Das Thema Matrizen stellt OpenGL-Einsteiger regelmäßig vor &amp;quot;unlösbare&amp;quot; Aufgaben:&amp;lt;br&amp;gt;&lt;br /&gt;
''Wieso dreht sich der Würfel so komisch, und nicht um sich selbst?''&amp;lt;br&amp;gt; &lt;br /&gt;
''Wieso verschiebt OpenGL die Kugel denn dahin, und nicht dorthin?''&amp;lt;br&amp;gt;&lt;br /&gt;
Dieses Tutorial von Flash befasst sich mit den 3 Matrixtypen, die es in OpenGL gibt und erklärt was die Befehle '''glScale, glRotate und glTranslate''' wirklich machen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Grundlagen-Tutorials ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Abseits eckiger Welten]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Abseits_eckiger_Welten.gif|right]] &amp;quot;Abseits eckiger Welten&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
3D-Welten bestehen seit eh und je aus Dreiecken, was sie oft recht eckig erscheinen lässt. In diesem Tutorial lernt ihr allerdings wie man mit Hilfe von Evaluatoren in OpenGL auch Rundungen erzeugen kann.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Renderpass]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Renderpass.jpg|right]] &amp;quot;Renderpass - Die Welt daneben&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
OpenGL bietet nicht nur die Möglichkeit seine Szene direkt auf den Bildschirm zu rendern, sondern auch diese in eine Textur zu rendern um diese dann auf ein Objekt zu kleben. Dadurch ergeben sich diverse neue Möglichkeiten, wie z.B. Spiegel, Portale oder nachträgliche Manipulation der Textur. Wie ihr eure Szene in eine Textur bekommt, erfahrt ihr hier.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Selection]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Selection.gif|right]] &amp;quot;Objectselektion A&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Die Selektion von Objekten braucht man spätestens dann, wenn man ein komfortable Interaktion mit der Spielwelt erstellen will. Mit diesem Tutorial von DCW_MrT ist die Thematik kein Problem mehr.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Objektselektion]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
| [[Bild:Tutorial_Selection_tut03.jpg|right]] &amp;quot;Objektselektion B&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Wie simpel der Objektselektionsmodus von OpenGL zu benutzen ist, wird in diesem Tutorial von Sascha Willems vermittelt. Dazu gibt es den Source-Code und eine fertig kompilierte Anwendung.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial TexFilter]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_TexFilter.jpg|right]] &amp;quot;Texturfilterung - Texturen-Feintuning&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Texturen sind seit langem ein wichtiger Bestandteil im Bereich der Echtzeitgrafik. OpenGL bietet auf diesem Gebiet auch diverse Möglichkeiten Texturen auch filtern zu lassen. Welche das sind und wie sie sich auswirken, könnt ihr in diesem Tutorial von Delphic nachlesen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kamera1]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Kamera1.gif|right]] &amp;quot;Dreht sich das Universum um uns? und andere philosophische Fragen&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial von Delphic geht es um die Kamera. Wie eine Kameraklasse gebaut sein könnte und was sie macht wird hier erklärt.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Effekte ==&lt;br /&gt;
&amp;lt;div align=&amp;quot;center&amp;quot;&amp;gt;&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Nebel]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Nebel.jpg|right]] &amp;quot;DGL Fogging Tutorial&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Erstaunlich einfach lässt sich mit OpenGL Nebel darstellen. Wie einfach, zeigt euch Lithander in diesem Tutorial. &lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Partikel1]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Partikel1.gif|right]] &amp;quot;Partikel-Tutorial I&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Eine Partikel-Engine sollte in (fast) jeder Engine enthalten sein. Anhand dieses Tutorials von Lithander könnt ihr den Grundstein dazu legen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial BumpMap]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_BumpMap.png|right]] &amp;quot;Bumpmapping - Plastisches 2D&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Bumpmapping ist eine immer stärker genutzte Technik, um polygonarme Oberflächen ohne Tesselation mit vorgegaukelten Details - abhängig vom Lichteinfall - zu versehen. In diesem Tutorial zeigt euch HomerS, wie man Bumpmapping über die NVIDIA-spezifischen Combiner realisiert.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial MultiTexturing]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Multitex05.jpg|right]] &amp;quot;Multitexturing&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Wie man mehrere Texturen auf ein Polygon bringen kann, erklärt auch Sascha Willems in diesem Tutorial zum Thema Multitexturing. Multitexturing ist seit OpenGL1.3 Teil des GL-Kerns und kann für z.B. für Lightmapping bzw. Detailmapping verwendet werden.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial StencilSpiegel]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_StencilSpiegel.jpg|right]] &amp;quot;Spiegelungen mit dem Stencil-Buffer&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Eine Echtzeit-Spiegelung ist einer der schönsten Effekte einer 3D-Welt und trägt viel zum Realismus bei. Eine Möglichkeit Spiegelungen über den Stencilpuffer zu realisieren, wird in diesem Tutorial von Sascha Willems erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial StereoSehen]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_StereoSehen.gif|right]]Auch wenn moderne Grafikkarten durch eine immer besser werdende Darstellung dem Benutzer versuchen das Betreten einer virtuellen 3D-Welt vorzugaukeln, so schafft es doch auch das beste Doom3-Monster nur bis zur Glasröhre zu erschrecken, rutscht dann aber quietschend davon ab. Was also tun, wenn man einen Schritt weiter gehen und dem Anwender wirkliches 3D bieten möchte? Wer eine 3D-Brille hat, wird mit diesem Tutorial von Delphic eine Möglichkeit finden, die dritte Dimension am Computer zur erschließen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Alphamasking]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Alphamasking_tut04.jpg|right]]In diesem kleinen aber feinen Tutorial erklärt Sascha Willems, wie man Alphamasking dazu verwenden kann, eine Szene optisch aufzuwerten und gleichzeitig Performance zu sparen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Wassereffekt]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Wassertutorial-scrshot-preview.jpg|right]]In diesem Tutorial erklärt Lord Horazont wie man eine Wasserebene mit Brechungen mit und ohne Shader erzeugen kann.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Extensions==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Cubemap]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Cubemap_mini.jpg|right]] &amp;quot;GL_ARB_Texture_Cubemap&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial erklärt Sascha Willems die Grundfunktionen der '''GL_ARB_Texture_Cubemap'''-Extension und zeigt auch weiterführende Techniken auf.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Vertexbufferobject]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial Vertexbufferobject preview.jpg|right]] &amp;quot;GL_ARB_Vertex_Buffer_Object&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Diese Extension führte '''VBO'''s ein. Wie man mit damit Vertexdaten schnell im Grafikkarten- und Hauptspeicher ablegt und darauf zugreift, erklärt Sascha Willems in diesem Tutorial.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Vertexprogramme]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_VP_preview.jpg|right]] &amp;quot;GL_ARB_Vertex_Program&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem umfangreichen Tutorial werden alle wichtigen Bereiche der Programmierung mit der GL_ARB_Vertex_Program-Extension abgedeckt. Man kann es als umfassende deutsche Referenz zu diesem Thema sehen, da auch alle wichtigen Funktionen aufgelistet werden und es auch sonst an nichts fehlt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial NVOcclusionQuery]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_NVO_preview.jpg|right]] &amp;quot;NV_Occlusion_Query&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Lard Middendorf geht in diesem Tutorial auf die Verwendung der NV_Occlusion_Query-Extension ein.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Pixelbuffer]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Pixelbuffer_preview.jpg|right]] &amp;quot;WGL_ARB_Pixel_Buffer&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Sascha Willems erklärt hier leicht verständlich den Umgang mit der Pixelbuffer-Extension. Als Additum wird auch noch auf die Nutzung dieser Extension für Shadowmapping eingegangen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial_Framebufferobject]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Framebufferobject_Preview.jpg|right]] &amp;quot;GL_EXT_FRAMEBUFFER_OBJECT&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Deathball erklärt in diesem Tutorial wie man Framebufferobjekte erstellt und diese zum Offscreenrendern benutzt.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Shader ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial glsl|Tutorial glSlang]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_glsl1.png|right]] &amp;quot;Einführung in GLSL&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Nach langem Ringen und Handeln hat es das ARB letztendlich doch geschafft, eine einheitliche Shaderhochsprache für OpenGL zu veröffentlichen, nämlich ''glSlang''. Mit glSlang können nun auch unter OpenGL Vertex- und Fragment-Shader in einer lesbaren, C-ähnlichen Hochsprache geschrieben werden, was deren Entwicklung stark vereinfacht. Diese Einführung von Sascha Willems ist weniger ein Tutorial, als ein kompletter Überblick über glSlang. Hier erfährt der Leser nicht nur etwas über die Benutzung von Shadern im Programm, sondern auch alles über die Sprachelemente, inklusive diverser Beispiele.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial glsl2|Tutorial glSlang 2]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_na.jpg|right]] &amp;quot;GLSL-Ergänzungen und Beispiele&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Dieses Tutorial von La_Boda ist eine direkte Fortsetzung des GLSL-Tutorials. Es behandelt verstärkt die Praxis und liefert anhand von einigen Beispielen eine bessere Sicht auf die bereits gelernte Theorie.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== KI ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial pathfinding|Tutorial Pathfinding]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_pathfinding.png|right]] &amp;quot;Pathfinding 1&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial zeigt euch Flo wie man recht simpel eine Wegfindungsroutine implementiert. Besonders wenn man sowas ohne großen Lernaufwand in sein Spiel einbinden möchte, sollte man einen Blick riskieren.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial pathfinding2|Tutorial Pathfinding 2]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_pathfinding2.png|right]] &amp;quot;Pathfinding 2&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Gerade bei aktuelleren Programmen reicht es meist nicht aus, wenn man seine Einheiten nur in 8 Himmelsrichtungen bewegen kann. Frase stellt in diesem Tutorial vor, wie man eine Wegfindungsroutine implementieren kann, wie diese in einem heutigen RTS vorkommen kann.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Terrain und Landschaften ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Terrain1]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Terrain1.gif|right]] &amp;quot;Aussenlandschaften mit System - Heightmaps&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Anhand der Graustufenwerte einer Bitmap-Datei kann man relativ einfach eine imposante Landschaft erstellen. Wie das ganze funktioniert erklärt euch Delphic in diesem Tutorial. Außerdem wird noch die Implementation von Skyboxen erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Terrain2|Tutorial Terrain 2]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Terrain2.gif|right]] &amp;quot;Heightmap-Texturen&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Da das Terrain aus dem vorigen Tutorial noch recht eintönig grau aussieht und das natürlich geändert werden soll, erklärt euch Delphic, wie man schmucke Schatten und Texturen für die Heightmap generieren kann.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Terrain3|Tutorial Terrain 3]]&lt;br /&gt;
{{Level_5}} &lt;br /&gt;
|[[Bild:Tutorial_Terrain3.gif|right]] &amp;quot;Terrain im Detail&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Da größere Landschaften aufgrund der hohen Polygonanzahl sehr aufwändig zu rendern sind erklärt euch Delphic hier, wie man entfernte Dreiecke &amp;quot;zusammenlegen&amp;quot; kann, um Rechenleistung zu sparen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Skyboxen]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Skybox_Vorschau.jpg|right]] &amp;quot;Skyboxen&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In diesem Tutorial erklärt Sascha Willems kurz und bündig den Umgang mit Skyboxen, mit denen man Landschaften schnell sehr stark optisch aufwerten kann. Es wird sowohl auf die Erstellung der Skybox-Texturen mit dem Programm Terragen als auch die Implementation der Skybox in OpenGL eingegangen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Spieletutorials und Softwareentwicklung==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Bomberman1|Tutorial Bomberman 1]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Bomberman1.jpg|right]] &amp;quot;Bomberman1 - Codebasis und Editor&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im ersten Teil dieser kleinen Tutorialserie zum Thema Spieleprogrammierung kümmern wir uns neben der Erstellung unseres Basiscodes auch um einen fertigen Editor. Nach der Durcharbeitung dieses Tutorials von Sascha Willems sollte der Leser alle Grundprinzipien zur Programmierung eines Spiels verstanden haben.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Bomberman2|Tutorial Bomberman 2]]&lt;br /&gt;
{{Level_3}}&lt;br /&gt;
|[[Bild:Tutorial_Bomberman2.jpg|right]] &amp;quot;Bomberman2 - Der 3D-Bombermanklon (Grundversion)&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im zweiten Teil gehts ans Eingemachte, nämlich einen fertigen Bombermanklon. In Sascha Willems Tutorial werdet ihr zusätzlich zu den bereits erworbenen Prinzipien diverse Techniken die in so ziemlich jedem Spiel Verwendung finden erlernen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Softwareentwicklung1|Tutorial Softwareentwicklung 1]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_SWE1.jpg|right]] &amp;quot;Softwareentwicklung1 - Objektorientierte Softwareentwicklung mit UML&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im ersten Teil dieser Tutorialserie zum Thema Softwareentwicklung erklärt euch Flash, wie man an ein Projekt herangeht und herausfindet was eigentlich zu tun ist. Es geht dabei um Analyse der Anforderungen und die Modellierung sogenannter Use Cases. Die hier vorgestellten Arbeiten sind Grundlage um später Klassen zu finden auf denen dann der Code aufgebaut wird.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Softwareentwicklung2|Tutorial Softwareentwicklung 2]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_SWE2.jpg|right]] &amp;quot;Softwareentwicklung2 - Objektorientierte Softwareentwicklung mit UML&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im zweiten und umfangreichsten Teil der Serie steht das Thema &amp;quot;Klassen&amp;quot; im Zentrum. Flash erklärt euch wie man aus den Use Cases Klassen ableitet und welche unterschiedlichen Einsatzgebiete Klassen innerhalb der Software haben können.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Softwareentwicklung3|Tutorial Softwareentwicklung 3]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_SWE3_Interface.jpg|right|128px]] &amp;quot;Softwareentwicklung3 - Objektorientierte Softwareentwicklung mit UML&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Im letzten Teil der Serie steht das Thema &amp;quot;Verhalten&amp;quot; im Zentrum. Flash erklärt euch wie die Klassen miteinander in Beziehung gesetzt werden. Außerdem wird nocheinmal auf den RUP als '''iterative''' Vorgehensweise eingegangen.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Mathematisches ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Lineare Algebra]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_lineare_Algebra_Preview.jpg|right]] &amp;quot;Vektorrechnung&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
In vielen Tutorials tauchen eine Menge Begriffe aus der linearen Algebra und analytischen Geometrie auf. Wer bei Begriffen wie Vektoren, Skalar-Produkt, Vektorkreuzprodukt, etc. ein wenig Auffrischung und Implementationshinweise braucht, ist mit diesem Tutorial von EternalLearner an der richtigen Stelle.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Nachsitzen]]{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Nachsitzen_preview.png|right]] &amp;quot;3d-Mathematik&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Wer die mathematischen Grundlagen wie Sinus, Cosinus und Matrizen aus der Schule schon wieder vergessen oder noch vor sich liegen hat, der kann mit Hilfe dieses Tutorials von Delphic dieses Wissen erlernen bzw. auffrischen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Objekt gedreht und dennoch nach vorne bewegt]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Objekt_gedreht_und_dennoch_nach_vorne_bewegt_preview.gif|right]] &amp;quot;Objekt gedreht und dennoch nach vorne bewegt&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
SchodMC erklärt in diesem Tutorial wie man ein Objekt drehen und dabei trotzdem vorwärts bewegen kann. Quer fahrende Autos sind zwar praktisch zum Einparken Aber doch eher selten ;-)&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Objekt immer um eigene Achse drehen]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Objekt_immer_um_die_eigene_Achse_drehen_preview.gif|right]] &amp;quot;Objekt immer um eigene Achse drehen&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Wenn ihr euer Objekt nun noch um die eigene Achse drehen wollt, seid ihr mit diesem Tutorial von SchodMC an der richtigen Adresse&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Separating Axis Theorem]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:SAT_Kollision.jpg|right|128px]] &amp;quot;Separating Axis Theorem&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Seth erklärt in diesem Tutorial wie man Polygonkollisionen mit Hilfe des ''Seperating Axis Theorem'' erkennen kann. &lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kollision1]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
|[[Bild:Tutorial_Kollision1_Coll2.png|128px|right]] &amp;quot;Kollision 1&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Reinhard Niehoff fragte uns ob er ein Tutorial über Kollision schreiben könnte. Das konnten wir nicht ablehnen, und so entstand dieses Tutorial in dem grundlegende Kollisionsberechnungen erklärt werden. Weitere sollen folgen. &lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kollision2]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Kollision2_Thumb.png|128px|right]] &amp;quot;Kollision 2&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Beim zweiten Tutorial gehts mehr in die Tiefe und einige Spezialfälle bei Kugel-Polygon-Kollisionen werden erläutert. Mit dabei: Die [[Werkzeugkiste]] mit nützlichen Funktionen.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Kollision3]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Kollision3_Thumb.png|128px|right]] &amp;quot;Kollision 3&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
Beim letzten Tutorial dieser Serie gehts darum, wie man die bisherigen Ansätze in einem Programm unterbringt.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Grafik und Modellierung ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Modellierung eines Low-Poly Menschen Teil 1]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Low-Poly-Mensch1_preview.jpg|right]] &amp;quot;Modellierung eines Low-Poly-Menschen&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Die Modellierung von organischen &amp;quot;Objekten&amp;quot; gehört mit zu den kompliziertesten Aufgaben, die es beim Modelling gibt. Wie man einen Menschen mit aus möglichst wenigen Polygonen mit dem Programm 3D Studio Max erstellen kann wird in diesem Tutorial von Sascha Willems erklärt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Modellierung eines Low-Poly Menschen Teil 2]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
|[[Bild:Tutorial_Low-Poly-Mensch2_preview.jpg|right]] &amp;quot;Kleider machen Leute (UVW-Mapping)&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Nun spendiert Sascha Willems seinem Menschen aus dem 1. Tutorial eine schmucke Uniform, so dass er sich endlich in der Öffentlichkeit blicken lassen kann.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Skripte ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Scripting mit JvInterpreterProgram]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_JvInterpreter_preview.png|right]] &amp;quot;Skripting mithilfe der Jedi-Code-Library&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
SchodMC erklärt hier wie man mit relativ wenig Aufwand Skripte in eigene Programme integrieren kann.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Scriptsprachen Teil 1]]&lt;br /&gt;
{{Level_5}} &lt;br /&gt;
|[[Bild:Tutorial_Skriptsprachen1_preview.gif|right]] &amp;quot;Scriptsprachen Teil 1 - Einführung&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Für alle die schon immer einmal wissen wollten wie ein Compiler arbeitet ist diese Tutorial-Reihe von Delphic genau das richtige.&lt;br /&gt;
&lt;br /&gt;
Der erste Teil widmet sich der Lexikalischen Analyse und dem Parsen des Quellcodes&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Scriptsprachen Teil 2]]&lt;br /&gt;
{{Level_5}} &lt;br /&gt;
|[[Bild:Tutorial_Skriptsprachen2_preview.gif|right]] &amp;quot;Scriptsprachen Teil 2 - Virtuelle Computer und Code Erzeugung&amp;quot;.&amp;lt;br&amp;gt;&lt;br /&gt;
Für alle die schon immer einmal wissen wollten wie ein Compiler arbeitet ist diese Tutorial-Reihe von Delphic genau das richtige.&lt;br /&gt;
&lt;br /&gt;
Der zweite Teil beschreibt den Bau einer VM und der Codeerzeugung&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Delphi allgemein ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Debugging]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
| [[Bild:Tutorial Debugging.gif|right]] &amp;quot;Debugger benutzen und andere praktische Tipps&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Tutorial werdet von Delphic mit der Nutzung des Delphi-Debuggers eingeführt. Auch werden Wege zur Vermeidung von Fehlern aufgezeigt. Genauso findet Ihr aber auch in diesem Tutorial Hinweise, zu häufig begangenen Fehlern und deren Ursachen.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Komponentenentwicklung]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
| [[Bild:Tutorial Komponentenentwicklung.png|right]] &amp;quot;Komponentenentwicklung&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
In diesem Tutorial werdet ihr ein wenig tiefer in die Entwicklung von Komponenten unter Delphi eingeführt. Es wird Grundwissen auf diesem Gebiet vorausgesetzt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial Multithreading]]&lt;br /&gt;
{{Level_3}} &lt;br /&gt;
|[[Bild:Tutorial_Multithreading.gif|right]] &amp;quot;Das Prinzip der Dualität&amp;quot;.&amp;lt;br&amp;gt; &lt;br /&gt;
Threads sind ein erweitertes Prinzip des bekannten Multitasking und werden innerhalb eines Programmes oft dazu genutzt, verschiedene Aufträge gleichzeitig abzuarbeiten. LossyEx erklärt euch hier deren Nutzung.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Software-Synthesizer]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Bild:Noexist.jpg|right]] &amp;quot;Software-Synthesizer&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Computerspiele bestehen nicht nur aus Grafik. Dieses Tutorial widmet sich einem ganz anderen Bereich der Spieleprogrammierung: Der Erzeugung von synthetischen Sounds und Musik.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== SDL ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial SDL Einstieg]]&lt;br /&gt;
{{Level_2}} &lt;br /&gt;
|[[Bild:Tutorial_Lektion1.gif|right]] &amp;quot;SDL-Einsteiger-Tutorial&amp;quot;&amp;lt;br&amp;gt; &lt;br /&gt;
Crossplattform-Programmierung ist das Zauberwort, welches in den letzten Jahren - dank verstärkter Präsenz von Linux - immer wieder in den Programmierforen des Internets auftaucht. Für Grafikprogrammier ist [[SDL]] hier das Mittel der Wahl. Bekannte Titel wie &amp;quot;Quake III&amp;quot; und &amp;quot;Civilisation - Call to Power&amp;quot; bauen bereits auf diese Bibiothek für ihre Linux-Ports. Phobeus zeigt euch in diesem ersten SDL-Tutorial was SDL ist und wie man es benutzt.&lt;br /&gt;
|-&lt;br /&gt;
![[Tutorial SDL_RWops]]&lt;br /&gt;
{{Level_2}}&lt;br /&gt;
| [[Bild:Noexist.jpg|right]] &amp;quot;SDL_RWops-Tutorial&amp;quot;&amp;lt;br&amp;gt;&lt;br /&gt;
SDL benutzt für den Dateizugriff SDL_RWops. [[Benutzer:Lord Horazont|Lord Horazont]] zeigt euch in diesen Tutorial wie man diese benutzt und auch komfortabler gestaltet.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Rendertechniken ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Octree]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
| [[Bild:Tutorial Octree preview.jpg|right]] &amp;quot;Octrees&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Octrees sind eine einfach zu implementierende, aber sehr effiziente Möglichkeit um besonders Outdoor-Szenen abhängig vom Betrachterblickfeld stark zu beschleunigen. In diesem Tutorial zeigt Shadow euch eine komplette Implementation eines Octrees inklusive ausgiebigem Quellcode.&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Frustum Culling]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
| [[Bild:Tutorial Frustum Culling.jpg|right]] &amp;quot;Frustum Culling&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Frustum Culling ist eine einfache Möglichkeit die Rendergeschwindigkeit zu erhöhen, da man damit schon vor dem Senden der Daten an die Grafikkarten feststellen kann, welche Objekte sich im Blickfeld des Spielers befinden und welche nicht.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Raytracing ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Raytracing - Grundlagen I]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Bild:Tutorial_RaytracingI_thumb.jpg|right]] &amp;quot;Raytracing - Grundlagen I&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Die Grundzüge des Raytracings Teil 1 - Von den Strahlen bis zur ersten Darstellung von Kugeln und Ebenen&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial Raytracing - Grundlagen II]]&lt;br /&gt;
{{Level_4}} &lt;br /&gt;
| [[Bild:Tutorial_RaytracingI_thumb.jpg|right]] &amp;quot;Raytracing - Grundlagen II&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
Die Grundzüge des Raytracings Teil 2 - Einfache Basisobjekte, Transformationen und Phong-Lightning&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Sonstiges ==&lt;br /&gt;
{|{{Prettytable_B1}} width=&amp;quot;100%&amp;quot;&lt;br /&gt;
!width=&amp;quot;15%&amp;quot;|Link&lt;br /&gt;
!width=&amp;quot;85%&amp;quot;|Beschreibung&lt;br /&gt;
|-&lt;br /&gt;
! [[Tutorial GLScene]]&lt;br /&gt;
{{Level_1}} &lt;br /&gt;
| [[Bild:Tutorial GLScene preview.jpg|right]] &amp;quot;Einführung in GLScene&amp;quot; &amp;lt;br&amp;gt;&lt;br /&gt;
GLScene ist eine zu erstaunlicher Größe angewachsene Komponentensammlung, die quasi einen OpenGL-Wrapper darstellt und euch dank Delphis VCL dadurch recht einfach OpenGL-Programme erstellen lässt. LaBoda gibt euch zu dieser Komponentensammlung in diesem Tutorial deshalb eine kleine Einführung.&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Delphic</name></author>	</entry>

	</feed>