Introduction to Cg Ed Angel Professor of Computer Science, Electrical and Computer Engineering, and Media Arts Director, Arts Technology Center University of New Mexico
Introduction Cg = C for graphics - C-like language for programming vertex and fragment shaders References - R. Fernando and M. Kilgard, The Cg Tutorial, Addison-Wesley - Cg Users Manual, available on-line 2
Cg Model 3
Writing Program We can write and compile shaders independently and load them as either source or assembly code - Compiler cgc cgc simple.cg flags Or use sdk Can hand optimize assembly - Tie to OpenGL or Direct X program through runtime libraries cc openglprog.c lglut lglu lgl lcg lcggl.. 4
Simple Vertex Shader struct C2E1v_Output float4 position : POSITION; float4 color : COLOR; }; define an output structure C2E1v_Output C2E1v_green(float2 position : POSITION) vertex C2E1v_Output OUT; location OUT.position = float4(position, 0, 1); OUT.color = float4(0, 1, 0, 1); // RGBA green } return OUT; 5
Vertex Shader Vertex shader must output a position Can also output other information such as a color Note use of constructor to form 4 dimensional position for output Other state information is unchanged Next example is a pass through fragment shader that does nothing 6
Simple Fragment Shader struct C2E2f_Output float4 color : COLOR; }; C2E2f_Output C2E2f_passthrough(float4 color : COLOR) C2E2f_Output OUT; OUT.color = color; return OUT; } 7
Fragment Shader Must produce a color Can also output other information Gets color as an input since the fragment program takes in the output of the rasterizer 8
Interfacing with OpenGL Unlike C, Cg code is platform dependent because not all GPUs have the same capabilities - Describe GPU capabilities by profiles - Compile for a profile Must interface with a Cg runtime library and OpenGL specific library Establish a Cg context, Cg variables, and links to OpenGL variables 9
Cg Vertex Shading Example 10
simple.cg // Define inputs from application. struct appin float4 Position : POSITION; float4 Normal : NORMAL; }; // Define outputs from vertex shader. struct vertout float4 HPosition : POSITION; float4 Color : COLOR; }; 11
simple.cg (cont) vertout main(appin IN, uniform float4x4 ModelViewProj, uniform float4x4 ModelViewIT, uniform float4 LightVec) vertout OUT; // Transform vertex position into homogenous clip-space. OUT.HPosition = mul(modelviewproj, IN.Position); // Transform normal from model-space to view-space. float3 normalvec = normalize(mul(modelviewit, IN.Normal).xyz); 12
simple.cg (cont) // Store normalized light vector. float3 lightvec = normalize(lightvec.xyz); // Calculate half angle vector. float3 eyevec = float3(0.0, 0.0, 1.0); float3 halfvec = normalize(lightvec + eyevec); // Calculate diffuse component. float diffuse = dot(normalvec, lightvec); // Calculate specular component. float specular = dot(normalvec, halfvec); // Use the lit function to compute lighting vector from // diffuse and specular values. float4 lighting = lit(diffuse, specular, 32); 13
simple.cg (cont) // Blue diffuse material float3 diffusematerial = float3(0.0, 0.0, 1.0); // White specular material float3 specularmaterial = float3(1.0, 1.0, 1.0); // Combine diffuse and specular contributions and // output final vertex color. OUT.Color.rgb = lighting.y * diffusematerial + lighting.z * specularmaterial; OUT.Color.a = 1.0; return OUT; } 14
Linking with OpenGL Next two examples show use of Cg runtime libraries to connect with an OpenGL program First example is from Cg user s manual Second example is from web (see link on class home page) 15
Cg Vertex Program void VertexProgram( in float4 position : POSITION, in float4 color : COLOR0, in float4 texcoord : TEXCOORD0, out float4 positiono : POSITION, out float4 coloro : COLOR0, out float4 texcoordo : TEXCOORD0, const uniform float4x4 ModelViewMatrix ) positiono = mul(position, ModelViewMatrix); coloro = color; texcoordo = texcoord; } 16
Cg Vertex Program II Program does nothing except convert position by model-view matrix to eye coordinates Passes though color and texture coordinates The uniform variable obtains its initial value from the OpenGL state - Use runtime library to connect Cg and OpenGL 17
Cg Fragment Program void FragmentProgram( in float4 color : COLOR0, in float4 texcoord : TEXCOORD0, out float4 coloro : COLOR0, const uniform sampler2d BaseTexture, const uniform float4 SomeColor) coloro = color * tex2d(basetexture, texcoord) + SomeColor; } 18
Fragment Program II Pass in color and texture coodinate - Note we can pass in multiple colors from OpenGL Second color (SomeColor) and sampler BaseTexture are passed in from OpenGL program - The sampler is set up in the OpenGL code - Describes a texture Output color is computed by sampling the texture with the passed in (interpolated) texture coordinate Now let s look at OpenGL program 19
#include <cg/cg.h> #include <cg/cggl.h> OpenGL Program float* vertexpositions; // Initialized somewhere else float* vertexcolors; // Initialized somewhere else float* vertextexcoords; // Initialized somewhere else GLuint texture; // Initialized somewhere else float constantcolor[]; // Initialized somewhere else 20
OpenGL Program (cont) // Cg variables CGcontext context; CGprogram vertexprogram, fragmentprogram; CGprofile vertexprofile, fragmentprofile; CGparameter position, color, texcoord, basetexture, somecolor, modelviewmatrix; 21
OpenGL Program (cont) // Called at initialization void CgGLInit() // Create context context = cgcreatecontext(); // Initialize profiles and compiler options vertexprofile = cgglgetlatestprofile(cg_gl_vertex); cgglsetoptimaloptions(vertexprofile); 22
OpenGL Program (cont) fragmentprofile = cgglgetlatestprofile(cg_gl_fragment); cgglsetoptimaloptions(fragmentprofile); // Create the vertex program vertexprogram = cgcreateprogramfromfile( context, CG_SOURCE, "VertexProgram.cg", vertexprofile, "VertexProgram", 0); 23
OpenGL Program (cont) // Load the program cgglloadprogram(vertexprogram); // Create the fragment program fragmentprogram = cgcreateprogramfromfile( context, CG_SOURCE, "FragmentProgram.cg", fragmentprofile, "FragmentProgram", 0); 24
OpenGLProgram (cont) // Load the program cgglloadprogram(fragmentprogram); // Grab some parameters. position = cggetnamedparameter(vertexprogram, "position"); color = cggetnamedparameter(vertexprogram, "color"); texcoord = cggetnamedparameter(vertexprogram, "texcoord"); 25
OpenGL Program (cont) // match Cg and OpenGL parameters // set means OpenGL Cg // get means Cg OpenGL modelviewmatrix = cggetnamedparameter(vertexprogram, "ModelViewMatrix"); basetexture = cggetnamedparameter(fragmentprogram, "BaseTexture"); somecolor = cggetnamedparameter(fragmentprogram, "SomeColor"); 26
OpenGL Program (cont) // Set parameters that don't change: // They can be set only once because of parameter shadowing. cgglsettextureparameter(basetexture, texture); cgglsetparameter4fv(somecolor, constantcolor); } // Called to render the scene void Display() // Set the varying parameters cgglenableclientstate(position); cgglsetparameterpointer(position, 3, GL_FLOAT, 0, vertexpositions); cgglenableclientstate(color); 27
OpenGL Program (cont) cgglsetparameterpointer(color, 1, GL_FLOAT, 0, vertexcolors); cgglenableclientstate(texcoord); cgglsetparameterpointer(texcoord, 2, GL_FLOAT, 0, vertextexcoords); // Set the uniform parameters that change every frame cgglsetstatematrixparameter(modelviewmatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); // Enable the profiles cgglenableprofile(vertexprofile); cgglenableprofile(fragmentprofile); 28
OpenGL Program (cont) // Bind the programs cgglbindprogram(vertexprogram); cgglbindprogram(fragmentprogram); // Enable texture cgglenabletextureparameter(basetexture); // Draw scene //... // Disable texture cggldisabletextureparameter(basetexture); // Disable the profiles cggldisableprofile(vertexprofile); cggldisableprofile(fragmentprofile); 29
OpenGL Program (cont) // Set the varying parameters cggldisableclientstate(position); cggldisableclientstate(color); cggldisableclientstate(texcoord); } // Called before application shuts down void CgShutdown() // This frees any runtime resource. cgdestroycontext(context); } 30
Fragment Program struct appdata float4 position : POSITION; float4 color : COLOR0; float3 wave : COLOR1; }; struct vfconn float4 HPos : POSITION; float4 Col0 : COLOR0; }; 31
Fragment Program (cont) vfconn main(appdata IN, uniform float4x4 ModelViewProj) vfconn OUT; // Variable to handle our output from the vertex // shader (goes to a fragment shader if available). 32
Fragment Program (cont) } // Change The Y Position Of The Vertex Based On Sine Waves IN.position.y = ( sin(in.wave.x + (IN.position.x / 5.0) ) + sin(in.wave.x + (IN.position.z / 4.0) ) ) * 2.5f; // Transform The Vertex Position Into Homogenous Clip- Space (Required) OUT.HPos = mul(modelviewproj, IN.position); // Set The Color To The Value Specified In IN.color OUT.Col0.xyz = IN.color.xyz; return OUT; 33
GLUT Program #include <GL/gl.h> #include <GL/glu.h> #include <Cg/cg.h> #include <Cg/cgGL.h> #include <stdlib.h> #include <stdio.h> #include <GL/glut.h> // User Defined Variables #define SIZE 64 // Defines The Size Of The X/Z Axis Of The Mesh 34
GLUT Program (cont) bool cg_enable = true, sp; // Toggle Cg Program On / Off, Space Pressed? GLfloat mesh[size][size][3]; // Our Static Mesh GLfloat wave_movement = 0.0f; // Our Variable To Move The Waves Across The Mesh CGcontext cgcontext; // A Context To Hold Our Cg Program(s) CGprogram cgprogram; // Our Cg Vertex Program CGprofile cgvertexprofile; // The Profile To Use For Our Vertex Shader CGparameter position, color, modelviewmatrix, wave; // The Parameters Needed For Our Shader 35
GLUT Program (cont) bool Initialize () // Any GL Init Code & User Initialization Goes Here glclearcolor (0.0f, 0.0f, 0.0f, 0.5f); glcleardepth (1.0f); gldepthfunc (GL_LEQUAL); glenable (GL_DEPTH_TEST); glshademodel (GL_SMOOTH); glhint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); 36
GLUT example (cont) // set up mesh for (int x = 0; x < SIZE; x++) for (int z = 0; z < SIZE; z++) mesh[x][z][0] = (float) (SIZE / 2) - x; // We Want To Center Our Mesh Around The Origin mesh[x][z][1] = 0.0f; // Set The Y Values For All Points To 0 mesh[x][z][2] = (float) (SIZE / 2) - z; // We Want To Center Our Mesh Around The Origin } } 37
GLUT example (cont) // Setup Cg cgcontext = cgcreatecontext(); // Create A New Context For Our Cg Program(s) // Validate Our Context Generation Was Successful if (cgcontext == 0) fprintf(stderr, "Failed To Create Cg Context\n"); exit(-1); // We Cannot Continue } 38
GLUT Example (cont) cgvertexprofile = cgglgetlatestprofile(cg_gl_vertex); // Get The Latest GL Vertex Profile // Validate Our Profile Determination Was Successful if (cgvertexprofile == CG_PROFILE_UNKNOWN) fprintf(stderr, "Invalid profile type\n"); exit(-1); // We Cannot Continue } cgglsetoptimaloptions(cgvertexprofile); // Set The Current Profile 39
GLUT examples (cont) // Load And Compile The Vertex Shader From File cgprogram = cgcreateprogramfromfile(cgcontext, CG_SOURCE, "./Cg/Wave.cg", cgvertexprofile, "main", 0); if (cgprogram == 0) CGerror Error = cggeterror(); } fprintf(stderr,"%s \n",cggeterrorstring(error)); exit(-1); 40
GLUT Example (cont) cgglloadprogram(cgprogram); // Get Handles To Each Of Our Parameters So That // We Can Change Them At Will Within Our Code position = cggetnamedparameter(cgprogram, "IN.position"); color = cggetnamedparameter(cgprogram, "IN.color"); wave = cggetnamedparameter(cgprogram, "IN.wave"); modelviewmatrix = cggetnamedparameter(cgprogram, "ModelViewProj"); } return true; 41
GLUT Example (cont) void Deinitialize (void) cgdestroycontext(cgcontext); } void Update (int key,int x,int y) if ( key==27 ) Deinitialize(); exit(0); }; 42
GLUT example (cont) // if (g_keys->keydown [VK_F1]) // Is F1 Being Pressed? // ToggleFullscreen (g_window); // Toggle Fullscreen Mode if ( key==' ' ) sp=!sp; cg_enable=!cg_enable; }; } glutpostredisplay(); 43
GLUT example (cont) void Draw (void) glclear (GL_COLOR_BUFFER_BIT GL_DEPTH_BUFFER_BIT); glloadidentity (); glulookat(0.0f, 25.0f, -45.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0); // Set The Modelview Matrix Of Our Shader To Our OpenGL Modelview Matrix cgglsetstatematrixparameter(modelviewmatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY); 44
GLUT Example (cont) if (cg_enable) cgglenableprofile(cgvertexprofile); // Enable Our Vertex Shader Profile // Bind Our Vertex Program To The Current State cgglbindprogram(cgprogram); } // Set The Drawing Color To Light Green //(Can Be Changed By Shader, Etc...) cgglsetparameter4f(color, 0.5f, 1.0f, 0.5f, 1.0f); 45
GLUT Example (cont) for (int x = 0; x < SIZE - 1; x++) // Start Drawing Our Mesh // Draw A Triangle Strip For Each Column Of Our Mesh glbegin(gl_triangle_strip); for (int z = 0; z < SIZE - 1; z++) // Set The Wave Parameter Of Our Shader To The // Incremented Wave Value From Our Main Program cgglsetparameter3f(wave, wave_movement, 1.0f, 1.0f); glvertex3f(mesh[x][z][0], mesh[x][z][1], mesh[x][z][2]); glvertex3f(mesh[x+1][z][0], mesh[x+1][z][1], mesh[x+1][z][2]); wave_movement += 0.00001f; } glend(); } 46
GLUT example (cont) if (cg_enable) cggldisableprofile(cgvertexprofile); // Disable Our Vertex Profile } glflush (); Flush The GL Rendering Pipeline glutswapbuffers(); // 47
callbacks void ReshapeGL (int width, int height) glviewport (0, 0, (GLsizei)(width), (GLsizei)(height)); glmatrixmode (GL_PROJECTION); glloadidentity (); gluperspective (45.0f, (GLfloat)(width)/(GLfloat)(height), 0.1f, 100.0f); glmatrixmode (GL_MODELVIEW); glloadidentity (); glutpostredisplay(); } 48
callbacks void Key(unsigned char key,int x,int y) Update(key,x,y); return ; }; void OnIdle() glutpostredisplay(); }; 49
main() int main( int argc, char *argv[] ) glutinit( &argc, argv ); glutinitwindowposition( 0, 0 ); glutinitwindowsize( 640, 480 ); glutinitdisplaymode( GLUT_RGB GLUT_DOUBLE GLUT_DEPTH ); glutcreatewindow(argv[0]); glutreshapefunc( ReshapeGL ); glutkeyboardfunc( Key ); glutspecialfunc( Update ); glutdisplayfunc( Draw ); glutidlefunc( OnIdle ); Initialize(); glutmainloop(); } 50