Um Eigenschaften und Positionierung von Licht in OpenGL zu verstehen, musste ich es mir erst visualisieren. Das Ergebnis teile ich gerne mit euch.
Es sind ein paar API Aufrufe dabei, es ist aber alles sehr überschaubar gehalten.
Meine Top 3 Learnings waren: - Glanzlichter sind doch gar nicht so schwer - Platzierung von Licht ist unbeeindruckt von Pushs und Pops - Die Lichtgenauigkeit ist direkt von der Dreiecksanzahl abhängig
$H OpenGL.ph
declare time&, frames%
declare rtri!, light#
declare white#,red#, green#,blue#, zero#, list&,loop&
dim light#,16
dim white#,16
dim red#,16
dim green#,16
dim blue#,16
dim zero#,16
FloatArray(white#,1,1,1,1)
FloatArray(red#,1,0,0,1)
FloatArray(green#,0,1,0,1)
FloatArray(blue#,0,0,1,1)
FloatArray(zero#,0,0,0,1)
FloatArray(light#,-0.05,-0.05,-0.05, 1.0)
PROC GRID
'Es gibt bessere Möglichkeiten, Gitter zu erstellen aber für dieses Beispiel reicht es, ein einzelner Quad würde
'nicht vernünftig beleuchtet werden (siehe Würfel) "per-vertex lighting"
parameters size!, resolution!
if list& = 0
list& = ogl("StartList")
oGL("Move", -(size! * 0.5)-(size! / resolution! * 0.5),(size! * 0.5)-(size! / resolution! * 0.5), 0)
whileloop 1, int(resolution!)
oGL("Move", (size! / resolution!),-size!, 0)
loop& = &loop
whileloop 1, int(resolution!)
if ((&loop + loop&) MOD 2) = 0
oGL("Color", 0.2,0.2,0.2,1.0)
else
oGL("Color", 1.0,1.0,1.0,1.0)
endif
oGL("Move", 0.0, (size! / resolution!), 0)
oGL("Quad", (size! / resolution!),(size! / resolution!))
endwhile
endwhile
ogl("EndList")
endif
ogl("Drawlist", list&)
ENDPROC
Proc Light
'Zur besseren Veranschaulichung in Proc gekapselt, wenn es um Performance geht nimmt man einen fertigen Bereich,
'Definition von allem aus Position würde auch einmal bei Initialisierung reichen, das Objekt dient der Visualisierung
'der Lichtposition. Das Grundlicht (Ambient) ist leicht negativ gesetzt da es aus irgendeinem Grund bei "0" noch etwas
'Licht gibt
parameters no&, r!, g!, b!
declare color#
dim color#, 16
FloatArray(color#,r!, g!, b!, 1.0)
oGL("glMaterialfv", ~GL_FRONT_AND_BACK, ~GL_EMISSION, color#)
oGL("Color", r!, g!, b!, 1.0)
oGL("Cuboid", 0.15, 0.15, 0.15)
oGL("glMaterialfv", ~GL_FRONT_AND_BACK, ~GL_EMISSION, zero#)
oGL("glLightfv",~GL_LIGHT0 + no&,~GL_AMBIENT,light#)'GL_AMBIENT
oGL("glLightfv",~GL_LIGHT0 + no&,~GL_DIFFUSE, color#)' GL_DIFFUSE
oGL("glLightfv",~GL_LIGHT0 + no&,~GL_POSITION,zero#)' GL_POSITION
oGL("glLightfv",~GL_LIGHT0 + no&,~GL_SPECULAR, white#)' GL_SPECULAR
oGL("glEnable",~GL_LIGHT0 + no&)
dispose color#
Endproc
proc DrawGLScene
oGL("Clear")
oGL("Move", 0, 0.75, -5.0)
oGL("glMaterialfv",~GL_FRONT_AND_BACK, ~GL_SPECULAR, white#)' Glanzlichtfarbe
oGL("glMaterialf", ~GL_FRONT_AND_BACK, ~GL_SHININESS,128.0)' Glanzlichtgröße (große Zahl ist kleiner, max 128.0)
oGL("glDisable",~GL_LIGHT0)'Default Licht aus
'-------
'Lichtpositionen lassen sich nicht durch Push/Pop kapseln!
'Jegliche Positionierung muss also danach wieder negiert werden, bei Rotationen achsenweise
'und alles immer in umgekehrter Reihenfolge - eine Aufnahme davon in der Light()-Funktion wäre denkbar
'LICHTER
oGL("Rotate",0,0, rtri!)
oGL("Move", 2.0, 0,0)
'Light(Lichtnummer, Rot, Grün, Blau)
Light(1,1,0,0)' rot
oGL("Move", -2.0, 0,0)
oGL("Rotate", 0,0,-rtri!)
oGL("Rotate",0,90,0)
oGL("Rotate",0,0, rtri!)
oGL("Move", 2.0, 0,0)
Light(2,0,1,0)' grün
oGL("Move", -2.0, 0,0)
oGL("Rotate", 0,0,-rtri!)
oGL("Rotate", 0,-90,0)
oGL("Rotate", 0, rtri!,0)
oGL("Move", 2.5, 0,0)
Light(3,0,0,1)' blau
oGL("Move", -2.5, 0,0)
oGL("Rotate", 0, -rtri!,0)
'OBJEKTE
oGL("Color", 1, 1, 1, 1)
'etwas in der gegen herumschauen:
oGL("Rotate",sin(rtri!*0.01) * 10.0, sin(rtri!*0.01) * 20.0, sin(rtri!*0.01) * 5.0)
oGL("Push")'Boden
oGL("Move", 0, -2.2, -4)
oGL("Rotate",270, 0,0)
GRID(20,40)
oGL("Pop")
oGL("Push")'Würfel, nur sehr eingeschränktes Lighting
oGL("Move", -0.65, 0.5, 0)
oGL("Rotate", -45, 45, 0)
oGL("Cuboid", 0.75, 0.75,0.75)
oGL("Pop")
oGL("Push")'Kugel, mit vielen Dreiecken siehts richtig gut aus
oGL("Move", 1, 0, 0)
oGL("Sphere", 0.65, 192,192)
oGL("Pop")
oGL("Push")'Kegel / Cone
oGL("Move", 2.5, -1.5, -1.0)
oGL("Cylinder", 1.0, 0,2.0,192)
oGL("Pop")
oGL("Push")'Cylinder, sieht auch mit wenigen Unterteilungen schon gut aus
oGL("Move", -2.0, -0.5, -1.5)
oGL("Rotate", -15, -30, 30)
oGL("Cylinder", 0.20, 0.20,4,30)
oGL("Pop")
oGL("Show")
rtri! = rtri! + 1
endproc
Proc FloatArray
parameters x&,a!,b!,c!,d!
long x&,0 = single(a!)
long x&,4 = single(b!)
long x&,8 = single(c!)
long x&,12 = single(d!)
Endproc
' Hauptprogramm
' -------------
declare ende%
CLS 0
oGL("Init", %hWnd, 0,0,0,1)
oGL("PosMode", 1)
oGL("glEnable",~GL_CULL_FACE)
oGL("glEnable",~GL_DEPTH_TEST)
oGL("BlendMode", 1)
oGL("Fog", 3, 6, 14)
time& = &GetTickCount
frames% = 0
ende% = 0
WhileNot ende%
'WaitInput sollte in 3D-Anwendungen und Spielen in jedem Fall vermieden werden,
'da dort auch ohne timer ca. 8 ms unkontrollierbar verschwinden
if isKey(27)
ende% = 1
endif
DrawGLScene()
inc frames%
if &GetTickCount - time& >= 1000' 1 Sekunde ist 'rum
setText %hWnd, str$(frames%) + " Frames/sek"
time& = &GetTickCount
frames% = 0
endif
EndWhile
end
|