NeHe OpenGL教程 第四十七课:CG顶点脚本
前言
声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改。对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢。
NeHe OpenGL第四十七课:CG顶点脚本

CG 顶点脚本
nVidio的面向GPU的C语言,如果你相信它就好好学学吧,同样这里也只是个入门。记住,类似的语言还有微软的HLSL,OpenGL的GLSL,ATI的shaderMonker。不要选错哦:)
使用顶点和片断脚本去做渲染工作可以得到额外的好处,最大的好处就是把CPU的一些工作交给了GPU,Cg提供了书写这些强大的脚本的一种手段。
这篇教程有许多目的,第一向你展现了一个非常简单的顶点脚本,第二向你说明如何在OpenGL中使用Cg编写的脚本。
这个教程是基于最新的NeHeGL的基本代码,为了获得更多的信息,你可以访问nVidia的官方网站(developer.nvidia.com),它会给你一个完整的答案。
注意:这个教程不是叫你如何去写一个完整的Cg脚本,而是教你在OpenGL中载入并运行脚本。
开始:
第一步,从nVidia的网站上下载Cg Compiler库,最好去下载1.1版本的,因为nvidia各个版本的变化很大,为了让程序不出现任何问题,最好这样做,因为我们用的是1.1版本的。
下一步,包含编译需要的头文件和库文件。
我已经帮你把它们拷贝到了工程的文件夹里了。
Cg介绍
你必须有以下几个概念:
1、顶点脚本会作用于你输入的每一个顶点,如果你想要作用于一些顶点,那么你必须在作用前加载顶点脚本,并于作用后释放顶点脚本。
2、顶点脚本输出的结果被送入到片断处理器中,你不用管这其中是如何实现的。
最后,记住顶点脚本在图元装配前被执行,片断脚本在光栅化后被执行。
好了,现在我们创建一个空白的文件吧(保存为wave.cg),接着我们创建一个数据结构,它被我们得脚本使用。下面的代码被加入到wave.cg文件中。
struct appdata { float4 position : POSITION; float4 color : COLOR0; float3 wave : COLOR1;};
上面的结果说明,我们输入的顶点包含一个位置坐标,一个颜色和我们自定义的波的颜色
下面的代码定义一个输出顶点的数据,包括一个顶点和颜色
struct vfconn{ float4 HPos : POSITION; float4 Col0 : COLOR0;};
下面的代码是Cg的主函数,每个顶点都会被以下函数执行:
vfconn main(appdata IN, uniform float4x4 ModelViewProj)
{
vfconn OUT; // 保存我们输出顶点的数据
// 计算顶点y的坐标
IN.position.y = ( sin(IN.wave.x + (IN.position.x / 5.0) ) + sin(IN.wave.x + (IN.position.z / 4.0) ) ) * 2.5f;
// 保存到输出数据中
OUT.HPos = mul(ModelViewProj, IN.position);
// 不改变输入的颜色
OUT.Col0.xyz = IN.color.xyz;
return OUT;
}
完成了上面的代码,记得保存一下.
下面我们到了程序中,首先包含使用cg需要的头文件,和库文件
#include <cg\cg.h> #include <cg\cggl.h>
#pragma comment( lib, "cg.lib" ) #pragma comment( lib, "cggl.lib" )
下面我们定义一些全局变量,用来计算我们得网格和控制cg程序的开关
#define SIZE 64 // 定义网格的大小bool cg_enable = TRUE, sp; //
开关Cg程序GLfloat mesh[SIZE][SIZE][3]; //
保存我们的网格GLfloat wave_movement = 0.0f; // 记录波动的移动
下面我们来定义一些cg相关的全局变量
CGcontext cgContext; // 用来保存cg脚本
我们需要的第一个变量是CGcontext,这个变量是多个Cg脚本的容器,一般来说,你获得你可以用函数从这个容器中获得你想要的脚本
接下来我们定义一个CGprogram变量,它用来保存我们得顶点脚本
CGprogram cgProgram; // 我们得顶点脚本
接下来我们需要一个变量来设置如何编译这个顶点脚本
CGprofile cgVertexProfile; // 被顶点脚本使用
下面我们需要一些参数用来把Cg脚本使用的数据从程序中传送过去。
CGparameter position, color, modelViewMatrix, wave; // 脚本中需要的参数
在初始化阶段我们先要创建我们网格数据
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
for (int x = 0; x < SIZE; x++)
{
for (int z = 0; z < SIZE; z++)
{
mesh[x][z][0] = (float) (SIZE / 2) - x;
mesh[x][z][1] = 0.0f;
mesh[x][z][2] = (float) (SIZE / 2) - z;
}
}
我们设置多边形的现实模式为线框图,接着遍历没有顶点,设置其高度。
接下来,我们初始化Cg程序
// 设置Cg cgContext = cgCreateContext(); // 创建一个Cg容器
// 测试是否创建成功
if (cgContext == NULL)
{
MessageBox(NULL, "Failed To Create Cg Context", "Error", MB_OK);
return FALSE;
}
我们创建一个Cg程序的容器,并检查它是否创建成功
cgVertexProfile = cgGLGetLatestProfile(CG_GL_VERTEX); // 配置在OpenGL中使用顶点缓存
// 检测Cg程序的是否创建成功
if (cgVertexProfile == CG_PROFILE_UNKNOWN)
{
MessageBox(NULL, "Invalid profile type", "Error", MB_OK);
return FALSE;
}
cgGLSetOptimalOptions(cgVertexProfile); // 启用配置文件
如果你想使用片断脚本,使用CG_GL_FRAGMENT变量。如果返回的变量为CG_PROFILE_UNKNOW表示没有可用的配置文件,则不能编译你需要的Cg程序。
// 从文件中载入Cg程序 cgProgram = cgCreateProgramFromFile(cgContext, CG_SOURCE, "CG/Wave.cg", cgVertexProfile, "main", 0);
// 检测是否成功
if (cgProgram == NULL)
{
CGerror Error = cgGetError();
MessageBox(NULL, cgGetErrorString(Error), "Error", MB_OK);
return FALSE;
}
我们尝试从源文件中创建一个Cg程序,并返回编译后的结果。
// 载入脚本 cgGLLoadProgram(cgProgram);
下面我们把顶点脚本载入到显存,并准备帮定给GPU。所有的脚本在使用前必须加载。
//
把数据变量地址发送给Cg程序 position = cgGetNamedParameter(cgProgram,
"IN.position"); color = cgGetNamedParameter(cgProgram,
"IN.color"); wave = cgGetNamedParameter(cgProgram,
"IN.wave"); modelViewMatrix = cgGetNamedParameter(cgProgram,
"ModelViewProj");
return TRUE;
在初始化的最后,我们必须告诉Cg脚本在那里去获得输入的数据,我们需要把变量的指针传递过去,下面的函数完成了这个功能。
程序结束时,记得释放我们创建的内容。
cgDestroyContext(cgContext);
下面的代码使用空格切换是否使用Cg程序
if (g_keys->keyDown [' '] && !sp) { sp=TRUE; cg_enable=!cg_enable; }
if (!g_keys->keyDown [' ']) sp=FALSE;
现在我们已经完成了所有的准备工作了,到了我们实际绘制网格的地方了,按照惯例我们还是先设置我们得视口。
gluLookAt(0.0f, 25.0f, -45.0f, 0.0f, 0.0f, 0.0f, 0, 1, 0);
// 把当前Cg程序的模型变化矩阵告诉当前程序 cgGLSetStateMatrixParameter(modelViewMatrix, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY);
上面我们要做的事就是把当前Cg程序的模型变化矩阵告诉当前程序。
结下来如果使用cg程序,则把顶点的颜色设置为绿色
// 如果使用Cg程序 if
(cg_enable) { //
使用顶点脚本配置文件 cgGLEnableProfile(cgVertexProfile); //
帮定到当前的顶点脚本 cgGLBindProgram(cgProgram); //
设置绘制颜色 cgGLSetParameter4f(color, 0.5f, 1.0f, 0.5f, 1.0f); }
下面我们来绘制我们的网格。
// 开始绘制我们的网格 for (int x =
0; x < SIZE - 1; x++) { glBegin(GL_TRIANGLE_STRIP); for (int z = 0;
z < SIZE - 1; z++) { // 设置Wave参数 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; if (wave_movement >
TWO_PI) wave_movement =
0.0f; } //经过Cg程序处理,进行绘制 glEnd(); }
上面的代码完成具体的绘制操作,对于每一个顶点,我们动态的传入波动系数和输入原始的顶点数据。在绘制开始前,顶点脚本接受所有的顶点数据并处理,接着进行光栅华操作。
别忘了在绘制完成后,关闭我们启用的顶点脚本,否则在绘制其它的模型时会让你得到不想要的结果。
if (cg_enable)
cgGLDisableProfile(cgVertexProfile); // 禁用顶点脚本配置文件
原文及其个版本源代码下载:
NeHe OpenGL教程 第四十七课:CG顶点脚本的更多相关文章
- NeHe OpenGL教程 第三十七课:卡通映射
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十三课:FreeType库
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十课:绳子的模拟
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十八课:轨迹球
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十五课:顶点缓存
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十六课:全屏反走样
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十四课:3D光晕
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四十二课:多重视口
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- NeHe OpenGL教程 第四课:旋转
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
随机推荐
- html中input文本框,初始里边有文字提示,当点击时,文字消失,怎么设置?
使用onfocus事件检查当前值,如果是默认值,就将value属性置空.如:<input type="text" value="请输入内容" onfocu ...
- Java 并发和多线程(一) Java并发性和多线程介绍[转]
作者:Jakob Jenkov 译者:Simon-SZ 校对:方腾飞 http://tutorials.jenkov.com/java-concurrency/index.html 在过去单CPU时 ...
- C#微信公众号开发之网页授权oauth2.0获取用户基本信息(一)
咨询 请加 QQ::QQ群: 在微信里面,非认证的公众号账号,只能通过在微信回复菜单单击等事件获取openid,但是认证的公众账号(之前认证的订阅号是不可以的,现在新开放了政府媒体机构的认证订阅号)可 ...
- MySQL 入门知识点
参考网址:http://www.cnblogs.com/mr-wid/archive/2013/05/09/3068229.html 1.数值类数据列类型 数据列类型 存储空间 描述 TINYINT ...
- PHP过滤外部链接及外部图片 添加rel="nofollow"属性
原来站内很多文章都是摘录的外部文章,文章里很多链接要么是时间久了失效了,要么就是一些测试的网址,如:http://localhost/ 之类的,链接多了的话,就形成站内很多死链接,这对SEO优化是很不 ...
- warning: incompatible implicit declaration of built-in function ‘exit’
出现这个错误,一般是程序中某个函数没有include相关的文件. EG. 出现这个错误是因为要使用exit()应该包含stdlib.h文件
- ios网络学习------4 UIWebView的加载本地数据的三种方式
ios网络学习------4 UIWebView的加载本地数据的三种方式 分类: IOS2014-06-27 12:56 959人阅读 评论(0) 收藏 举报 UIWebView是IOS内置的浏览器, ...
- 关于jsonp跨域过程中 cookie中的值一直为null的原因
今天技术交流群里的小伙伴一直被一个问题而困扰,就是写入cookie里面的值 再次进行请求时 cookie 就为空了 他被问题纠结了一天 我也好奇了一天 终于在快下班的时候 他解决掉了 下面我来收一个 ...
- BlackHat会议上将公布一款免费的汽车黑客工具
汽车,无可厚非是现代社会很重要的交通工具,但与此同时却也带来了诸多安全隐患,不管怎样,汽车安全都是我们不可忽视的一个重大问题. 即将免费分享该工具 近日一名法国研究者将发布一款检测汽车安全漏洞的工具, ...
- iOS 利用 Framework 进行动态更新
http://nixwang.com/2015/11/09/ios-dynamic-update/ 前言 目前 iOS 上的动态更新方案主要有以下 4 种: HTML 5 lua(wax)hotpat ...