C for graphics
C for Graphics (Abkürzung: Cg) war eine von Nvidia begründete High Level Shader Language (nicht zu verwechseln mit High Level Shading Language) zum Schreiben von Vertex-Shader-, Pixel-Shader-, Geometry-Shader- und Tessellation-Shader-Programmen. Die Sprache ist weitestgehend unabhängig von der zugrunde liegenden Grafik-API- (OpenGL und DirectX) und dem Grafikkartenhersteller (Nvidia und ATI).
Hochsprache
Die Entwicklung einer Shader-Hochsprache wurde dadurch motiviert, dass das Programmieren von Vertex- und Pixel-Shadern in Maschinensprache recht kompliziert und schnell unübersichtlich ist. Weitere Shader-Hochsprachen sind GLSL, GLSL ES, HLSL und RenderMan. Einen anderen Ansatz verfolgt Sh als Metasprache.
Syntax
Cg ähnelt von der Syntax her der Programmiersprache C. Bestandteile sind u. a. einfache Datentypen, Arrays, Bedingungen und Schleifen. Aufgrund der Zusammenarbeit zwischen NVIDIA und Microsoft ist die Syntax von Cg sehr stark an HLSL angelehnt.
Datentypen
- int (32bit integer)
- float (32bit floating point)
- half (16bit floating point)
- fixed (12bit fixed point, 1-1-10)
- double
- bool
- sampler (für Texturobjekte)
Es sei darauf hingewiesen, dass auf manchen Grafikkarten alles auf float gerechnet wird.
Hinzu kommen die entsprechenden Vektoren und Matrizen: float2, float3, float4, float4x4.
Parameter
Ausgabe-Parameter werden mit out gekennzeichnet:
out float4 pos : POSITION; // Eckpunkt, der vom Vertex-Programm weitergegeben wird
out float4 color : COLOR; // Farbe, die vom Vertex-Programm weitergegeben wird
Uniform-Parameter werden außerhalb vom Vertex-Programm gesetzt und ändern sich nicht pro Eckpunkt:
z. B. in einem OpenGL-Programm:
CGparameter timeParam = cgGetNamedParameter(vertexProgram, "time");
CGparameter modelviewParam = cgGetNamedParameter(vertexProgram, "modelview");
cgGLSetParameter1f(timeParam, 100);
cgGLSetStateMatrixParameter(modelviewParam, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY);
Verwendung dann im Vertex-Programm:
uniform float time;
uniform float4x4 modelview;
Zugriff auf OpenGL State
Normalerweise erfolgt der Zugriff über Uniform-Parameter. Diese Parameter müssen im OpenGL-Programm immer neu gesetzt werden. Im Falle eines ARB-Profils ist der Zugriff auf einen OpenGL State möglich, z. B.
glstate.matrix.mvp // Projection * Modelview
Profile
Ein weiterer Aspekt ist die Möglichkeit zum Kompilieren für verschiedene Profile. Das sind verschiedene Versionen von Vertex- bzw. Fragment-Programmen, von denen automatisch das bestmögliche für die vorhandene Hardware aktiviert wird:
CGprofile vertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
cgGLSetOptimalOptions(vertexProfile);
CGprofile fragmentProfile = cgGLGetLatestProfile(CG_GL_FRAGMENT);
cgGLSetOptimalOptions(fragmentProfile);
Profil ausgeben lassen:
cgGetProfileString(fragmentProfile)
Einbindung und Programmierung
Die erstellten Programm-Codes können separat kompiliert und als externe Quelle in ein lauffähiges Hochsprachen-Programm (z. B. C++) eingebunden oder alternativ erst zur Laufzeit übersetzt werden.
Es muss zunächst ein Kontext (Speicher für Programme) erzeugt und dann das Programm kompiliert werden:
CGcontext context = cgCreateContext();
CGprogram program = cgCreateProgramFromFile(context, CG_SOURCE, filename, profile, "main", NULL);
cgGLLoadProgram(program); // Programm laden
Anschließend erfolgen Aktivierung und Auswahl des Programms:
// Profil aktivieren (und Programm aktivieren)
cgGLEnableProfile(CGProfile profile);
…
// Ab hier läuft jeder glVertex() durchs eigene Vertex Program
…
// Profil (und Programm deaktivieren)
cgGLDisableProfile(CGProfile profile)
…
// Ab jetzt läuft wieder jeder glVertex() durch die Standard OpenGL
// Pipeline
…
// Aktuelles Vertex/Fragment Program festlegen
cgGLBindProgram(myVertexProgram);
Vor- und Nachteil
Vorteil
Da Cg sowohl Platform- als auch Grafikschnittstellen unabhängig ist, muss ein Shader nur einmal in Cg geschrieben werden und kann für nahe zu jedes Render-System verwendet werden. Arbeitet ein Programmierer mit GLSL und HLSL müssen Shader Effekte mehrfach geschrieben werden.
Nachteil
Während die Cg Shader auf Grafikkarten mit NVIDIA GPU (z. B. der GeForce Serie) weitestgehend optimal laufen, ist die Umsetzung für andere Grafik-Chips, wie denen von AMD (z. B. der Radeon Serie) meist eher schlecht. Darauf haben die anderen Chip-Hersteller – wie eben AMD – jedoch keinen direkten Zugriff, da das Cg Toolkit nur von NVIDIA entwickelt wird.
Weblinks
- Cg bei NVIDIA (englisch)