https://wiki.delphigl.com/api.php?action=feedcontributions&user=Komoluna&feedformat=atomDGL Wiki - Benutzerbeiträge [de]2024-03-29T02:15:56ZBenutzerbeiträgeMediaWiki 1.27.4https://wiki.delphigl.com/index.php?title=Tutorial_Octree&diff=26314Tutorial Octree2015-06-14T17:17:10Z<p>Komoluna: Rechtschreibkorrektur des Edits vom 12.03.2005</p>
<hr />
<div>=Octree-Tutorial=<br />
by Shadow<br />
<br />
==Einleitung==<br />
<br />
Herzlich Willkommen zu meinem ersten Tutorial für die Delphi OpenGL Community.<br />
<br />
<br />
Schon mal vorweg: Dieses Tutorial hat weniger mit OpenGL-technischen Verfahren zu tun, sondern viel mehr mit der Programmiersprache und ist absolut nicht an Anfänger in Sachen Delphi gerichtet, da schon für Einsteiger komplizierte Verfahren, wie z.B. sich selbst aufrufende Prozeduren, genutzt werden. Aber ich möchte niemanden erschrecken, denn dies ist ein freies Land und jeder darf tun und lassen was er will ;-). Es ist ratsam dass von mir geschriebene selbst zu schreiben und nicht mit Strg+C & Strg+V in sein Programm zu kopieren, da man dabei nicht sehr viel lernt. Ich will die Sache schnell hinter mich bringen, also fang ich gleich mal an, denn wir haben viel Arbeit vor uns (was jetzt nicht heißen soll dass ich alles überfliege, ich versuch so gut wie möglich alles zu erklären).<br />
<br />
<br />
Stellt euch vor, ihr habt eine riesige Landschafts-Szene die aus 512x512 Vertices besteht. Jedes dieser Vertices besitzt nun auch noch Textur-Koordinaten, Normalen, usw.<br />
Dass alles zu rendern würde eine große Rechenleistung benötigen. Aber höchstwahrscheinlich sieht der Spieler nur immer einen Teil der Landschaft, also warum alles darstellen, wenn nur ein Teil gesehen wird?<br />
Frustum-Culling (d.h. jedes Polygon auf Sichtbarkeit zu überprüfen) würde den gesamten Performance-Bedarf auf die CPU übertragen und wäre somit bei ca. 500x500 Polygonen auch nicht hilfreich.<br />
An dieser Stelle hilft uns ein Octree.<br />
"Octree", dass werden schon viele von euch gehört haben, aber was dass genau ist, das wird wohl nicht jeder wissen. Ich werd mal versuchen zu erklären was dass genau ist und wofür man dieses Ding braucht.<br />
<br />
<br />
==Was ist ein Octree==<br />
Nun das Wort "Octree" kommt aus dem Lateinischen oder so.... ;-) "Oct" steht für "Acht" und "Tree" bedeutet im Englischen "Baum". Was soll das nun heißen? ... ACHT-BAUM? Ein Octree kann man sich folgendermaßen vorstellen : Ein Würfel, der in 8 kleine Würfel unterteilt wird. Jeder dieser Würfel wird dann noch einmal in 8 kleine Würfel geteilt usw. Kann man vergleichen mit einem Baum, der 8 große Zweige hat, diese Zweige haben wieder 8 Zweige usw.<br />
Deswegen „Baum“. Beim Octree heißen diese Würfel „Nodes“, was übersetzt „Knoten“ heißt (fragt mich bitte nicht warum [Weil ein binärer Baum nunmal Knoten hat, nämlich dort wo sich "Äste" verzweigen - Anmerkung des Lektors, SoS]).<br />
<br />
<br />
==Wie funktioniert ein Octree==<br />
Nun dies ist nicht mit einem Satz zu erklären. Aber ich versuch es mal mit ein "paar" Sätzen:<br />
<br />
[[Bild:Tutorial Octree mainnode.jpg|left]] Die gesamte Szene wird in einen großen Würfel gepackt. Dazu überprüft man alle Vertices auf ihre größten und kleinsten Werte. Ist z.B. die y-Koordinate von Vertex a die Größte und die z-Koordinate von Vertex b die Kleinste, so ist die Länge unseres Würfels: a.y - b.z Am Mittelpunkt der Szene wird dann der Würfel mit diesen Seitenlängen berechnet. Dieser Würfel, wird dann in 8 kleinere Würfel geteilt und diese wiederum in 8 kleinere usw. Alle Nodes, die leer sind fallen dabei weg, da sie für uns überflüssig sind.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br><br />
<br><br />
[[Bild:Tutorial Octree nodes.jpg|left]] Auf dem Bild links seht ihr nun die Szene mit mehreren Nodes.<br />
Dies kann man nun so oft man will wiederholen, aber Vorsicht : Es benötigt viel Rechenzeit alle kleinen Nodes noch mal zu teilen, und diese noch mal, weil dabei immer überprüft werden muss, ob sich Vertices in ihnen befinden. Außerdem ist es ab einer Gewissen Anzahl von Nodes nicht mehr sehr sinnvoll, da z.B. zu viele Nodes sich eher negativ auf die Performance auswirken würden.<br />
<br><br />
<br><br />
<br><br />
<br><br />
<br><br />
<br><br />
<br />
Deswegen machen wir folgendes: Wir speichern die Anzahl der Vertices bzw. Polygone, die sich in unserem Node befinden, und teilen nur so lange sich diese Zahl über einer bestimmen Limit befindet, z.B. 500 Polygone. So werden Nodes, die weniger als 500 Polygone besitzen, nicht mehr geteilt. Wenn dies alles erledigt ist, dann muss man beim Rendern der Szene folgendes beachten:<br />
<br />
Es wird per Frustum-Culling überprüft, ob sich die großen Nodes im Blickfeld befinden. Von denen, die sichtbar sind, wird überprüft, ob deren kleinere Würfel sichtbar sind und deren Unterknoten usw. Ist ein Node nicht sichtbar, so werden auch seine Kindwürfel nicht überprüft. Wenn man beim kleinsten Node angekommen ist, was dank dieses Algorithmus sehr schnell geschieht, werden nur die Polygone gezeichnet, die sich in ihm befinden.<br />
<br />
Wie ihr euch wahrscheinlich denken könnt, bringt dieses Verfahren eine Menge Geschwindigkeit.<br />
<br />
<br />
==Was brauch ich dafür==<br />
*Nun da ich aus Zeitgründen das Frustum-Culling nicht erklären kann, müsst ihr eine Unit haben, die den Frustum berechnet und ein Würfel auf<br />
Sichtbarkeit überprüfen kann. Sehr empfehlenswert ist die von SoS (nette Grüße) auf www.delphigl.de.<br />
<br />
*Außerdem müsst Ihr euren Terrain/Objekte laden und in einer Polygon-Array speichern. Am besten aus einer Bitmap-Datei, so wie ich es mache.<br />
<br />
<br />
==Let's get started==<br />
Auf in den Kampf:<br />
<br />
<br />
Am besten erstellt/benutzt eine Unit in der die Haupttypen definiert sind. Bei mir sieht diese folgendermaßen aus:<br />
<br />
<source lang="pascal"><br />
unit Globals;<br />
<br />
interface<br />
<br />
uses<br />
Windows, Messages, dglOpenGL, FrustumC;<br />
<br />
type<br />
PVertex = ^TVertex;<br />
TVertex = record<br />
x,y,z : GlFloat;<br />
end;<br />
PFullVertex = ^TFullVertex;<br />
TFullVertex = record<br />
ver,n : TVertex;<br />
u,v : GlFloat;<br />
end;<br />
PPolygon = record<br />
v : array [0..2] of PFullVertex;<br />
end;<br />
TPolygon = record<br />
v : array [0..2] of TFullVertex;<br />
end;<br />
<br />
var<br />
Frustum:TFrustum;<br />
</source><br />
<br />
<br />
Die Typen die ihr deklariert, solltet ihr in eurem Hauptprogramm auch benutzt wenn ihr eurer Vektoren laden wollt, damit es nicht zu Problemen zwischen der Octree-Klasse und euren Arrays kommt.<br />
<br />
Nun fangen wir mit der Typdefinition in der Octree-Unit an. Oben definieren wir eine Konstante, die angibt ab welcher Vektorenanzahl ein Knoten nicht mehr geteilt wird:<br />
<br />
<br />
<source lang="pascal"><br />
unit Octree;<br />
<br />
interface<br />
<br />
uses<br />
Windows, Messages, dglOpenGL, Globals;<br />
<br />
Const<br />
MAX_TRIANGLES_IN_NODE = 500;<br />
</source><br />
<br />
<br />
Wir überlegen uns mal was wir so alles für Typen definieren müssen ...hmmmmmmm am besten:<br />
<br />
*Einen Knoten als Objekt, da Prozeduren und Funktionen hinzukommen werden<br />
*und den Octree als Klasse, damit wir Konstructor und Destruktor entsprechend nutzen können<br />
<br />
<br />
Hier das Node-Objekt:<br />
<br />
<br />
<source lang="pascal"><br />
type PNode = ^TNode;<br />
TNode = object<br />
pos : TVertex;<br />
size : glfloat;<br />
nump : Integer;<br />
numc : Byte;<br />
poly : array of PPolygon;<br />
children : array of PNode;<br />
smallest : Boolean;<br />
function HowManyPolygons(const polygons : array of PPolygon;Add:Boolean):Integer;<br />
function PolygonIn(p:PPolygon):Boolean;<br />
Procedure Divide(const polygons : array of PPolygon);<br />
procedure DrawPolygons;<br />
procedure Check;<br />
procedure Draw;<br />
procedure Clear;<br />
end;<br />
</source><br />
<br />
<br />
Ich denke, dass das alles sehr selbsterklärend ist, aber um sicher zugehen dass ihr das alle versteht:<br />
<br />
<br />
Erstmal einen Pointer auf die Knoten, und folgende Informationen für einen Knoten :<br />
*seinen Mittelpunkt --> Vektor<br />
*seine Größe --> glFloat<br />
*die Anzahl der Polygonen, die sich in ihm befinden --> Integer<br />
*die Anzahl an Würfeln (maximal 8), die aus ihm entstehen, wenn er mehr als MAX_TRIANGLES_IN_NODE Vektoren in sich hat --> Byte<br />
*ein Array für die Polygone --> array of TPolygon<br />
*und anschließend ein Array für die untergeordneten Nodes --> array of PNode<br />
*ob es der kleinste Node ist, also ob sich weniger als MAX_TRIANGLES_IN_NODE in ihm befinden --> Boolean, denn dann erst speichern wir in das Array die Polygone, damit wir diese anzeigen können, und auch dann erst wird er wieder geteilt.<br />
*Die Funktion "HowManyPolygons" überprüft, wie viele Polygone in dem Node sind und der Parameter "Add" entscheidet, ob die Polygone in das Array des Nodes aufgenommen werden sollen. Dies brauchen wir, weil nur in die kleinsten Nodes die Polygone aufgenommen<br />
werden müssen, da wir sonst alle Polygone öfter zeichnen würden; und nicht genau wissen, welches Polygon bereits gezeichnet wurde und welches nicht.<br />
*"PolygonIn" testet, ob ein Polygon im Node ist und liefert dann TRUE zurück.<br />
*"Divide" teilt den Node in 8 kleine Würfel.<br />
*"Check" überprüft den Node auf Sichtbarkeit und zeichnet dann seine Polygone.<br />
*"Draw" zeichnet den Node selbst.<br />
*"Clear" löscht den Node.<br />
<br />
<br />
So, jetzt das Objekt für den ganzen Octree :<br />
<br />
<br />
<source lang="pascal"><br />
TOctree = class<br />
public<br />
mainnode : PNode;<br />
procedure drawOctree(drawPol,drawNodes:Boolean);<br />
Constructor Create(const polygons : array of PPolygon);<br />
Destructor Destroy;<br />
end;<br />
</source><br />
<br />
<br />
MainNode ist der oberste Würfel. Mehr brauchen wir nicht, da die restlichen Nodes diesem untergeordnet werden.<br />
<br />
Die Parameter in "DrawOctree" geben an, ob die Polygone im Node gezeichnet werden sollen und ob der Node dargestellt werden soll (eigentlich unwichtig, aber zur Veranschaulichung sehr nützlich).<br />
<br />
Die zu überprüfenden Polygone werden als Pointer übergeben.<br />
<br />
<br />
Nun kommen wir zu der Initialisierungs-Prozedur, die den obersten Würfel um die ganze Szene berechnet:<br />
<br />
<source lang="pascal"><br />
Constructor TOctree.Create(const polygons : array of PPolygon);<br />
var<br />
i,j:Integer;<br />
maxSize,minSize:Glfloat;<br />
begin<br />
inherited Create;<br />
maxsize:=polygons[0].v[0].ver.x;<br />
minsize:=polygons[0].v[0].ver.x;<br />
for i:=0 to High(polygons) do<br />
for j:=0 to 2 do<br />
with polygons[i].v[j].ver do<br />
begin<br />
if x > maxSize then maxSize:=x;<br />
if y > maxSize then maxSize:=y;<br />
if z > maxSize then maxSize:=z;<br />
<br />
if x < minSize then minSize:=x;<br />
if y < minSize then minSize:=y;<br />
if z < minSize then minSize:=z;<br />
end;<br />
New(mainnode);<br />
MainNode.pos.x:=(maxSize+minSize)/2;<br />
MainNode.pos.y:=(maxSize+minSize)/2;<br />
MainNode.pos.z:=(maxSize+minSize)/2;<br />
MainNode.size:=(maxSize-minSize)/2;<br />
MainNode.smallest:=FALSE;<br />
MainNode.Divide(polygons);<br />
end;<br />
</source><br />
<br />
<br />
Es ist logisch, dass vor der Initialisierung des Octrees die Landschaft erst einmal geladen werden muss; damit das Polygon-Array die richtigen Werte hat.<br />
<br />
Also zur Prozedur : Alle Vertices werden auf ihre größte und kleinste Komponente überprüft, die gesuchten Werte lassen uns dann den Mittelpunkt und die Größe unseres Nodes berechnen.<br />
Mit "New()" wird im Speicher ein TNode angelegt, da MainNode nur ein Pointer ist und dieser erst einmal erstellt werden muss. Da müsst ihr beachten, dass ihr den Speicher dann am Ende mit "Dispose()" wider freigebt, aber ich werde euch noch daran erinnern.<br />
<br />
<br />
Die untenstehende Prozedur teilt den Node in 8 kleine Würfel und überprüft, ob diese leer sind. Hier die Divide-Prozedure:<br />
<br />
<source lang="pascal"><br />
Procedure TNode.Divide(const polygons : array of PPolygon);<br />
var<br />
TempNodes:array[0..7] of PNode;<br />
i:Integer;<br />
begin<br />
for i:=0 to 7 do New(TempNodes[i]);<br />
numc:=0;<br />
TempNodes[0].pos.x:=pos.x-size/2;<br />
TempNodes[0].pos.y:=pos.y+size/2;<br />
TempNodes[0].pos.z:=pos.z-size/2;<br />
<br />
TempNodes[1].pos.x:=pos.x+size/2;<br />
TempNodes[1].pos.y:=pos.y+size/2;<br />
TempNodes[1].pos.z:=pos.z-size/2;<br />
<br />
TempNodes[2].pos.x:=pos.x+size/2;<br />
TempNodes[2].pos.y:=pos.y+size/2;<br />
TempNodes[2].pos.z:=pos.z+size/2;<br />
<br />
TempNodes[3].pos.x:=pos.x-size/2;<br />
TempNodes[3].pos.y:=pos.y+size/2;<br />
TempNodes[3].pos.z:=pos.z+size/2;<br />
<br />
TempNodes[4].pos.x:=pos.x-size/2;<br />
TempNodes[4].pos.y:=pos.y-size/2;<br />
TempNodes[4].pos.z:=pos.z-size/2;<br />
<br />
TempNodes[5].pos.x:=pos.x+size/2;<br />
TempNodes[5].pos.y:=pos.y-size/2;<br />
TempNodes[5].pos.z:=pos.z-size/2;<br />
<br />
TempNodes[6].pos.x:=pos.x+size/2;<br />
TempNodes[6].pos.y:=pos.y-size/2;<br />
TempNodes[6].pos.z:=pos.z+size/2;<br />
<br />
TempNodes[7].pos.x:=pos.x-size/2;<br />
TempNodes[7].pos.y:=pos.y-size/2;<br />
TempNodes[7].pos.z:=pos.z+size/2;<br />
for i:=0 to 7 do<br />
begin<br />
TempNodes[i].size:=size/2;<br />
TempNodes[i].smallest:=FALSE;<br />
end;<br />
for i:=0 to 7 do<br />
begin<br />
if TempNodes[i].HowManyPolygons(polygons,FALSE)>0 then<br />
begin<br />
inc(numc);<br />
setLength(children,numc);<br />
children[numc-1]:=TempNodes[i];<br />
if children[numc-1].nump < MAX_TRIANGELS_IN_NODE then<br />
begin<br />
children[numc-1].smallest:=TRUE;<br />
children[numc-1].HowManyPolygons(polygons,TRUE);<br />
end;<br />
end else Dispose(TempNodes[i]);<br />
end;<br />
for i:=0 to numc-1 do<br />
if children[i].smallest=FALSE then children[i].Divide(polygons);<br />
end;<br />
</source><br />
<br />
<br />
Es werden erst einmal die 8 Nodes neu im Speicher angelegt und dann in Abhängigkeit zum Node berechnet. Dann wird für jeden dieser TempNodes mit der Funktion VerticesIn überprüft, wie viele Polygone sich in ihm befinden. Der zweite Parameter bestimmt, ob die Polygone in das Array des Nodes gespeichert werden sollen. Dies wollen wir erst einmal nicht. Diese Prozedur zeige ich euch gleich etwas genauer. Wichtig ist, dass wenn sich Polygone im Node befinden, er erst dann zum Kind des Nodes wird. Sind weniger Polygone als unsere Konstante '''MAX_TRIANGLES_IN_NODE''' in unserem Kindknoten, dann ist er der kleinste, d.h. er wird nicht mehr geteilt und wir können die Polygone in seinem Array speichern.<br />
<br />
Befindet sich kein Polygon im TempNode, so wird dieser nicht als Kindknoten aufgenommen und mit Dispose() aus dem Speicher entfernt.<br />
<br />
Wenn alle Nodes überprüft worden sind, so werden die, die als Kinder aufgenommen wurden, auch mit dieser Prozedur geteilt und überprüft, aber nur wenn sie weniger als '''MAX_TRIANGELS_IN_NODE''' (smallest=FALSE) Polygone in sich haben.<br />
<br />
<br />
Wie ihr wahrscheinlich merkt, ist dies die Haupt-Prozedur.<br />
Sie hört erst auf, wenn alle Nodes weniger als '''MAX_TRIANGLES_IN_NODE''' Polygone in sich haben.<br />
<br />
<br />
Nun schauen wir uns mal die "HowManyPolygons" und die "PolygonIn"-Funktion an:<br />
<br />
<br />
<source lang="pascal"><br />
function TNode.PolygonIn(p:PPolygon):Boolean;<br />
var<br />
i:Integer;<br />
begin<br />
Result := FALSE;<br />
for i := 0 to 2 do<br />
if not Result then<br />
with p.v[i].ver do<br />
begin<br />
if(x >= pos.x - size) and<br />
(y >= pos.y - size) and<br />
(z >= pos.z - size) and<br />
(x <= pos.x + size) and<br />
(y <= pos.y + size) and<br />
(z <= pos.z + size) then Result:=TRUE;<br />
end;<br />
end;<br />
</source><br />
<br />
<source lang="pascal"><br />
function TNode.HowManyPolygons(const polygons : array of PPolygon; Add:Boolean):Integer;<br />
var<br />
i:Integer;<br />
begin<br />
nump := 0;<br />
<br />
if Add then<br />
begin<br />
for i := 0 to High(polygons) do<br />
if PolygonIn(polygons[i]) then<br />
begin<br />
Inc(nump);<br />
SetLength(poly, numv);<br />
poly[nump-1] := polygons[i];<br />
end;<br />
end<br />
else<br />
for i := 0 to High(polygons) do<br />
if PolygonIn(polygons[i]) then<br />
Inc(nump);<br />
<br />
Result := nump;<br />
end;<br />
</source><br />
<br />
<br />
[EDIT 12.03.2005 vom Autor]<br />
Habe was SEHR wichtiges vergessen. Anstatt alle Polygone zu überprüfen, ist es sehr(und ich meine SEHR) viel schneller, nur die Polygone, des übergeordneten Nodes zu testen. Ein Implementation sollte nicht all zu schwer sein: Einfach für jedes Node einen Pointer auf den Mother-Node setzten und die Polygone immer in die Array speichern, und dann bei der Überprüfung sich auf die polygon-array des Mother-Nodes beziehen. Sollte die Performance deutlich steigern. Ich entschuldige mich für meinen Fehler ;)<br />
[/EDIT]<br />
<br />
<br />
Die Funktion "PolygonIn" überprüft ob ein Polygon sich in einem Node befindet (wie der Name schon sagt).<br />
<br />
"HowManyPolygons" greift darauf zu und gibt die Anzahl der Polygone, die sich in dem Node befinden zurück und speichert diese in der Node Variablen "nump". Wenn der Parameter Add auf TRUE gesetzt wurde, dann werden alle Polygone in das Array des Nodes gespeichert.<br />
HINWEIS: Hierzu ist zu sagen, dass die Funktion "PolygonIn" nicht perfekt ist. Wenn sich mindestens ein Vektor des Polygons im Node befindet, dann wird das Polygon angenommen. Polygone, die unseren Node schneiden, aber trotzdem außerhalb liegen, werden nicht erkannt. Allerdings hatte ich damit bis jetzt keine Probleme.<br />
Das zweite Problem bei dieser Funktion ist, dass Polygone, die sich in mehreren Nodes befinden, auch allen zugeordnet werden und dann eventuell mehrmals gezeichnet werden. Allerdings fand ich noch nicht die Zeit diese Probleme zu beheben.<br />
Falls jemand eine bessere Methode hat, so kann er diese Prozeduren einfach erweitern (verbessern). Ich würde mich sehr über Ratschläge freuen. Eine Möglichkeit ist es, das Polygon an den Nodes in zwei Polygone zu schneiden (Auch Splitting genannt).<br />
<br />
<br />
Nun habt ihr die Berechnung eures Octrees. Es fehlt lediglich das Anzeigen und die Entfernung aus dem Speicher.<br />
<br />
<br />
So zeichnet ihr die Polygone eures Nodes:<br />
<br />
<source lang="pascal"><br />
procedure TNode.drawPolygons;<br />
var<br />
i,j:Integer;<br />
begin<br />
if nump = 0 then exit;<br />
glBegin(GL_TRIANGLES);<br />
for i := 0 to nump-1 do<br />
for j := 0 to 2 do<br />
with poly[i].v[j]^ do<br />
begin<br />
glNormal3fv(@n);<br />
glTexCoord2f(u,v);glVertex3fv(@ver);<br />
end;<br />
glEnd;<br />
end;<br />
</source><br />
<br />
<source lang="pascal"><br />
procedure TNode.check;<br />
var<br />
i:Integer;<br />
begin<br />
if Frustum.IsBoxWithin(<br />
pos.x,pos.y,pos.z,<br />
size,size,size)=TRUE then<br />
begin<br />
if smallest then drawPolygons;<br />
for i:=0 to numc-1 do<br />
if not smallest then children[i].check;<br />
end;<br />
end;<br />
</source><br />
<br />
<br />
Die erste Prozedur zeichnet alle Vektoren in einem Node. Hier tue ich das mit Hilfe einer einfachen Schleife. Displaylisten oder VBOs würden das ganze noch ein wenig beschleunigen, aber die Erklärung dafür würde den Umfang dieses Tutorials zu sehr vergrößern.<br />
<br />
<br />
Interessanter und komplizierter ist die "check"-Prozedur, die überprüft, mit welchen Nodes dies geschehen soll.<br />
<br />
Eure Octree-Klasse muss Zugriff zu eurer Frustum-Culling-Variablen und seiner Unit haben.<br />
Es wird überprüft ob der Node sichtbar ist (IsBoxWithin). Ist dies nicht der Fall, so passiert nichts (auch seine Kinder werden dann nicht überprüft). Ist er sichtbar, so werden seine Polygon gezeichnet (falls er der kleinste Node ist). Außerdem werden dann alle seine Kinder dem selbem Test unterzogen (falls er nicht der kleinste ist). Dies geschieht jetzt mit allen Nodes, die in einem sichtbaren Node sind.<br />
<br />
Dank unseres Baum-Schemas werde alle Nodes, die sich in einem nicht sichtbaren Node befinden erst gar nicht überprüft. Eure FPS-Zahlen können sich dann sehen lassen.<br />
<br />
<br />
So dies zeichnet die Polygone. Jetzt zum zeichnen des Baumes selbst:<br />
<br />
<source lang="pascal"><br />
procedure TNode.draw;<br />
var<br />
i:Integer;<br />
begin<br />
if Frustum.IsBoxWithin(<br />
pos.x,pos.y,pos.z,<br />
size,size,size)=FALSE then exit;<br />
with pos do<br />
begin<br />
glBegin(GL_LINES);<br />
glVertex3f(x-size,y-size,z-size);<br />
glVertex3f(x+size,y-size,z-size);<br />
glVertex3f(x-size,y+size,z-size);<br />
glVertex3f(x+size,y+size,z-size);<br />
glVertex3f(x-size,y-size,z+size);<br />
glVertex3f(x+size,y-size,z+size);<br />
glVertex3f(x-size,y+size,z+size);<br />
glVertex3f(x+size,y+size,z+size);<br />
<br />
glVertex3f(x+size,y+size,z+size);<br />
glVertex3f(x+size,y-size,z+size);<br />
glVertex3f(x+size,y+size,z-size);<br />
glVertex3f(x+size,y-size,z-size);<br />
glVertex3f(x-size,y+size,z+size);<br />
glVertex3f(x-size,y-size,z+size);<br />
glVertex3f(x-size,y+size,z-size);<br />
glVertex3f(x-size,y-size,z-size);<br />
<br />
glVertex3f(x+size,y+size,z+size);<br />
glVertex3f(x+size,y+size,z-size);<br />
glVertex3f(x+size,y-size,z+size);<br />
glVertex3f(x+size,y-size,z-size);<br />
glVertex3f(x-size,y-size,z+size);<br />
glVertex3f(x-size,y-size,z-size);<br />
glVertex3f(x-size,y+size,z+size);<br />
glVertex3f(x-size,y+size,z-size);<br />
glEnd;<br />
end;<br />
if Length(children) > 0 then<br />
for i:=0 to Length(children)-1 do children[i].draw;<br />
end;<br />
</source><br />
<br />
<source lang="pascal"><br />
procedure TOctree.drawOctree(drawPol,drawNodes:Boolean);<br />
begin<br />
if drawPol then<br />
begin<br />
glEnable(GL_TEXTURE_2D);<br />
glEnable(GL_LIGHTING);<br />
MainNode.check;<br />
end;<br />
if drawNodes then<br />
begin<br />
glDisable(GL_TEXTURE_2D);<br />
glDisable(GL_LIGHTING);<br />
glColor3f(1,1,0);<br />
MainNode.draw;<br />
glColor3f(1,1,1);<br />
end;<br />
end;<br />
</source><br />
<br />
<br />
In den ersten Prozeduren gibt es nichts zu beachten, dort wird lediglich ein Node, wenn er sichtbar ist, veranschaulicht, indem er gezeichnet wird und der selbe Test wird mit seinen untergeordneten Nodes durchgeführt. In einer Engine ist das Anzeigen des Nodes ja eher Nebensache.<br />
<br />
Die zweite Prozedur ist nun die "drawOctree" Prozedure. Sie überprüft, ob ihr die Polygone und/oder den Octree zeichnen wollt. Dies wird getrennt durchgeführt, damit wir die vielen StateChanges (glEnable..) vermeiden, da dies unnötig Performance kostet. Sie führt dann die jeweilige Überprüfung mit dem MainNode durch, da unsere oberen Prozeduren dann voll automatisch weiter machen (ist dies nicht wunderbar).<br />
<br />
<br />
Eigentlich wär's das, ihr müsstet nur noch eure Nodes am Ende des Programms aus dem Speicher entfernen. Da ihr alle Nodes mit der Prozedur New() erstellt habt müsst ihr diese nun mit Dispose() für ein und alle mal "vernichten" (auch "Speicherfreigabe" genannt):<br />
<br />
<source lang="pascal"><br />
Procedure TNode.clear;<br />
var<br />
i:Integer;<br />
begin<br />
if Length(children) > 0 then<br />
for i:=0 to Length(children)-1 do children[i].clear;<br />
setLength(children,0);<br />
Dispose(@self);<br />
end;<br />
</source><br />
<br />
<source lang="pascal"><br />
Destructor TOctree.Destroy;<br />
begin<br />
MainNode.clear;<br />
inherited Destroy;<br />
end;<br />
</source><br />
<br />
<br />
Hier seht ihr wieder eine sich selbst aufrufende Prozedur. Mit "Octree.destroy" wird der MainNode als erster zur Vernichtung geschickt.<br />
<br />
Der Algorithmus in "clear" sorgt dafür, dass ein Node erst gelöscht wird, wenn seine Children gelöscht wurden. Diese werden erst gelöscht, wenn deren Children gelöscht wurden usw.<br />
<br />
<br />
Das wars ihr habt einen voll funktionsfähigen Octree.<br />
<br />
In eurem Programm müsst ihr nur noch auf folgendes achten:<br />
*ihr müsst eine Variable erstellen z.B. "octree : TOctree"<br />
*erst müsst ihr am Anfang des Programms eure Vektordaten laden<br />
*diese müssen dann in ein Array gespeichert werden : in eine Polygon-Array "polygons" (TPolygon)<br />
*dann könnt ihr erst euren Octree initialisieren, da die Daten der Vektoren für die Berechnung nötig sind<br />
<br />
<br />
Beim Zeichnen nur noch darauf achten, dass erst die Kamera positioniert wird (glTranslatef und glRotatef), dann muss das Frustum berechnet werden und dann könnt ihr ohne Sorge "octree.drawOctree" aufrufen, dieses zeichnet dann die Polygone. Falls ihr Texturen wünscht, dann diese vorher einbinden.<br />
<br />
==Schluss==<br />
Wie ihr seht war dies ein ganzes Stück Arbeit und dieses Tutorial ist letztendlich doch noch zu seinem Ende gekommen.<br />
<br />
Es wird sicher Alles nicht sofort bei euch klappen, da es auch eine Rolle spielt, wie euer Programm aufgebaut ist.<br />
<br />
Ich bitte um viel Feedback, damit ich sehe wo es Probleme in meiner Formulierung gab.<br />
Es würde mich freuen, wenn es wenigstens bei einer Person klappt, denn dann hat sich meine Mühe für dieses Tut gelohnt.<br />
<br />
Also wenn es bei euch läuft sagt mir Bescheid. Mich würde auch der Frame Unterschied zu vorher interessieren.<br />
<br />
Wenn ihr Probleme habt, ich bin für euch da ;-) Eshat_at_gmx.net<br />
<br />
<br />
Euer<br />
<br />
Eshat aka SoulChild ([http://shadow3d.delphigl.com shadow3d.delphigl.com])<br />
<br />
== Dateien ==<br />
* {{ArchivLink|file=tut_octree_vcl|text=Delphi-VCL-Quelltext mit Windows Binaries}}<br />
{{TUTORIAL_NAVIGATION|-|-}}<br />
<br />
[[Kategorie:Tutorial|Octree]]</div>Komolunahttps://wiki.delphigl.com/index.php?title=Glbitmap_loader&diff=26313Glbitmap loader2015-06-08T20:29:36Z<p>Komoluna: Codebeispiele und Erläuterungen sollten mit der aktuellen Version von glBitmap funktionieren</p>
<hr />
<div>{{Unvollständig}}<br />
= glBitmap - Texturenloader =<br />
<br />
== Warum das Ganze und wo kann ich sie finden? ==<br />
<br />
Früher benutzte ich die glBMP, da sie so "schön" Objekt orientiert war. Leider hatte mein Grafiktreiber zu der Zeit einen Fehler bei der Auswahl des Texturformates. So führte es dazu, dass sobald ich eine Textur mit Alphakanal und dem Standard Texturformat an OpenGL übergab, er als Farbtiefe 16 Bit verwendete. Wenn ich ein Foto genommen hätte wäre mir das wahrscheinlich gar nicht aufgefallen aber dummerweise (oder glücklicherweise) hatte ich aber eine Textur mit einem weichem Farbverlauf. Wie zu erwarten war sah das natürlich alles ziemlich schrecklich aus. Bis dahin kann der Loader ja nichts dafür wenn in einem Treiber ein Fehler existiert. Nur das kuriose an dem Ganzen war, dass meine Textur in Wirklichkeit gar keinen Alphakanal haben durfte. Also habe ich mich auf die Suche nach der Ursache gemacht und bin auch prompt fündig geworden. Der Loader war der Meinung er müsse alle Texturen mit einem Alphakanal versehen ungeachtet der Tatsache ob sie nun einen hatten oder eben nicht. Das ist natürlich eine Sache mit der ich mich nicht abfinden wollte. Kurz darauf begann ich also eine Ableitung der glBMP Texturenklasse zu erstellen und dort musste ich mit Schrecken feststellen, dass die Rechte in der Klasse so ungünstig vergeben wurden, dass ich keine andere Wahl gehabt hätte als direkt die Unit zu editieren. Da ich ungern externe Quellen editiere habe ich für mich die andere Alternative entschieden. Was dabei rausgekommen ist sieht man ja jetzt.<br />
<br />
Gefunden werden kann sie entweder im DGL-SDK oder auf der [http://www.dev-center.de/index.php?cat=header&file=glbitmap Webseite] von [[Benutzer:Lossy eX|Lossy eX]].<br />
<br />
{{Hinweis|Die glBitmap wird in Zukunft von der DelphiGL Community weiterentwickelt und gepflegt. Eine aktuelle Version kann entweder vom [[http://git.delphigl.com/?p=glBitmap.git;a=summary DGL git Repository]] oder unter folgenden Links bezogen werden: <br />
*[[http://git.delphigl.com/?p=glBitmap.git;a=snapshot;h=refs/heads/master;sf=tgz aktuelle Release-Version]]<br />
*[[http://git.delphigl.com/?p=glBitmap.git;a=snapshot;h=refs/heads/unstable;sf=tgz aktuelle Entwickler-Version]]}}<br />
<br />
== Allgemeines und Features ==<br />
<br />
Dieser Artikel geht nicht darauf ein was zu tun ist um in OpenGL eine Textur darstellen zu können. In ihm werde ich lediglich darauf eingehen was man tun kann und muss um mittels der glBitmap eine Textur laden zu können. Außerdem werden die verfügbaren Einstellungen und ihre Wirkungen erklärt. Für alles andere wäre es besser das [[Tutorial_lektion4|Tutorial über Texturen]] durchzulesen.<br />
<br />
Der wichtigste Unterschied zu den bestehenden Loadern bringe ich gleich einmal als erstes. Die glBitmap legt die Texturen anders im Speicher ab. Um zwar im speziellen meine ich damit die 2D Texturen. Bei bestehenden Loadern werden diese Texturen mit der untersten Zeile zu erst im Speicher abgelegt. In der glBitmap werden sie aber mit '''der obersten Zeile zu erst abgelegt'''. Man könnte auch sagen, dass sie bei den bestehenden Loadern auf dem Kopf stehen. Beide Möglichkeiten funktionieren und sind korrekt. Das Einzige was sich in diesem Zusammenhang ändert ist die [[glTexCoord| Adressierung der Texturen]]. Sie müssen entsprechend geändert werden. Sollte das nicht möglich sein so besteht mit der Methode ''FlipVert'' die Möglichkeit die Textur zu spiegeln. Näheres in Abschnitt [[Glbitmap_loader#Texturen_konfigurieren|Texturen konfigurieren]]. Im Normalfall sollte das andere Verhalten nicht zu Problemen führen sondern die Arbeit damit vereinfachen und verständlicher gestalten.<br />
<br />
Die glBitmap holt sich ihre Daten ausschließlich aus Streams. Das zugrundeliegende Format wird automatisch anhand des Inhaltes der Daten ausgewählt. Es besteht also kein Notwendigkeit daran, dass der Entwickler wissen muss um welches Format es sich in Wirklichkeit handelt.<br />
<br />
=== unterstütze Formate ===<br />
<br />
* Windows Bitmaps (*.bmp) Wird Automatisch auf 24 Bit gesetzt sollte es kleiner sein.<br />
* JPEG (*.jpg)<br />
* TARGA (*.tga) komprimiert und unkomprimiert, 24 und 32 Bit. Ursprung unten links oder oben links<br />
* Portable Network Graphics (*.png) 24 Bit mit oder ohne Alphakanal. Es wird eine zusätzliche Bibliothek benötigt.<br />
* [[DDS|Direct Draw Surfaces]] (*.dds) 8,16,24,32 Bit DXT1,DXT3,DXT5, keine Cubemaps, keine Mipmaps<br />
Es besteht auch die Möglichkeit die Bilddaten dynamisch generieren zu lassen oder sie aus einer Instanz der Klasse TBitmap zu laden. Diese Instanz muss dann aber als Pixelformat 24 oder 32 Bit haben.<br />
<br />
<br />
Um PNGs laden zu können muss eine externe Bibliothek namens [http://pngdelphi.sourceforge.net/ PNGImage] eingebunden und das Define ''pngimage'' hinzugefügt werden. Alternativ dazu kann das Define auch in der glBitmap auskommentiert werden.<br />
<br />
== Texturen laden ==<br />
<br />
Das Laden von Texturen kann auf 2 Weg geschehen. Bei Beiden ist aber zu beachten, dass '''OpenGL richtig initialisiert worden sein muss''' bevor man eine Textur erzeugen kann. Was noch sehr wichtig ist. Es sollte niemals eine Textur bei jedem Rendervorgang angelegt und freigegeben werden! Es ist viel effektiver, wenn man die Textur zu beginn lädt und so lange im Speicher behält bis sie nicht mehr benötigt wird. Wenn man sie erst später benötigt, dann kann man sie auch später noch nachladen aber auch dann sollte sie so lange wie nötig existieren.<br />
<br />
=== Procedural ===<br />
<br />
Hierbei genügt der Aufruf einer einzelnen Methode um eine Textur zu laden und diese an OpenGL zu übergeben. Allerdings auf Grund der Einfachheit steht nur das Laden aus Dateien oder Ressourcen zur Verfügung. Zusätzliche Funktionalität können dabei nicht benutzt werden. Generell empfehle ich immer die Objekt orientierte Variante.<br />
<br />
'''var'''<br />
Texture: TGLuint;<br />
<br />
LoadTexture('<font color="blue">myTex\Wall.bmp</font>', Texture, False); ''<font color="green">// Datei laden</font>''<br />
<br />
Damit wird die Datei ''Wall.bmp'' geladen und die TextureID wird in die Variable ''Texture'' geschrieben. Wenn die Textur dann benötigt wird, dann muss man diese entsprechend mit [[glBindTexture]] binden und das benötigte Texturtarget mit [[glEnable]] aktivieren. Das Target ist üblicherweise ''GL_TEXTURE_2D''. Wenn die Textur nicht mehr benötigt wird sollte sie mit [[glDeleteTextures]] auch wieder frei gegeben werden.<br />
<br />
=== Objekt orientiert ===<br />
<br />
Dieser Abschnitt beschäftigt sich ausschließlich mit den 2D Texturen. Aber grundsätzlich lässt sich alles hier erwähnte auch auf die 1D Texturen und die Cubemaps übertragen.<br />
Der Objekt orientierte Weg erfordert zwar eine wenig mehr Schreibarbeit aber nur so kann man den vollen Funktionsumfang der glBitmap genießen.<br />
<br />
Als Erstes müssen wir eine Instanz der Texturenklasse definieren. Dies tun wir vorzugsweise als Member des Fensters auf dem wir zeichnen.<br />
<br />
TForm1 = '''class'''(TForm)<br />
''<font color="green">// Verschiene Elemente und Events des Fensters</font>''<br />
'''private'''<br />
fTexture: TglBitmap2D; ''<font color="green">// Instanz unserer Textur</font>''<br />
'''end;'''<br />
<br />
Nun müssen wir der Textur noch Leben einhauchen.<br />
<br />
'''procedure''' TForm1.FormShow(Sender: TObject);<br />
'''begin'''<br />
''<font color="green">// OpenGL Initialisieren</font>''<br />
<br />
fTexture := TglBitmap2D.Create; ''<font color="green">// Instanz der Klasse erstellen</font>''<br />
fTexture.LoadFromFile('<font color="blue">myTex\Wall.bmp</font>'); ''<font color="green">// Datei laden</font>''<br />
fTexture.GenTexture; ''<font color="green">// geladene Textur an OpenGL übergeben</font>'' <br />
'''end;'''<br />
<br />
Für Schreibfaule besteht auch noch die Möglichkeit in einem überladenen Konstruktor einem Dateinamen anzugeben.<br />
<br />
fTexture := TglBitmap2D.Create('<font color="blue">myTex\Wall.bmp</font>'); ''<font color="green">// Instanz erstellen und Datei laden</font>''<br />
fTexture.GenTexture; ''<font color="green">// geladene Textur an OpenGL übergeben</font>'' <br />
<br />
In GenTexture wird im Normalfall immer überprüft ob die Textur eine gültige Größe hat. Sollte diese Überprüfung nicht gewünscht sein so kann man diese mit einem optionalen Parameter deaktivieren. Diese Überprüfung testet auch ob die Texturgröße eine Potenz von 2 ist (1, 2, 4, 8, 16 usw.) und wenn nicht ob solche Texturen von dem Rendercontex unterstützt werden.<br />
<br />
fTexture.GenTexture(False); ''<font color="green">// Es wird keine Prüfung der Texturgröße vorgenommen.</font>'' <br />
<br />
Wenn kein Fehler aufgetreten ist und alles so funktioniert hat wie es sein sollte, dann kann die Textur benutzt werden. <br />
<br />
fTexture.Bind; ''<font color="green">// Textur und entsprechendes Target wird aktiviert.</font>''<br />
<br />
Sollte es nicht gewünscht werden, dass auch gleichzeitig das Target aktiviert wird so muss Bind mit dem Parameter False aufgerufen werden. Damit wird nur noch die Textur gebunden.<br />
<br />
Sollte man die Textur einmal nicht mehr benutzen wollen so genügt es entweder eine andere Textur zu binden oder Unbind von der Texturenklasse aufzurufen. Damit wird die Textur mit der TexturID 0 gebunden und das Target deaktiviert. Auch hier existiert wieder der Parameter der es verhindert, dass das Target deaktiviert wird.<br />
<br />
Wenn die Anwendung beendet wird müssen wir auch hier unsere Textur wieder frei geben. Dies geschieht so.<br />
<br />
fTexture.Free; ''<font color="green">// Textur wieder frei geben.</font>''<br />
<br />
Hierbei ist zu beachten, dass dies nach Möglichkeit '''vor dem Löschen des Rendercontex''' geschehen sollte, da so die Textur zu einem sinnvollem Zeitpunkt gelöscht werden kann. Wenn der Rendercontex nicht mehr existiert, so sollte die Textur auch nicht mehr existieren und wenn man dann noch einmal versucht sie zu löschen so könnte es zu Problemen führen. Bisher ist mir kein Fall bekannt aber ausschließen kann man es auch nicht. Also zu erst immer die Texturen frei geben und anschließend des Rendercontex löschen.<br />
<br />
== Das leidige Thema Alphakanal ==<br />
<br />
Es gibt zwei Möglichkeiten einen Alphakanal in eine Textur zu integrieren. Der einfachste und schnellste Weg ist, wenn sich dieser Kanal von Beginn an in der Textur befindet. Dazu wird ein Grafikprogramm benötigt welches so etwas unterstützt und ein Dateiformat welches das Speichern eines Alphakanals ermöglicht. Ein solches Programm ist zum Beispiel [http://www.gimp.org/ Gimp]. Als mögliche Dateiformate kämen TGAs und PNGs in Frage. Alle anderen Formate unterstützen keinen Alphakanal. Sollte man sich für diesen Weg entscheiden so genügt es dann, ganz normal die Textur zu laden und zu benutzen und schon besitzen wir einen funktionierenden Alphakanal. Ich persönlich empfehle bis auf wenige Ausnahmen immer diesen Weg.<br />
<br />
Nichts desto trotz habe ich ja gesagt, dass es noch eine Möglichkeit gibt. Bei diesem Weg haben wir Alphakanal und RGB Daten in zwei getrennten Bildern vorliegen. Aber wie bekommen wir das jetzt in ein Bild? Dafür bietet die glBitmap die Möglichkeit einen Alphakanal aus einem separaten Bild zu laden. Zu Beginn benötigen wir jedoch wieder eine Instanz der Klasse und es müssen schon normale Bilddaten geladen worden sein. Und ganz Wichtig damit es überhaupt funktioniert. '''Der Aufruf muss vor ''GenTexture'' stattfinden, da sonst die Textur bereits an OpenGL übergeben wurde.'''<br />
<br />
fTexture.AddAlphaFromFile('<font color="blue">myTex\Wall_alpha.bmp</font>'); ''<font color="green">// Alphakanal aus Datei laden</font>''<br />
<br />
Das war alles nun sind wir im Besitz einer Textur mit einem Alphakanal. Es besteht unter anderem auch die Möglichkeit den Alphakanal aus verschiedenen anderen Quellen zu laden (Resourcen, Streams, TBitmap). Zusätzlich dazu kann man den Kanal aber auch dynamisch erstellen. Dafür existiert die Methode ''AddAlphaFromFunc''. Die Findigen unter euch habe aber bestimmt schon herausgefunden, dass man bei alle Methoden solch eine Function übergeben kann. Näheres dazu findet ihr im Abschnitt ''e = mc²''<br />
<br />
Etwas was häufiger gebraucht wird habe ich von Hause aus schon implementiert. Und zwar das Erstellen eines Alphakanals anhand einer Farbe. <br />
<br />
fTexture.AddAlphaFromColorKey(Red, Green, Blue, Deviation); ''<font color="green">// Alphakanal anhand einer Farbe hinzufügen</font>''<br />
<br />
Dabei wird nur auf vollkommen durchlässig und nicht durchlässig unterschieden. Alle Pixel die die angegebene Farbe besitzen werden dabei als 0 (nicht Sichtbar) in den Alphakanal geschrieben alle anderen erhalten 255 (Sichtbar). Die ''Deviation'' bestimmt eine Abweichung um der die Farben abweichen dürfen um trotzdem noch als Transparent erkannt zu werden. Speziell für JPEGs ist das nicht unwichtig, da die Bilder beim Komprimieren leicht abgewandelt werden.<br />
<br />
Damit die OpenGL Primitiven jetzt transparent dargestellt werden muss der [[GlAlphaFunc|Alphatest]] oder das [[glBlendFunc|Blending]] aktiviert sein. Sonst nützt einem der Alphakanal nicht sonderlich viel.<br />
<br />
Entfernen kann man einen Alphakanal natürlich auch. Dazu genügt der Aufruf von ''RemoveAlpha''. Dieser muss natürlich nicht mit der glBitmap erstellt worden sein. Er kann auch aus einer Datei geladen worden sein.<br />
<br />
fTexture.RemoveAlpha; ''<font color="green">// entfernt den Alphakanal</font>''<br />
<br />
== Texturen konfigurieren ==<br />
<br />
Hier beginnt jetzt der Teil der für die Meisten recht wichtig sein dürfte. Bisher haben wir ja nur Daten geladen und diese an OpenGL übergeben. Nun wollen wir aber ein wenig an den Einstellungen rumschrauben und sehen was wir daraus machen können.<br />
<br />
Folgende Einstellungsmöglichkeiten verändern ausschließlich nur das Verhalten der glBitmap. Sie haben keinen Einfluss auf die resultierende Textur.<br />
<br />
'''''DeleteTextureOnFree''''' ist vom Typ Boolean und gibt an ob beim Freigeben der Klasse die Texture auch freigegeben wird oder ob weiter existieren darf. Standard wird sie mit freigegeben.<br />
<br />
'''''FreeDataAfterGenTexture''''' ist vom Typ Boolean und gibt an ob die Bilddaten nach dem Erzeugen der Textur aus dem Hauptspeicher entfernt werden sollen oder nicht. Im Normalfall werden sie das auch.<br />
<br />
'''''Target''''' ist vom Typ Cardinal und bestimmt das OpenGL Target. Wird von den Klassen auf den Standardwert gesetzt und muss nur dann auf einen anderen Wert gesetzt werden, wenn ein anderes Target verwendet werden soll. Zum Beispiel bei der Verwendung von Texture_rectangle. Es sollte aber immer direkt nach dem erstellen gesetzt werden, da die Textur sonst unbrauchbar gemacht werden könnte.<br />
<br />
'''''Format''''' ist ein Aufzählungstyp und er erlaubt 4 Werte. <br />
{| {{Prettytable}}<br />
|tfDefault<br />
|Dabei wird das Standardformat des Grafikkartentreibers benutzt. Je nach eingestellter Qualität kann dies 16 oder 32 Bit sein.</td><br />
|-<br />
|tf16Bit<br />
|Hier wird die Textur in 16Bit abgelegt.<br />
|-<br />
|tf32Bit<br />
|Hier wird die Textur in 32Bit abgelegt.<br />
|-<br />
|tfCompressed<br />
|Bei diesem Format wird zu erst geschaut ob eines der folgenden Kriterien erfüllt ist. Extension GL_ARB_texture_compression, OpenGL Version 1.3 oder die Extension GL_EXT_texture_compression_s3tc. Sollten alle 3 Möglichkeiten nicht funktionieren so wird das Standardformat vom Grafikkartentreiber benutzt.<br />
|}<br />
<br />
'''''MipMap''''' ist ebenfalls ein Aufzählungstyp und er erlaubt 3 Werte.<br />
{|{{Prettytable}}<br />
|mmNone<br />
|Wie man vermuten könnte werden hierbei keine Mipmaps erstellt.<br />
|-<br />
|mmMipmap<br />
|Ähnlich wie bei komprimierten Texturen werden zu erst verschiedene neue Möglichkeiten überprüft. Ab OpenGL Version 1.4 oder mit der Extension GL_SGIS_generate_mipmap unterstützt die Grafikkarte ein generieren der [[Mipmaps]]. Das ist natürlich wesentlich schneller als der Weg ausschließlich über die Software. Sollte es keinen anderen Weg geben so werden die [[Mipmaps]] mittels der GLU generiert.<br />
|-<br />
|mmMipmapGlu<br />
|In diesem Falle werden die [[Mipmaps]] ausschließlich mit der GLU erstellt.<br />
|}<br />
<br />
Mithilfe der Methoden '''''SetFilter''''' und '''''SetWrap''''' können das Filterverhalten und das Beschränken der Texturkoordinaten angepasst werden. Eine genaue Auflistung möglicher Werte findet man beim Artikel zu [[glTexParameter]]. Das Aufrufen der Methoden ist überall dort möglich wo auch [[glTexParameter]] gültig ist. Mögliche Fehlerhafte Werte werden automatisch auf die vorhandene Textur angepasst. So wird bei SetFilter niemals ein [[MipMaps|MipMap]] bei die Filterung eingestellt wenn keine [[MipMaps]] erzeugt wurden. Das würde sonst dazu führen, dass die Textur nicht dargestellt werden könnte.<br />
<br />
'''''FlipVert''''' und '''''FlipHorz''''' sind Methoden die nichts anderes machen als das Bild entlang der entsprechenden Richtung (Vertikal und Horizontal) zu spiegeln. Dies wäre auch mit der Funktionsschnittstelle möglich aber besonders bei FlipVert wäre es unpraktisch da wir so nicht die komplette Zeile am Stück kopieren könnten, sondern nur Pixel für Pixel.<br />
<br />
Zum Invertieren des Bildes genügt es die Methode '''''Invert''''' aufzurufen. Sie bekommt zwei boolsche Parameter mit denen man steuern kann was man invertieren möchte. Einen für RGB und einen für den Alphakanal.<br />
<br />
Die Methode '''''ToNormalMap''''' wurde implementiert um aus einer 2D Textur eine NormalMap zu erzeugen. Er funktioniert ähnlich wie das NormalMapPlugin für Gimp. Die Methode bekommt 3 Parameter. Der Erste gibt an mit welcher Methode die Normalmap berechnet werden soll. Mögliche Werte hierfür sind<br />
{|{{Prettytable}}<br />
|nm4Samples</td><br />
|Hierbei werden die jeweils geradlinigen benachbarten Pixel zu gleichen Teilen in die Berechnung einbezogen. (Oben, Unten Recht und Links). Diese Methode ist die einfachste, schnellste und empfindlichste gegenüber Farbvariationen.<br />
|-<br />
|nmSobel<br />
|Mit dieser Methode werden fließen benachbarten Pixel zu gleichen Teilen in die Berechnung ein.<br />
|-<br />
|nm3x3<br />
|Bei diese Methode fließen auch alle benachbarten Pixel in die Berechnung ein. Die diagonalen Pixel werden Doppelt gewertet. Die NormalMap wirkt so ruhiger und nicht so anfällig gegen kleine Farbveränderungen.<br />
|-<br />
|nm5x5<br />
|Diese Methode benutzt eine Matrix von 5*5 Pixeln um Ihre Berechnungen durch zu führen. Je weiter die Punkte vom Mittelpunkt entfernt sind so geringer wird deren Einfluss.<br />
|}<br />
<br />
Der zweite Parameter gibt eine Skalierung an. Mögliche Werte hierfür liegen im Bereich von -100 bis 100. Bei einer Skalierung von 0 würde sich die Normalmap Wohlgefallen auflösen, da sie dann praktisch eine gerade Fläche darstellen würde. Die Textur dürfte dann außergewöhnlich gleichfarbig blau werden.<br><br />
Mit dem dritten und letzten Parameter kann man die Berechnung der Normalmap von den RGB Werten auf den Alphakanal verschieben. Die Berechnung zieht sich dann nicht mehr die RGB Werte sondern den Alphakanal zu Rate. Der genaue Nutzen davon liegt zwar momentan selber vor mir verborgen aber wer weiß wozu man so etwas später noch gebrauchen kann. ;-)<br />
<br />
== e = mc² ==<br />
<br />
Hierbei handelt es sich um eine Möglichkeit die Texturdaten zu manipulieren. Die Schnittstelle wurde so gestaltet, dass sie sehr flexibel und typisiert ist. Sprich, dass man immer genau weiß worum es sich handelt und welche Felder unterstützt werden. Eine einfache Handhabung und eine gute Ausführungsgeschwindigkeit waren natürlich auch sehr wichtige Punkte dabei. Finden kann man die Funktionsschnittstelle beim Hinzufügen des Alphakanals oder immer wenn man möchte durch die Methode ''AddFunc''. Es gibt außerdem noch eine Reihe von Funktionen, die intern die Schnittstelle benutzen. Das wären zum Beispiel die Funktionen ''Invert'', ''AddAlphaFromColokey'', ''ToNormalMap'' und ''FillWithColor''. Die Klasse ''TglBitmapNormalMap'' generiert ihre Texturen zum Beispiel mit der Schnittstelle.<br />
<br />
Die Arbeitsweise der Funktionsschnittstelle ist recht einfach. Es wird nichts anderes gemacht als 1 Mal Zeile für Zeile den Pointer eines jeden Pixels an eine Funktion zu Übergeben und darauf zu vertrauen, dass sie das Richtige tut. Um die Ausführung zu Beschleunigen wird ausschließlich mit Pointern gearbeitet. Die Funktionen bekommen die Instanz des Objektes, die Größe, die Position, das Quellpixel, das Zielpixel und einen Pointer auf benutzerdefinierte Daten übergeben. Das ist natürlich eine ganze Menge Holz was da an Daten übergeben aber das ist alles notwendig um die gewünschte Flexibilität erreichen zu können.<br />
<br />
Betrachten wir das ganze mal an einem Beispiel. Und zwar dem Aufruf von ''Invert''. Zu erst einmal der Aufruf der Funktion.<br />
<br />
'''if''' ((UseRGB) '''or''' (UseAlpha)) <br />
'''then''' AddFunc(glBitmapInvertFunc, False, Pointer(Integer(UseAlpha '''and''' HasAlpha) '''shl''' 1 '''or''' Integer(UseRGB)));<br />
<br />
In Zeile 1 handelt es sich lediglich um eine kleine Sicherheit. Es bringt ja nichts, wenn man eine Funktion ausführen möchte die keinen Nutzen hat. Zeile 2 Ruft die Methode ''AddFunc'' auf. Diese Methode bekommt als erstes unsere Funktion übergeben. Zu deren Aufbau komme ich gleich. Als Zweites bekommt ''AddFunc'' gesagt ob sie eine Kopie des Bildes erstellen soll. Für pixelübergreifende Funktionen ist dies unerlässlich, da man sich sonst seine noch benötigten Daten überschreiben würde. Der dritte Wert ist ein Pointer der zusätzliche Informationen hält. In diesem Falle handelt es sich lediglich um ein Bitset bei dem Bit 2 den Alphakanal und Bit 1 die RGB Werte repräsentiert. Es könnte sich dabei aber auch um einen Pointer auf ein Record handeln.<br />
<br />
'''procedure''' glBitmapInvertFunc(Sender : TglBitmap; '''const''' Position, Size: TglBitmapPixelPosition; <br />
'''const''' Source, Dest: TglBitmapPixelData; '''const''' Data: Pointer);<br />
'''begin'''<br />
'''if''' (Integer(Data) '''and''' $1 > 0) '''then begin'''<br />
Dest.ptRed^ := '''not''' Dest.ptRed^;<br />
Dest.ptGreen^ := '''not''' Dest.ptGreen^;<br />
Dest.ptBlue^ := '''not''' Dest.ptBlue^;<br />
'''end;'''<br />
<br />
'''if''' (Integer(Data) '''and''' $2 > 0) '''then begin'''<br />
Dest.ptAlpha^ := '''not''' Dest.ptAlpha^;<br />
'''end;'''<br />
'''end;'''<br />
<br />
'''''Position''''' und '''''Size''''' beinhalten die Aktuelle Position des Pixels und die Größe des Bildes. Das Record TglBitmapPixelPosition beinhält 4 Werte. Fields, X, Y, Z. Fields beschreibt welche Felder überhaupt zur Verfügung stehen. Mögliche Werte Dafür sind ffX, ffY und ffZ. Wofür X, Y und Z stehen erkläre ich jetzt mal nicht, dass sollte jedem klar sein. Bei einem 2D Bitmap sind üblicherweise die Felder X und Y mit leben gefüllt. Das Feld Z liegt brach.<br />
<br />
'''''Source''''' und '''''Dest''''' beinhalten die Pixeldaten. Die Records sind ziemlich genau so aufgebaut wie das für die Position. Es gibt einen Wert ''Fields''. Mögliche Werte für ihn sind ffRed, ffGreen, ffBlue und ffAlpha. Diese Felder sind anders als bei bei Position keine richtigen Werte sondern Pointer die Direkt auf die Farbwerte in den Bildern zeigen. Es gibt deswegen ''Source'' und ''Dest'', da es ja die Möglichkeit gibt eine Kopie des Bildes zu erstellen. Sollte ohne Kopie gearbeitet werden so sind ''Source'' und ''Dest'' gleich. Bei hinzufügen eines Alphakanals bezieht sich ''Source'' auf die Pixeldaten im dem Quellbild und ''Dest'' wie gewohnt auf die Daten im Zielbild.<br />
<br />
In dem obigen Beispiel werden die Bits des Parameters Data ausgewertet und die entsprechenden Kanäle negiert. Der Komplexibilität sind kaum Grenzen gesetzt. Alle Wissensdurstigen unter euch sollten sich dann auch mal die Methode ''ToNormalMap'' anschauen. Dort werden zwei Funktionen aufgerufen. In der Ersten werden Daten gesammelt mit denen in der Zweiten die Normalmap berechnet wird. Oder auch die Klasse ''TglBitmapNormalMap''. In dieser wird eine generelle Berechnungsroutine aufgerufen. Diese bekommt aber für jede Fläche der Map eine andere interne Methode übergeben. Mit dieser werden dann die Werte für jedes Pixel gefüllt.<br />
<br />
Noch ein Wort für alle Geschwindigkeitsfanatiker. Ich hatte ein mal spaßeshalber die Methode ''FlipHorz'' nachgebaut und die Geschwindigkeit gemessen. Das Ergebnis hat mich selber sehr angenehm überrascht. Die Hardcodierte super optimierte Methode benötigte bei 300 Aufrufen, auf ein 512x512 Pixel großes Bild ca. 5 Sekunden. Die Methode mit dem Funktionsaufruf benötigte Lediglich 300 ms länger. Ich selber hätte eher mit dem Doppelten der Zeit gerechnet.<br />
<br />
== Cubemaps mit glBitmap ==<br />
<br />
Das einzige worin sich CubeMaps von 2D Texturen unterscheidet ist das Laden. Aber das ist auch nicht viel komplizierter als bei 2D Texturen. Die Handhabung mit den Texturen (Binden, Frei geben) ist wie bei 2D Texturen weswegen ich das auch nicht noch einmal extra wiederholen werde.<br />
<br />
=== Procedural ===<br />
<br />
Wie auch bei den 2D Texturen haben wir die Auswahl zwischen zwei möglichen Wegen. Der procedurale Weg unterscheidet sich lediglich in der Anzahl der angegebenen Texturen. Das sind diesmal natürlich ein paar mehr.<br />
<br />
'''var'''<br />
Texture: TGLuint;<br />
<br />
''<font color="green">// Cubemaps laden</font>''<br />
LoadCubeMap('<font color="blue">xpos.bmp</font>', '<font color="blue">xneg.bmp</font>', '<font color="blue">ypos.bmp</font>', '<font color="blue">yneg.bmp</font>', '<font color="blue">zpos.bmp</font>', '<font color="blue">zneg.bmp</font>', Texture, False);<br />
<br />
Die ersten 6 Parameter geben die jeweils 6 Texturen an. Die Namen der Parameter geben auch gleichzeitig deren Ziel an. Also immer schön auf die Reihenfolge achten. In dem Siebten wird die Textur ID geschrieben und der Achte gibt an ob aus Resourcen geladen werden soll oder nicht.<br />
<br />
=== Objekt orientiert ===<br />
<br />
Der Objekt orientierte Weg gestaltet sich dieses mal ein wenig schreibintensiver. Es müssen ja auch schließlich 6 Texturen geladen werden. Aber das kann man auch praktischerweise in eine Schleife packen. Das praktische daran ist, dass wir alles mit nur einer Klasseninstanz lösen können (und auch müssen).<br />
<br />
fCubeMap := TglBitmapCubeMap.Create; ''<font color="green">// Instanz der Klasse erstellen</font>''<br />
fCubeMap.LoadFromFile('<font color="blue">xpos.jpg</font>'); ''<font color="green">// Datei Laden</font>''<br />
<br />
Die Textur wird normal angelegt und es wird wie gewöhnt ein Bild in den Speicher der Klasse geladen. Dieses Bild verhält sich wie jedes andere Bild. Es kann also wie gewöhnt manipuliert werden. Zum Beispiel durch die Funktionsschnittstelle.<br />
<br />
fCubeMap.GenerateCubeMap(GL_TEXTURE_CUBE_MAP_POSITIVE_X); ''<font color="green">// Einzelnen Teil übergeben</font>''<br />
<br />
Wenn die Textur also bereit zum Übergeben ist, dann müssen wir ''GenerateCubeMap'' mit dem entsprechenden Teil der Cubemap aufrufen. In diesem Falle ist es die positive X Achse. Das müssen wir dann natürlich noch mit allen anderen Maps machen. '''''Also Bild laden, evtl bearbeiten und dann an OpenGL übergeben.''''' Die Reihenfolge der Maps spielt hierbei keine Rolle. Wichtig ist nur, dass sie die selbe Auflösung und das selbe Format haben. Die Methode ''GenTexture'' steht bei dieser Klasse nicht zur Verfügung, da beim ersten Aufruf von GenerateCubeMap automatisch die OpenGL Textur erzeugt wird. '''''Die CubeMap ist nur dann einsetzbar, wenn alle Maps erfolgreich mit Daten versorgt wurden.'''''<br />
<br />
Beim Binden der CubeMap existiert ein zusätzlicher Parameter mit dem man die Aktivierung der automatische Generation der Texturkoordinaten deaktivieren kann. Standard ist dieses eingeschalten. Ähnlich wie beim Binden einer Textur. Dort kann man verhindern, dass das Target aktiviert wird.<br />
<br />
== Normalmaps mit glBitmap ==<br />
<br />
[[Normalmap|NormalMaps]] sind nichts anderes als Spezielle Cubemaps. Sie dienen dazu um Per Pixel Normale auch auf Systemen ohne Shaderhardware zu ermöglichen. Benutzt werden kann das zum Beispiel bei Bumpmapping mit [[GL_ARB_texture_env_dot3]].<br />
<br />
=== Procedural ===<br />
<br />
Wie auch bei den 2D Texturen und Cubemaps haben wir die Auswahl zwischen zwei möglichen Wegen. Da diese Texturen dynamisch generiert werden fällt die Anzahl der Parameter ziemlich gering aus. Sie besteht lediglich aus einer Texturgröße. In diesem Falle haben die resultierenden Texturen eine Größe von 32x32 Pixeln. Der zweite Parameter ist ein altbekannter von uns. Er ermöglicht es uns eine TexturID zu empfangen. Auf die Handhabung mit dieser ID gehe ich nicht noch einmal ein, da das oberhalb schon oft genug besprochen wurde.<br />
<br />
'''var'''<br />
Texture: TGLuint;<br />
<br />
''<font color="green">// Normalmaps erzeugen</font>''<br />
LoadNormalMap(32, Texture);<br />
<br />
=== Objekt orientiert ===<br />
<br />
Dieser Weg ist etwa genau so schreibintensiv wie der Procedurale. Hierbei wird eine Normalmap erstellt bei der einzelnen Texturen eine Größe von 32x32 Pixeln haben.<br />
<br />
fNormalMap := TglBitmapNormalMap.Create; ''<font color="green">// Instanz der Klasse erstellen</font>''<br />
fNormalMap.GenerateNormalMap(32); ''<font color="green">// Normalmap erzeugen</font>''<br />
<br />
Erstaunlich aber wahr. Das war bereits alles. Von nun an kann die Textur wie jede andere CubeMap auch verwendet werden.<br />
<br />
== Bekannte Probleme und Einschränkungen ==<br />
<br />
Vor einer Weile wurde im Forum die Frage gestellt warum die glBitmap beim Laden eines BMPs einen "Stream Read Error" produziert. Da das Bitmap nun mal ein sehr einfaches Format ist hat mich das auch sehr stark verwundert. Nach langem hin und her Rätseln kam ich dann dennoch darauf was das Problem war. Es lag daran, dass das Bitmap mit MS Paint abgespeichert wurde. Dieser war aber der Meinung er müsse im Bitmapheader eine Größe angeben die 2 Bytes größer war als die eigentlichen Daten. Diese 2 Bytes wurden auch aufgefüllt aber leider ist das TBitmap, welches ich zum Laden verwende, nicht so tolerant um darüber hinweg zu sehen. Und so bekommt man einen Fehler beim Laden. Den selben Fehler würde man auch bekommen wenn man das Bild in einem TImage anzeigen wollte.<br />
<br />
Abhelfen kann man dies in dem man ein [http://www.gimp.org/ alternatives Grafikprogramm (Gimp)] verwendet oder das Bild einmal mit dem Bildbetrachter [http://www.irfanview.de/ IrfanView] öffnet und abspeichert.<br />
<br />
Es muss nicht bei jedem mit MS Paint abgespeicherten Bild auftreten.</div>Komolunahttps://wiki.delphigl.com/index.php?title=Matrixstack&diff=26312Matrixstack2015-05-29T21:48:50Z<p>Komoluna: liegen -> liegt</p>
<hr />
<div>{{Hinweis|Seit Version 3.0 bietet OpenGL keinen eigenen Matrix-Stack mehr. Wer diese oder neuere OpenGL-Versionen nutzen möchte, muss ihn daher bei Bedarf selbst implementieren. Moderne Programmiersprachen bringen bereits Templates/generische Klassen für die Datenstruktur [[Stack]] an, was eine Menge Arbeit und Fehler erspart. In C++ z.B. std::stack.}}<br />
<br />
==Was ist das?==<br />
Die deutsche Übersetzung von '''STACK''' erklärt fast schon alles: Ein [[Stack]] ist ein Stapel. Und ein Matrixstack entsprechend ein Stapel mit Matrizen. Das besondere an der Datenstruktur '''Stack''' ist:<br />
* Neue Werte werden auf den Stack gelegt (liegen immer ganz oben!)<br />
* Werte können nur von der Spitze des Stacks entnommen werden (Speicherprinzip '''LIFO''' ''Last In First Out'')<br />
* Zugriff auf Daten die nicht ganz oben liegen ist nicht erlaubt.<br />
<br />
<br />
==Was nützt das?==<br />
Durch den '''LIFO''' Zugriff erreicht man eine Art Hierarchie. Dadurch ist es leicht möglich "die letzte Matrix" wiederherzustellen. Sie liegt ja unter der aktuellen Matrix auf dem Stack.<br />
<br />
OpenGL kann verschieden viele Matrizen auf einen Stack legen. Wieviel genau kann mittels [[glGet]] und den Token GL_MAX_MODELVIEW_STACK_DEPTH, GL_MAX_PROJECTION_STACK_DEPTH bzw. GL_MAX_TEXTURE_STACK_DEPTH ermittelt werden. <br><br />
''(Es gibt noch weitere Stacks. Z.B. den Name Stack und den Attribut Stack)''<br />
<br />
<br />
==Wie arbeite ich mit dem Matrixstack?==<br />
Wer glaubt, dass man nichts machen müsste um auf den Matrixstack zu zugreifen der liegt richtig. Allerdings nur bezüglich der obersten Matrix. Wenn man eine Matrix auf den Stack legen will oder die letzte vom Stack holen will, dann benötigt man noch die beiden Befehle [[glPushMatrix]] und [[glPopMatrix]]<br />
<br />
<br />
==Client - Server Problem==<br />
Der gerade beschriebene Matrixstack befindet sich auf dem Server (OpenGL ist ein Client Server System. Siehe [[OpenGL|Beschreibung von OpenGL]]). <br><br />
''Es gibt aber auch einen Stack der lokal beim Clienten liegt (dieser Speichert Clientattribute). Für diesen Stack gibt es die Befehle [[glPushClientAttrib]] und [[glPopClientAttrib]].''</div>Komolunahttps://wiki.delphigl.com/index.php?title=K%C3%BCnstliches_neuronales_Netz&diff=26299Künstliches neuronales Netz2015-03-02T19:45:04Z<p>Komoluna: </p>
<hr />
<div>{{Offline}} <br />
=Was ist ein "Künstliches neuronales Netz/Netz"=<br />
[[Bild:Artificial_neural_network.png|mini|Ein neuronales Netz mit nur einer versteckten Schicht]]<br />
Ein künstliches neuronales Netz (in diesem Artikel "das Netz" oder "ANN" für "artificial neural net") ist einem biologischen Gehirn(deinem Denkdings) nachempfunden, und kann somit auch komplexere Probleme lösen.<br />
Mathematische Funktion ist hier nicht nur als "echte" Funktion sondern als Gleichnis für allerlei mathematische Probleme zu sehen, z.B:<br />
*Eine KI-Steuerung für NPCs um komplexe Verhaltensweisen zu simulieren<br />
*Verschiedenste Mustererkennungen<br />
*Funktionen die nicht mit einer Formel beschrieben werden können (XOR-Gate)<br />
In diesem Artikel werden sogenannte "Feed-forward" Netze und Additionsneuronen mit sigmoider Funktion behandelt(siehe Bild). Feed-forward heißt, dass die Informationen im Netz immer nur in eine Richtung weitergereicht werden. Das bedeutet, dass das Netz sich nichts merken kann und seine Outputs zu 100% auf den Inputs basieren.<br />
<br />
Das Netz besteht aus 3 Typen von Schichten:<br />
{| {{Prettytable_B1}}}<br />
!Typ<br />
!Funktion<br />
|-<br />
|Inputschicht<br />
|Die Transferwerte werden manuell festgelegt. Die Neuronen in dieser Schicht haben keine eingehenden Verbindungen.<br />
|-<br />
|Versteckte Schicht<br />
|Von diesem Schichttyp können beliebig viele Hintereinandergeschaltet werden. Die versteckten Schichten sollten weder von außen gesehen, noch modifiziert werden.<br />
|-<br />
|Ausgabeschicht<br />
|Diese Schicht besitzt nur eingehende Verbindungen, da ihre Transferwerte direkt vom Programm ausgelesen und je nach Verwendungszweck des Netzes verwertet werden.<br />
|}<br />
<br />
=Vor/Nachteile=<br />
*Vorteile<br />
**Komplexe Handlungsweisen<br />
**Lernfähigkeit<br />
*Nachteile<br />
**keine exakten Ergebnisse(nur Annäherung)<br />
**[http://de.wikipedia.org/wiki/K%C3%BCnstliches_neuronales_Netz#Allgemeine_Probleme siehe Wikipedia]<br />
=Funktionsweise=<br />
==Das Netz==<br />
Das Netz besteht aus mehreren Neuronen, die miteinander verbunden sind.<br />
Jede Verbindung besitzt eine Wichtung, die den Einfluss des Senderneurons auf das Zielneuron bestimmt.<br />
==Das Neuron==<br />
[[Bild:ArtificialNeuronModel_deutsch.png|mini|Ein Neuron]]<br />
Ein einzelnes Neuron kann man als mathematische Funktion definieren, da immer mehrere Werte in ein Output umgewandelt werden.<br />
Im Verlauf der Berechnung werden 2 Variablen und eine Konstante benötigt:<br />
===Der Aktivierungswert===<br />
Ergibt sich aus der Summe der Transferwerte der verbundenen Senderneuronen multipliziert mit der Wichtung der jeweiligen Verbindung: <br />
<source lang="pascal">activation := 0;<br />
for i:=0 to High(Connections) do<br />
activation := activation + Connections[i].Sender.Transfer * Connections[i].Weight</source><br />
===Der Transferwert===<br />
Meist eine [http://de.wikipedia.org/wiki/Sigmoidfunktion Sigmoidfunktion] an die der Aktivierungswert übergeben wird:<br />
<source lang="pascal">Transfer := 1 / (1 + exp(-activation)) + Bias;</source><br />
===Der Bias===<br />
Dieser Wert wird nur verändert, wenn das Netz lernen soll. <br />
Im "normalen" Gebrauch bleibt der Bias konstant und dient der Verschiebung des Transferwerts</div>Komolunahttps://wiki.delphigl.com/index.php?title=Datei:Artificial_neural_network.png&diff=26298Datei:Artificial neural network.png2015-03-02T10:29:03Z<p>Komoluna: Wikipedia:
http://commons.wikimedia.org/wiki/Network_diagram?uselang=de</p>
<hr />
<div>Wikipedia:<br />
http://commons.wikimedia.org/wiki/Network_diagram?uselang=de</div>Komolunahttps://wiki.delphigl.com/index.php?title=Datei:ArtificialNeuronModel_deutsch.png&diff=26297Datei:ArtificialNeuronModel deutsch.png2015-03-01T22:14:11Z<p>Komoluna: Wikipedia:
http://commons.wikimedia.org/wiki/Artificial_neural_network?uselang=de</p>
<hr />
<div>Wikipedia:<br />
http://commons.wikimedia.org/wiki/Artificial_neural_network?uselang=de</div>Komolunahttps://wiki.delphigl.com/index.php?title=K%C3%BCnstliches_neuronales_Netz&diff=26295Künstliches neuronales Netz2015-03-01T21:59:48Z<p>Komoluna: Komoluna verschob die Seite Künstliches neurales Netz nach Künstliches neuronales Netz</p>
<hr />
<div>{{Unvollständig}}<br />
=Was ist ein "Künstliches neuronales Netz/Netz"=<br />
Ein künstliches neuronales Netz (in diesem Artikel "das Netz" oder "ANN" für "artificial neural net") ist einem biologischen Gehirn(deinem Denkdings) nachempfunden, und kann fast jede beliebige mathematische Funktion beschreiben.<br><br />
Mathematische Funktion ist hier nicht nur als "echte" Funktion sondern als Gleichnis für allerlei mathematische Probleme zu sehen, z.B:<br />
*Eine KI-Steuerung für NPCs um komplexe Verhaltensweisen zu simulieren<br />
*Verschiedenste Mustererkennungen<br />
*Funktionen die nicht mit einer Formel beschrieben werden können (XOR-Gate)<br />
<br />
In diesem Artikel werden sogenannte "Feed-forward" Netze und Additionsneuronen mit sigmoider Funktion behandelt. Feed-forward heißt, dass die Informationen im Netz immer nur in eine Richtung weitergereicht werden. Das bedeutet, dass das Netz sich nichts merken kann und seine Outputs zu 100% auf den Inputs basieren.<br />
<br />
=Vor/Nachteile=<br />
==Vorteile==<br />
*Komplexe Handlungsweisen<br />
*Lernfähigkeit<br />
==Nachteile==<br />
*keine exakten Ergebnisse(nur Annäherung)<br />
=Funktionsweise=<br />
==Das Netz==<br />
Das Netz besteht aus mehreren Neuronen, die miteinander verbunden sind.<br />
Jede Verbindung besitzt eine Wichtung, die den Einfluss des Senderneurons auf das Zielneuron bestimmt.<br />
==Das Neuron==<br />
Ein einzelnes Neuron kann man als mathematische Funktion definieren, da immer mehrere Werte in ein Output umgewandelt werden.<br />
Im Verlauf der Berechnung werden 2 Variablen benötigt:<br />
===Der Aktivierungswert===<br />
Ergibt sich aus der Summe der Transferwerte der verbundenen Senderneuronen mal der Wichtung der jeweiligen Verbindung: {{INLINE_CODE|activation = C[i].Sender.Transfer * C[i].Weight}}</div>Komolunahttps://wiki.delphigl.com/index.php?title=K%C3%BCnstliches_neurales_Netz&diff=26296Künstliches neurales Netz2015-03-01T21:59:48Z<p>Komoluna: Komoluna verschob die Seite Künstliches neurales Netz nach Künstliches neuronales Netz</p>
<hr />
<div>#WEITERLEITUNG [[Künstliches neuronales Netz]]</div>Komolunahttps://wiki.delphigl.com/index.php?title=K%C3%BCnstliches_neuronales_Netz&diff=26294Künstliches neuronales Netz2015-03-01T21:56:55Z<p>Komoluna: Die Seite wurde neu angelegt: „{{Unvollständig}} =Was ist ein "Künstliches neuronales Netz/Netz"= Ein künstliches neuronales Netz (in diesem Artikel "das Netz" oder "ANN" für "artificial…“</p>
<hr />
<div>{{Unvollständig}}<br />
=Was ist ein "Künstliches neuronales Netz/Netz"=<br />
Ein künstliches neuronales Netz (in diesem Artikel "das Netz" oder "ANN" für "artificial neural net") ist einem biologischen Gehirn(deinem Denkdings) nachempfunden, und kann fast jede beliebige mathematische Funktion beschreiben.<br><br />
Mathematische Funktion ist hier nicht nur als "echte" Funktion sondern als Gleichnis für allerlei mathematische Probleme zu sehen, z.B:<br />
*Eine KI-Steuerung für NPCs um komplexe Verhaltensweisen zu simulieren<br />
*Verschiedenste Mustererkennungen<br />
*Funktionen die nicht mit einer Formel beschrieben werden können (XOR-Gate)<br />
<br />
In diesem Artikel werden sogenannte "Feed-forward" Netze und Additionsneuronen mit sigmoider Funktion behandelt. Feed-forward heißt, dass die Informationen im Netz immer nur in eine Richtung weitergereicht werden. Das bedeutet, dass das Netz sich nichts merken kann und seine Outputs zu 100% auf den Inputs basieren.<br />
<br />
=Vor/Nachteile=<br />
==Vorteile==<br />
*Komplexe Handlungsweisen<br />
*Lernfähigkeit<br />
==Nachteile==<br />
*keine exakten Ergebnisse(nur Annäherung)<br />
=Funktionsweise=<br />
==Das Netz==<br />
Das Netz besteht aus mehreren Neuronen, die miteinander verbunden sind.<br />
Jede Verbindung besitzt eine Wichtung, die den Einfluss des Senderneurons auf das Zielneuron bestimmt.<br />
==Das Neuron==<br />
Ein einzelnes Neuron kann man als mathematische Funktion definieren, da immer mehrere Werte in ein Output umgewandelt werden.<br />
Im Verlauf der Berechnung werden 2 Variablen benötigt:<br />
===Der Aktivierungswert===<br />
Ergibt sich aus der Summe der Transferwerte der verbundenen Senderneuronen mal der Wichtung der jeweiligen Verbindung: {{INLINE_CODE|activation = C[i].Sender.Transfer * C[i].Weight}}</div>Komolunahttps://wiki.delphigl.com/index.php?title=Shadersammlung&diff=26288Shadersammlung2014-11-29T12:53:16Z<p>Komoluna: </p>
<hr />
<div>==Was sind Shader?==<br />
Die traditionelle [[Feste_Funktionspipeline|Funktionspipeline]] der OpenGL ist sehr beschränkt, neuere [[Algorithmus|Algorithmen]] erfordern eine viel höhere Flexibilität. [[Shader]] sind kleine Programme die es erlauben Teile der Funktionspipeline völlig frei zu programmieren. Dies bietet völlig neue Möglichkeiten. Auf der einen Seite sind Shader für Einsteiger eine gewisse Hürde, auf der anderen Seite können sie viele Dinge aber auch enorm vereinfachen. Aus diesem Grund wurde in OpenGL 3.1 sowie OpenGL ES 2.0 die feste Funktionspipeline entfernt, so dass Shader dort verpflichtend sind.<br />
<br />
Der Artikel [[Shader]] gibt einen ausführlichen Überblick zum Thema sowie eine [[Shader#Wie_geht_es_nun_weiter.3F|Linksammlung]] für den Einstieg.<br />
<br />
==Shader hinzufügen==<br />
Die Shadersammlung braucht deine Hilfe um zu wachsen. Wenn du einen Shader bereitstellen könntest wäre dies ein toller Dienst für die Community.<br />
<br />
Wer einen Shader zur Shadersammlung hinzufügen möchte, findet am Ende dieses Seite eine [[#Vorlage|Vorlage]].<br />
<br />
==Schwierigkeitsgrad==<br />
Es ist nicht leicht einen Schwierigkeitsgrad für Shader anzugeben, trotzdem haben wir dies einmal versucht. Der Schwierigkeitsgrad kann zumindest für Einsteiger einen groben Hinweis geben was man sich vielleicht mal anschauen könnte.<br />
{|{{Prettytable_B1}} style="margin-left:50px;"<br />
| {{TableHead}} | {{ShaderLevel|1}}<br />
| Der Shader ist für Einsteiger geeignet. Um den Shader herum wird keine zusätzliche Infrastruktur benötigt.<br />
|-<br />
| {{TableHead}} | {{ShaderLevel|2}}<br />
| Der Shader ist für Einsteiger geeignet, benötigt aber etwas zusätzliche Infrastruktur. Etwa benötigt ein Post-Processing-Shader ein [[FBO|FrameBufferObject]], für [[Bumpmapping]] wird eine [[Normalmap]] benötigt.<br />
|-<br />
| {{TableHead}} | {{ShaderLevel|3}}<br />
| Mittlerer Schwierigkeitsgrad. Der Shader ist etwas komplizierter und/oder benötigt viel zusätzliche Infrastruktur.<br />
|-<br />
| {{TableHead}} | {{ShaderLevel|4}}<br />
| Hoher Schwierigkeitsgrad. Der Shader ist kompliziert und/oder verwendet intensiv Extensions.<br />
|-<br />
| {{TableHead}} | {{ShaderLevel|5}}<br />
| Extremer Schwierigkeitsgrad...alles was es sonst noch gibt.<br />
|}<br />
<br />
==GLSL-Shader==<br />
Die hier gelisteten Shader sind in Kategorien aufgeteilt. Weitere Kategorien dürfen bei Bedarf einfach ergänzt werden.<br />
<br />
===Beleuchtung und Texturen===<br />
Diese Kategorie umfasst alles vom einfachen Fixed-Function-Pipeline-Ersatz über PerPixel-Licht und Bumpmapping bis zu ShadowMaps. Der Shader-Einsteiger wird in dieser Kategorie sicherlich fündig.<br />
{|{{Prettytable_B1}} width=100%<br />
| {{TableHead}} | [[shader_verysimple|Verysimple]] von [[Benutzer:damadmax|damadmax]] {{ShaderLevel|1}}<br />
| {{Table150R2}} style="text-align:center;" | (kein Bild vorhanden)<br />
|-<br />
| {{TableCell}} | Ein einfacher Shader, welcher eine Textur an Vertices bindet. Dieser Shader baut damit das Standardverhalten der festen Pipeline nach. {{ShaderLink|shader_verysimple}}<br />
|-<br />
| {{TableHead}} | [[shader_PerPixelLighting|Per Pixel-Beleuchtung]] von [[Benutzer:Ireyon|Ireyon]] {{ShaderLevel|1}}<br />
| {{Table150R2}} | [[Bild:shader_ppl.png|150px|150px]]<br />
|-<br />
| {{TableCell}} | Shader, der Per Pixel beleuchtet. {{ShaderLink|shader_PerPixelLighting}}<br />
|-<br />
| {{TableHead}} | [[shader_PerPixel_Lighting2|Per Pixel-Beleuchtung2]] von [[Benutzer:Olee|Olee]] {{ShaderLevel|1}}<br />
| {{Table150R2}} | [[Bild:PPLShader.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Beleuchtet Flächen nach Pixeln anstatt wie OpenGl-Licht je Vertex. Erlaubt unendlich weit entferntes Licht und beachtet [[glFog]]. {{ShaderLink|shader_PerPixel_Lighting2}}<br />
|-<br />
| {{TableHead}} | [[shader_Bumpmapping|BumpmappingShader]] von [[Benutzer:Bergmann89|Bergmann89]] {{ShaderLevel|2}}<br />
| {{Table150R2}} | [[Bild:Bumpmapping.JPG|150px|150px]]<br />
|-<br />
| {{TableCell}} | BumpmappingShader auf der Basis des [[shader_PerPixelLighting|Per Pixel-Beleuchtung]]-Shaders {{ShaderLink|shader_Bumpmapping}}<br />
|-<br />
| {{TableHead}} | [[shader_ConeVolumeShadow|Kegelvolumen-Schatten ]] von [[Benutzer:Coolcat|Coolcat]] {{ShaderLevel|3}}<br />
| {{Table150R2}} | [[Bild:shader_ConeVolumeShadow2.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Spezialshader für realistische Schatten einer Kugellichtquelle. Kugellichtquellen erzeugen im Gegensatz zu den üblichen Punktlichtquellen weiche Schatten. Dieser Ansatz ist im Vergleich extrem schnell, da er nur eine Erweiterung des gewöhnlichen Per-Pixel-Lighting darstellt. Allerdings funktioniert dieser Shader nur dann, wenn es sich bei sämtlichen Schatten werfenden Objekten in der Szene um Kugeln handelt. {{ShaderLink|shader_ConeVolumeShadow}}<br />
|}<br />
<br />
===Post-Processing===<br />
Post-Processing-Shader zeichnen sich dadurch aus, dass sie auf die gesamte Szene angewendet werden <u>nachdem</u> diese bereits gerendert wurde. Üblicherweise wird die Szene zuerst mit einem [[FBO|FramebufferObject]] (FBO) in eine Textur gerendert. Anschließend wird diese Textur auf ein bildschirmfüllendes Quad gespannt und mit dem Post-Processing-Shader gerendert.<br />
{|{{Prettytable_B1}} width=100%<br />
| {{TableHead}} | [[shader_sepia|Sepia-Shader]] von [[Benutzer:Markus|Markus]] {{ShaderLevel|2}}<br />
| {{Table150R2}} | [[Bild:shader_sepia_nachher.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Post-Processing-Shader, welcher einen Sepia-Farbfilter auf die Szene anwendet. {{ShaderLink|shader_sepia}}<br />
|-<br />
| {{TableHead}} | [[shader_radial_blur|Radial Blur]] von [[Benutzer:Markus|Markus]] {{ShaderLevel|2}}<br />
| {{Table150R2}} | [[Bild:shader_radial_blur_nachher.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Post-Processing-Shader, welcher die Szene ausgehend von einem beliebigen Punkt verwischt. {{ShaderLink|shader_radial_blur}}<br />
|-<br />
| {{TableHead}} | [[shader_blur2|Blur-Shader]] von [[Benutzer:Skeptiker|Skeptiker]] und [[Benutzer:Coolcat|Coolcat]] {{ShaderLevel|3}}<br />
| {{Table150R2}} | [[Bild:Shader_blur_seerose_blured_small.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Post-Processing-Shader, welcher die Szene insgesamt verwischt. Dieser Shader kann beispielsweise genutzt werden um einen Glow-Effekt zu erreichen. {{ShaderLink|shader_blur2}}<br />
{{excIcon}} Excellenter Artikel<br />
|-<br />
| {{TableHead}} | [[shader_Stereoscopy|Stereoskopie]] von [[Benutzer:Joni|Joni]] {{ShaderLevel|2}}<br />
| {{Table150R2}} | [[Bild:shader_stereo_preview.png|150px|150px]]<br />
|-<br />
| {{TableCell}} | Sammlung von Post-Processing-Shadern, welche ein linkes und ein rechtes Bild als Stereogramm mit verschiedenen Methoden (verschiedene Anaglyphen, Zeilenverschachtelung, ...) anzeigen. {{ShaderLink|shader_Stereoscopy}}<br />
|}<br />
<br />
===Geometrie===<br />
Hier finden sich Shader die die Geometrie entweder komplett neu erzeugen oder stark verändern. Es muss nicht unbedingt Geometryshader oder Instancing sein, auch mit dem Vertexshader kann man schon viel anstellen. Ein klassisches Beispiel ist die Mesh-Animation.<br />
{|{{Prettytable_B1}} width=100%<br />
| {{TableHead}} | [[shader_Terrain_GPU4|Heightmap-Terrain]] von [[Benutzer:Coolcat|Coolcat]] {{ShaderLevel|3}}<br />
| {{Table150R2}} | [[Bild:Terrain.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Shader für ein Heightmap-Terrain der ShaderModel 4.0 Features nutzt. Das Terrain wird zur Laufzeit fast vollständig aus der Heightmap generiert, was ordentlich Speicherplatz spart. Im Fragmentshader werden drei Texturlayer mit Hilfe einer Alphamap interpoliert {{ShaderLink|shader_Terrain_GPU4}}<br />
<br />
'''Extensions:'''<br><br />
[[GL_EXT_gpu_shader4]]<br />
|-<br />
| {{TableHead}} | [[shader_Instancing|Instancing-Shader]] von [[Benutzer:Coolcat|Coolcat]] {{ShaderLevel|4}}<br />
| {{Table150R2}} | [[Bild:shader_Instancing.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Dieser Shader zeigt die Benutzung von [[GL_ARB_draw_instanced]]. Ein häufiger Anwendungsfall ist das rendern vieler gleichartiger Objekte. Die Extension beschleunigt derartige Anwendungen, in dem die Anzahl der API-Aufrufe und die Menge redundanter Daten reduziert wird. {{ShaderLink|shader_Instancing}}<br />
<br />
'''Extensions:'''<br><br />
[[GL_ARB_draw_instanced]]<br><br />
[[GL_EXT_gpu_shader4]]<br><br />
[[GL_EXT_texture_buffer_object]]<br><br />
[[GL_ARB_texture_float]]<br />
|-<br />
| {{TableHead}} | [[shader_tesselation|Tesselation-Shader]] von [[Benutzer:dj3hut1|dj3hut1]] {{ShaderLevel|4}}<br />
| {{Table150R2}} | [[Bild:Tesselation_s.png|150px|150px]]<br />
|-<br />
| {{TableCell}} | Dieser Shader nutzt einen Geometry Shader um ein Dreieck zu tesselieren. {{ShaderLink|shader_tesselation}}<br />
<br />
'''Extensions:'''<br><br />
[[GL_ARB_geometry_shader4]]<br />
|-<br />
| {{TableHead}} | [[shader_normal_debug|Normal Debugging-Shader]] von [[Benutzer:dj3hut1|dj3hut1]] {{ShaderLevel|4}}<br />
| {{Table150R2}} | [[Bild:Normal_debug_s.png|113px|150px]]<br />
|-<br />
| {{TableCell}} | Nützlicher Shader um ohne viel Aufwand die Normalen eines Modells anzuzeigen. {{ShaderLink|shader_normal_debug}}<br />
<br />
'''Extensions:'''<br><br />
[[GL_ARB_geometry_shader4]]<br />
|}<br />
<br />
===Partikel===<br />
Natürlich kann man auch bei einem [[Partikelsystem]] Shader einsetzen. Mit etwas Geschick kann man die gesamte Berechnung sogar vollständig auf die Grafikkarte verlagern um die CPU zu entlasten.<br />
{|{{Prettytable_B1}} width=100%<br />
| {{TableHead}} | [[GLSL_Partikel_2|GPU Partikelsystem]] von [[Benutzer:Coolcat|Coolcat]] {{ShaderLevel|5}}<br />
| {{Table150R2}} | [[Bild:Partikel-Gravitation.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Ein GPU-Partikelsystem welches insbesondere auf SM4 Features wie Geometryshader und Transform-Feedback setzt. So ist auch eine Partikel-Partikel-Interaktion mit über 200.000 Partikeln ist kein Problem. {{ShaderLink|GLSL_Partikel_2}}<br />
<br />
'''Extensions:'''<br><br />
[[GL_EXT_geometry_shader4]]<br><br />
[[GL_NV_transform_feedback]]<br><br />
[[GL_EXT_gpu_shader4]]<br><br />
[[GL_EXT_texture_buffer_object]]<br><br />
[[GL_ARB_texture_float]]<br><br />
[[GL_EXT_texture_integer]]<br />
|-<br />
| {{TableHead}} | [[GLSL_Partikel|GPU Partikelsystem für alte Hardware]] von [[Benutzer:Oc2k1|Oc2k1]] {{ShaderLevel|5}}<br />
| {{Table150R2}} style="text-align:center;" | (kein Bild vorhanden)<br />
|-<br />
| {{TableCell}} | Ebenfalls ein GPU-Partikelsystem, welches aber auf FramebufferObjects und Fragmentshader setzt. Damit sollte es auch auf älterer Hardware funktionieren. {{ShaderLink|GLSL_Partikel}}<br />
<br />
'''Extensions:'''<br><br />
[[GL_ARB_texture_float]]<br />
|}<br />
<br />
===Sonstiges===<br />
Hier kommt alles rein was sonst nirgendwo rein passt und eine neue Kategorie nicht lohnenswert ist.<br />
{|{{Prettytable_B1}} width=100%<br />
| {{TableHead}} | [[shader_game_of_life|Game of Life]] von [[Benutzer:dj3hut1|dj3hut1]] {{ShaderLevel|3}}<br />
| {{Table150R2}} | [[Bild:Game_of_life_s.png|150px|150px]]<br />
|-<br />
| {{TableCell}} | Simuliert das altbekannte 'Game of Life' im Shader. {{ShaderLink|shader_game_of_life}}<br />
|-<br />
| {{TableHead}} | [[shader_Zufallsgenerator|Pseudozufallsgenerator]] von [[Benutzer:Coolcat|Coolcat]] {{ShaderLevel|4}}<br />
| {{Table150R2}} | [[Bild:shader_Zufallsgenerator.png|150px|150px]]<br />
|-<br />
| {{TableCell}} | Generierung von Pseudozufallszahlen im Shader mit [[GL_EXT_gpu_shader4]]. Außerdem eine Beispielanwendung: Ein reproduzierbares pesudozufälliges Verwirbelfeld für ein GPU-Partikelsystem. {{ShaderLink|shader_Zufallsgenerator}}<br />
<br />
'''Extensions:'''<br><br />
[[GL_EXT_gpu_shader4]]<br />
|-<br />
| {{TableHead}} | [[shader_Mandelbrot|Mandelbrotfraktal Shader]] von [[Benutzer:Komoluna|Komoluna]]<br />
| {{Table150R2}} | [[Bild:Mandelbrotshader blackwhite.png|150px|150px]]<br />
|-<br />
| {{TableCell}} | Ein Shader zum generieren eines Mandelbrotfraktals. {{ShaderLink|shader_Mandelbrot}}<br />
|-<br />
|}<br />
<br />
==Non-GLSL-Shader==<br />
In diesem Abschnitt findet ihr Shader die mit einer anderen Technik als GLSL geschrieben wurden.<br />
<br />
{|{{Prettytable_B1}} width=100%<br />
| {{TableHead}} | [[shader_texturing(ARB)|Texturing (ARB)]] von [[Benutzer:dj3hut1|dj3hut1]] {{ShaderLevel|1}}<br />
| {{Table150R2}} | [[Bild:Texarb_textured_s.png|166px|150px]]<br />
|-<br />
| {{TableCell}} | Demonstriert eine einfache Texturierung. {{ShaderLink|shader_texturing(ARB)}}<br />
|-<br />
| {{TableHead}} | [[shader_phong_per_pixel(ARB)|Phong per Pixel (ARB)]] von [[Benutzer:dj3hut1|dj3hut1]] {{ShaderLevel|1}}<br />
| {{Table150R2}} | [[Bild:Phong_arb_s.png|150px|150px]]<br />
|-<br />
| {{TableCell}} | Per-Pixel-Beleuchtung. {{ShaderLink|shader_phong_per_pixel(ARB)}}<br />
|-<br />
| {{TableHead}} | [[shader_diffuse_bumpmapping(Cg)|Diffuse Bumpmapping (NVIDIA-Cg)]] von [[Benutzer:igel457|igel457]] {{ShaderLevel|2}}<br />
| {{Table150R2}} | [[Bild:shader_diffuse_bumpmapping_cg.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Wendet diffuses Bumpmapping auf eine beliebige Oberfläche an. {{ShaderLink|shader_diffuse_bumpmapping(Cg)}}<br />
|-<br />
| {{TableHead}} | [[shader_surface_scattering(ARB)|Surface Scattering (ARB)]] von [[Benutzer:dj3hut1|dj3hut1]] {{ShaderLevel|3}}<br />
| {{Table150R2}} | [[Bild:Scattering_s.jpg|150px|150px]]<br />
|-<br />
| {{TableCell}} | Der Shader bestimmt die Distanz, die Licht durch ein Material zurücklegt. Auf diese Weise wird die Lichtdurchlässigkeit bestimmt. {{ShaderLink|shader_surface_scattering(ARB)}}<br />
|-<br />
|}<br />
<br />
==Vorlage==<br />
Die Shadersammlung braucht deine Hilfe um zu wachsen. Wenn du einen Shader bereitstellen könntest wäre dies ein toller Dienst für die Community.<br />
<br />
Folgende Schritte müssen gemacht werden um einen Shader einzutragen:<br />
# Erstelle mit Hilfe der [[Shaderartikelvorlage]] einen neuen Artikel. Dazu den wiki-Code der Vorlage einfach kopieren und in den neuen Artikel einfügen. Der Artikelname sollte mit dem Präfix <tt>shader_</tt> beginnen, z.B. <tt>shader_Wasser2d</tt> für einen 2D Wassershader.<br />
# Da Shader zu 90% optische Effekte bewirken, sollte (mindestens) ein aussagekräftiges Beispielbild im Shaderartikel hinterlegt werden. Eines der Bilder sollte dann auch hier in der Liste verlinkt werden.<br />
# Füge deinen Shader in die Shadersammlung ein. Verwende dazu dieses Template:<br><tt> |-</tt><br><tt> | <nowiki>{{TableHead}} | [[shader_Wasser2d|2D Wassershader]] von [[Benutzer:DeinName|DeinName]]</nowiki></tt><br><tt> | <nowiki>{{Table150R2}} | [[Bild:Wassershader2D.jpg|150px|150px]]</nowiki></tt><br><tt> |-</tt><br><tt> | <nowiki>{{TableCell}}</nowiki> | Einige Sätze zur Beschreibung des Shaders. <nowiki>{{ShaderLink|shader_Wasser2d}}</nowiki></tt><br><tt> </tt><br><tt><nowiki>'''Extensions:'''<br></nowiki></tt><br><tt>Liste von notwendigen Extensions.</tt><br><tt> |-</tt><br />
# Keine Angst, es muss nicht alles auf Anhieb perfekt sein.<br />
<br />
Falls du Fragen oder Probleme mit der Vorlage hast, im [[DGL-Chat]] oder [http://www.delphigl.com/forum/ Forum] hilft man immer gerne.</div>Komolunahttps://wiki.delphigl.com/index.php?title=shader_Mandelbrot&diff=26287shader Mandelbrot2014-11-29T12:17:27Z<p>Komoluna: </p>
<hr />
<div>=Mandelbrot Shader=<br />
Zurück zur [[Shadersammlung]]<br />
{|{{Prettytable_B1}} width=100%<br />
!width=60%|Beschreibung<br />
!width=20%|Autor<br />
!width=20%|Version<br />
|-<br />
|Ein Shader zum generieren eines Mandelbrotfraktals<br />
|Komoluna<br />
|1.0<br />
|}<br />
<br />
==Bilder==<br />
{|<br />
|[[Bild:Mandelbrotshader blackwhite.png|200px|thumb|Screenshot des Shaders bei der Arbeit]]<br />
|}<br />
<br />
==Beschreibung==<br />
Dieser Shader zeichnet abhängig von den Texturkoordinaten ein Mandelbrotfraktal [http://de.wikipedia.org/wiki/Mandelbrot-Menge (Mandelbrot-Menge)].<br />
Ein Fraktal ist ein Muster oder eine Figur, deren Teile eine ähnlich Form haben, wie das gesamte Objekt. (Bsp: Romanesco-Brokkoli oder eine Schneeflocke)<br />
<br><br><br />
Die Uniform Variable camera wird folgendermaßen verwendet:<br />
{|{{Prettytable_B1}} width=50%<br />
!width=10%|camera[0]<br />
!width=15%|camera[1]<br />
!width=15%|camera[2]<br />
|-<br />
|Zoomfaktor (Default = 1)<br />
|Verschiebung auf der X Achse (Default = 0)<br />
|Verschiebung auf der Y Achse (Default = 0)<br />
|}<br />
<br />
==Besondere Vorraussetzungen==<br />
Viel Grafikprozessorleistung ;-)<br />
<br><br />
Da für jedes Pixel eine lange(je nach Position) Schleife durchlaufen werden muss, ist der Shader leider sehr resourcenfressend. Daher sollte man ihn eher auf guten Grafikkarten verwenden und die Bildschirmflächen, auf denen der Shader angewendet wird eher klein halten.<br />
<br />
==Code==<br />
<b>Ich wäre für Tipps zur Performanceverbesserung sehr dankbar...</b><br />
===Vertexshader===<br />
<source lang="glsl">void main()<br />
{<br />
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;<br />
gl_TexCoord[0] = gl_MultiTexCoord0; //Wichtig, da sonst nicht auf die Texturkoordinaten zugegriffen werden kann.<br />
}</source><br />
===Fragmentshader===<br />
<source lang="glsl">#version 120<br />
<br />
uniform vec3 camera = vec3(1,0,0);<br />
<br />
uniform int MaxIter = 1000;<br />
<br />
void main()<br />
{<br />
vec2 tc = vec2(gl_TexCoord[0]);<br />
<br />
float x0 = (tc.x * 3 - 2) * camera[0] + camera[1];<br />
float y0 = (tc.y * 2 - 1) * camera[0] + camera[2];<br />
<br />
float x = 0;<br />
float y = 0;<br />
int iteration = 0;<br />
<br />
while ((x * x + y * y <= 4) && (iteration < MaxIter))<br />
{<br />
float xtemp = x * x - y * y + x0;<br />
y = 2 * x * y + y0;<br />
x = xtemp;<br />
<br />
iteration += 1;<br />
}<br />
<br />
if (iteration == MaxIter)<br />
{<br />
/*<br />
Hier wird der Farbwert für das Innere der Mandelbrotmenge gesetzt<br />
*/<br />
gl_FragColor = vec4(0, 0, 0, 1);<br />
}<br />
else<br />
{<br />
/*<br />
Hier kann eine beliebige Farbwahl stattfinden(z.B. mit einer Farbtabelle).<br />
als Index verwendet man die Variable "iteration", die einen Wert zwischen 1 und MaxIter hat.<br />
*/<br />
x = sin(float(iteration));<br />
gl_FragColor = vec4(x, x, x, 1);<br />
}<br />
<br />
}</source></div>Komolunahttps://wiki.delphigl.com/index.php?title=shader_Mandelbrot&diff=26286shader Mandelbrot2014-11-29T12:11:32Z<p>Komoluna: </p>
<hr />
<div>=Mandelbrot Shader=<br />
Zurück zur [[Shadersammlung]]<br />
{|{{Prettytable_B1}} width=100%<br />
!width=60%|Beschreibung<br />
!width=20%|Autor<br />
!width=20%|Version<br />
|-<br />
|Ein Shader zum generieren eines Mandelbrotfraktals<br />
|Komoluna<br />
|1.0<br />
|}<br />
<br />
==Bilder==<br />
{|<br />
|[[Bild:Mandelbrotshader blackwhite.png|200px|thumb|Screenshot des Shaders bei der Arbeit]]<br />
|}<br />
<br />
==Beschreibung==<br />
Dieser Shader zeichnet abhängig von den Texturkoordinaten ein Mandelbrotfraktal [http://de.wikipedia.org/wiki/Mandelbrot-Menge (Mandelbrot-Menge)].<br />
Ein Fraktal ist ein Muster oder eine Figur, deren Teile eine ähnlich Form haben, wie das gesamte Objekt. (Bsp: Romanesco-Brokkoli oder eine Schneeflocke)<br />
<br />
==Besondere Vorraussetzungen==<br />
Viel Grafikprozessorleistung ;-)<br />
<br><br />
Da für jedes Pixel eine lange(je nach Position) Schleife durchlaufen werden muss, ist der Shader leider sehr resourcenfressend. Daher sollte man ihn eher auf guten Grafikkarten verwenden und die Bildschirmflächen, auf denen der Shader angewendet wird eher klein halten.<br />
<br />
==Code==<br />
<b>Ich wäre für Tipps zur Performanceverbesserung sehr dankbar...</b><br />
===Vertexshader===<br />
<source lang="glsl">void main()<br />
{<br />
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;<br />
gl_TexCoord[0] = gl_MultiTexCoord0; //Wichtig, da sonst nicht auf die Texturkoordinaten zugegriffen werden kann.<br />
}</source><br />
===Fragmentshader===<br />
<source lang="glsl">#version 120<br />
<br />
uniform vec3 camera = vec3(1,0,0);<br />
<br />
uniform int MaxIter = 1000;<br />
<br />
void main()<br />
{<br />
vec2 tc = vec2(gl_TexCoord[0]);<br />
<br />
float x0 = (tc.x * 3 - 2) * camera[0] + camera[1];<br />
float y0 = (tc.y * 2 - 1) * camera[0] + camera[2];<br />
<br />
float x = 0;<br />
float y = 0;<br />
int iteration = 0;<br />
<br />
while ((x * x + y * y <= 4) && (iteration < MaxIter))<br />
{<br />
float xtemp = x * x - y * y + x0;<br />
y = 2 * x * y + y0;<br />
x = xtemp;<br />
<br />
iteration += 1;<br />
}<br />
<br />
if (iteration == MaxIter)<br />
{<br />
/*<br />
Hier wird der Farbwert für das Innere der Mandelbrotmenge gesetzt<br />
*/<br />
gl_FragColor = vec4(0, 0, 0, 1);<br />
}<br />
else<br />
{<br />
/*<br />
Hier kann eine beliebige Farbwahl stattfinden(z.B. mit einer Farbtabelle).<br />
als Index verwendet man die Variable "iteration", die einen Wert zwischen 1 und MaxIter hat.<br />
*/<br />
x = sin(float(iteration));<br />
gl_FragColor = vec4(x, x, x, 1);<br />
}<br />
<br />
}</source></div>Komolunahttps://wiki.delphigl.com/index.php?title=shader_Mandelbrot&diff=26285shader Mandelbrot2014-11-29T12:10:32Z<p>Komoluna: Seite erstellt</p>
<hr />
<div>=Mandelbrot Shader=<br />
Zurück zur [[Shadersammlung]]<br />
{|{{Prettytable_B1}} width=100%<br />
!width=60%|Beschreibung<br />
!width=20%|Autor<br />
!width=20%|Version<br />
|-<br />
|Ein Shader zum generieren eines Mandelbrotfraktals<br />
|Komoluna<br />
|1.0<br />
|}<br />
<br />
==Bilder==<br />
{|<br />
|[[Bild:Mandelbrotshader blackwhite.png|200px|thumb|Screenshot des Shaders bei der Arbeit]]<br />
|}<br />
<br />
==Beschreibung==<br />
Dieser Shader zeichnet abhängig von den Texturkoordinaten ein Mandelbrotfraktal [http://de.wikipedia.org/wiki/Mandelbrot-Menge (Mandelbrot-Menge)].<br />
Ein Fraktal ist ein Muster oder eine Figur, deren Teile eine ähnlich Form haben, wie das gesamte Objekt. (Bsp: Romanesco-Brokkoli oder eine Schneeflocke)<br />
<br />
==Besondere Vorraussetzungen==<br />
Viel Grafikprozessorleistung ;-)<br />
<br><br />
Da für jedes Pixel eine lange(je nach Position) Schleife durchlaufen werden muss, ist der Shader leider sehr Resourcenfressend. Daher sollte man ihn entweder nur mit guten Grafikkarten verwenden und die Bildschirmflächen, auf denen der Shader angewendet wird klein halten.<br />
<br />
==Code==<br />
<b>Ich wäre für Tipps zur Performanceverbesserung sehr dankbar...</b><br />
===Vertexshader===<br />
<source lang="glsl">void main()<br />
{<br />
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;<br />
gl_TexCoord[0] = gl_MultiTexCoord0; //Wichtig, da sonst nicht auf die Texturkoordinaten zugegriffen werden kann.<br />
}</source><br />
===Fragmentshader===<br />
<source lang="glsl">#version 120<br />
<br />
uniform vec3 camera = vec3(1,0,0);<br />
<br />
uniform int MaxIter = 1000;<br />
<br />
void main()<br />
{<br />
vec2 tc = vec2(gl_TexCoord[0]);<br />
<br />
float x0 = (tc.x * 3 - 2) * camera[0] + camera[1];<br />
float y0 = (tc.y * 2 - 1) * camera[0] + camera[2];<br />
<br />
float x = 0;<br />
float y = 0;<br />
int iteration = 0;<br />
<br />
while ((x * x + y * y <= 4) && (iteration < MaxIter))<br />
{<br />
float xtemp = x * x - y * y + x0;<br />
y = 2 * x * y + y0;<br />
x = xtemp;<br />
<br />
iteration += 1;<br />
}<br />
<br />
if (iteration == MaxIter)<br />
{<br />
/*<br />
Hier wird der Farbwert für das Innere der Mandelbrotmenge gesetzt<br />
*/<br />
gl_FragColor = vec4(0, 0, 0, 1);<br />
}<br />
else<br />
{<br />
/*<br />
Hier kann eine beliebige Farbwahl stattfinden(z.B. mit einer Farbtabelle).<br />
als Index verwendet man die Variable "iteration", die einen Wert zwischen 1 und MaxIter hat.<br />
*/<br />
x = sin(float(iteration));<br />
gl_FragColor = vec4(x, x, x, 1);<br />
}<br />
<br />
}</source></div>Komolunahttps://wiki.delphigl.com/index.php?title=Datei:Mandelbrotshader_blackwhite.png&diff=26284Datei:Mandelbrotshader blackwhite.png2014-11-29T11:05:03Z<p>Komoluna: Ein Screenshot des Mandelbrotshaders in der Shadersammlung.</p>
<hr />
<div>Ein Screenshot des Mandelbrotshaders in der Shadersammlung.</div>Komoluna