综述
Cg是在DX和OpenGL上再次封装的一门语言,用来编写GPU程序的语言。所以,以DX或者OpenGL开发的3D程序,都可以用Cg来开发Shader程序,并加载上来用。一下是在OpenGL中加载Cg程序的过程,其中使用了GLUT库来协助完成。
加载过程:
第一步: 包含头文件
我使用了预编译头,
#include "targetver.h" #include <tchar.h> #include <iostream> #include <stdlib.h> #include <GL/glut.h> #include <Cg/cg.h> #include <Cg/cgGL.h>
项目设置:
有人会疑问? 为什么没有库呢? 其实,在你的path里面有这句就够了
C:\Program Files\NVIDIA Corporation\Cg\bin;
至于path是什么请看http://www.cnblogs.com/leisure/archive/2012/02/13/2349797.html 里面有相关的介绍。
第二步: 开始写程序
首先,在Cg运行的过程中,总共需要知道三个变量:
static CGcontext myCgContext; static CGprofile myCgVertexProfile; static CGprogram myCgVertexProgram;
设备上下文,程序语言子集,着色程序
我们这里全部是以顶点着色程序为例来说明的。熟悉MFC的应该都知道在绘图的过程中使用的设备上下文,在这里也是这样的。
程序语言子集:
Cg 程序的编译不但依赖于宿主程序所使用的三维编程接口,而且依赖于图形硬件环境,因为图形硬件自身的限制,不一定支持某种 Cg 语句,例如,如果 你所使用的 GPU 并不支持循环控制指令,那么在 Cg 程序中编写的循环控制语 句将无法通过编译。被特定的图形硬件环境或 AIP 所支持的 Cg 语言子集,被称 为 Cg Profiles 。需要注意的是: profile 分为顶点程序的 profile 和片段程序的 profile ,这是因为顶点着色器和片段着色器原本就不是工作在同一个硬件。 Cg Profiles 是 Cg 语言的重要组成部分,在使用 Cg 语言编写着色程序时, 首先要考虑的一点就是“当前的图形硬件环境支持那个 Cg Profile”,这直接关系 到您所编写的着色程序是否可以在当前的图形硬件上运行。(阳春白雪与下里巴人)
着色程序:
就是我们通过CgAPI和Cg脚本生成的一个着色程序。
为了以上三个变量的获得,我们提供三个字符串。
static const char *myProgramName = "vertex_program", *myVertexProgramFileName = "../debug/MyVertexProgram.cg", *myVertexEntryPoint = "vs_main";
分别是,程序名称、文件名称(可以是地址相对)、入口函数。
那么怎么用呢?
第一步:获得上下文:
myCgContext = cgCreateContext();
DESCRIPTION
cgCreateContext creates a Cg context object and returns its handle. A Cg context is a container for Cg programs. All Cg programs must be added as part of a context.
【描述】
cgCreateContext 方法创建了Cg的设备表对象并返回它的句柄。Cg的设备表是Cg程序的容器。所有的Cg程序必须作为设备表的一部分添加到设备表中。
第二步:获得语言子集
myCgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX);
DESCRIPTION
cgGLGetLatestProfile returns the best available profile of a given class. It will check the available OpenGL extensions to see what the determine the best profile.
cgGLGetLatestProfile may be used in conjuction with cgCreateProgram to ensure that more optimal profiles are used as they are made available even though they might not be available at compile time or with a given version of the runtime.
【描述】
cgGLGetLatestProfile方法通过给定的类返回一个语言子集列表中最好的那一个(如果没有返回CG_PROFILE_UNKNOWN 标准错误)。方法会检测可用的OpenGL扩展中决定最好语言子集的因素。
cgGLGetLatestProfile方法被用来推测cgCreateProgram方法来确保更多的最佳语言子集能够使用。有的时候在编译的时候或者比较版本的时候是不能确定的因素。(好恶心啊,我是这么理解的)
第三步: 设置编译器参数
cgGLSetOptimalOptions(myCgVertexProfile);
DESCRIPTION
cgGLSetOptimalOptions sets implicit compiler arguments that are appended to the argument list passed to cgCreateProgram. The arguments are chosen based on the the available compiler arguments, GPU, and driver.
The arguments will be appended to the argument list every time cgCreateProgram is called until the last CGcontext is destroyed.
【描述】
设置默认的编译器参数,这个编译器参数与cgCreateProgram方法连接的参数列表时相关的。默认参数是由可用的编译器参数、GPU和驱动决定的。
每次调用cgCreateProgram 方法的时候,这些参数都会添加带参数列表中,知道设备上下文被销毁。
第四步:创建程序
我们选择从文件创建程序
myCgVertexProgram = cgCreateProgramFromFile( myCgContext, /* 设备上下文*/ CG_SOURCE, /*硬盘读入程序*/ myVertexProgramFileName, /* 文件名*/ myCgVertexProfile, /* 得到的语言子集 */ myVertexProgramName, /*入口函数名 */ NULL); /* 额外的编辑器参数 没有*/
DESCRIPTION
cgCreateProgramFromFile generates a new CGprogram object and adds it to the specified Cg context.
【描述】
cgCreateProgramFromFile 产生一个新的Cgprogram对象,并将它添加到指定的Cg 上下文去。
(返回值当然是一个CgProgram的句柄)
第五步: 加载创建的程序
cgGLLoadProgram(myCgVertexProgram);
DESCRIPTION
cgGLLoadProgram prepares a program for binding. All programs must be loaded before they can be bound to the current state. See cgGLBindProgram for more information about binding programs.
【描述】
cgGLLoadProgram 方法为程序绑定做准备。所有的程序在绑定到当前状态之前必须首先被加载。看一下cgGLBindProgram获取更多关于程序绑定的内容。
第六步:绑定程序
cgGLBindProgram(myCgVertexProgram);
DESCRIPTION
cgGLBindProgram binds a program to the current state. The program must have been loaded with cgGLLoadProgram before it can be bound. Also, the profile of the program must be enabled for the binding to work. This may be done with the cgGLEnableProfile function.
cgGLBindProgram will reset all uniform parameters that were set with the cgGLSetXXXXX() functions for profiles that do not support program local parameters (e.g. the vp20 profile).
【描述】
cgGLBindProgram 为当前状态绑定一个程序。如前所述,这个程序必须是以及被加载的程序。而且,这个程序语言子集对这个程序得到绑定并工作来说必须可用。这个是用cgGLEnableProfile是可以完成的。
cgGLBindProgram会重置所有被类似cgGLSetXXXXX()设置的又不被支持的uniform类型的参数。
第七步:设置语言子集可用开关
cgGLEnableProfile(myCgVertexProfile);
cgGLDisableProfile(myCgVertexProfile);
DESCRIPTION
cgGLEnableProfile enables a given profile by making the appropriate OpenGL calls. For most profiles, this will simply make a call to glEnable with the approriate enumerant.
【描述】
cgGLEnableProfile方法通过设置适当的OpenGL的调用打开一个给定的profile,相当于在可用类表里简单调用了glEnable方法。
(关闭亦然)
到这里,Cg做完了它的事情,用过GLUT库的人知道,只有放到display()函数并用glutDisplayFunc(display) 调用,加上glutMainLoop() 才会一直调用。所以,在以上的代码中,绑定程序并设置上下文可用,才能够一直维持程序在当前状态。
绘画函数:
static void display(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); cgGLBindProgram(myCgVertexProgram); cgGLEnableProfile(myCgVertexProfile); /* Rendering code verbatim from Chapter 1, Section 2.4.1 "Rendering a Triangle with OpenGL" (page 57). */ glBegin(GL_TRIANGLES); glVertex2f(-0.8, 0.8); glVertex2f(0.8, 0.8); glVertex2f(0.0, -0.8); glEnd(); cgGLDisableProfile(myCgVertexProfile); glutSwapBuffers(); }
效果如图所示:
如果安装了Cg库,就在例子里面。