NeHe OpenGL教程 第四十七课:CG顶点脚本

转自【翻译】NeHe OpenGL 教程

前言

声明,此 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);     // 禁用顶点脚本配置文件

原文及其个版本源代码下载:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=47

时间: 2024-12-21 00:22:51

NeHe OpenGL教程 第四十七课:CG顶点脚本的相关文章

NeHe OpenGL教程 第三十七课:卡通映射

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第三十七课:卡通映射 卡通映射: 什么是卡通了,一个轮廓加上少量的几种颜色.使用一维纹理映射,你也可以实现这种效果. 看到人们仍然e-mail我请求在文章中使用我方才在GameDev.net上写的源代码,还看到文章的第二版(在那每一

NeHe OpenGL教程 第四十三课:FreeType库

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十三课:FreeType库 在OpenGL中使用FreeType库 使用FreeType库可以创建非常好看的反走样的字体,记住暴雪公司就是使用这个库的,就是那个做魔兽世界的.尝试一下吧,我只告诉你了基本的使用方式,你可以走的更远

OpenGL教程翻译 第十七课 环境光(Ambient Lighting)

OpenGL教程翻译 第十七课 环境光(Ambient Lighting) 原文地址:http://ogldev.atspace.co.uk/(源码请从原文主页下载) Background 光照是3D图形学的最重要的研究领域之一.对光照得体的模拟会使渲染的场景增加很多视觉吸引力.之所以使用"模拟"这个词是因为你无法准确的模仿出光照在自然界中的样子.真正的光是由大量的称为"光子"的粒子组成的,并且同时表现出波和粒子的特性(光的"波粒二象性").如果

NeHe OpenGL教程 第四十四课:3D光晕

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十四课:3D光晕 3D 光晕 当镜头对准太阳的时候就会出现这种效果,模拟它非常的简单,一点数学和纹理贴图就够了.好好看看吧. 大家好,欢迎来到新的一课,在这一课中我们将扩展glCamera类,来实现镜头光晕的效果.在日常生活中,

NeHe OpenGL教程 第四十二课:多重视口

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十二课:多重视口 多重视口 画中画效果,很酷吧.使用视口它变得很简单,但渲染四次可会大大降低你的显示速度哦:) 欢迎来到充满趣味的另一课.这次我将向你展示怎样在单个窗口内显示多个视口.这些视口在窗口模式下能正确的调整大小.其中有

NeHe OpenGL教程 第四十六课:全屏反走样

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第四十六课:全屏反走样 全屏反走样 当今显卡的强大功能,你几乎什么都不用做,只需要在创建窗口的时候该一个数据.看看吧,驱动程序为你做完了一切. 在图形的绘制中,直线的走样是非常影响美观的,我们可以使用反走样解决这个问题.在众多的解决

NeHe OpenGL教程 第二十五课:变形

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十五课:变形 变形和从文件中加载3D物体: 在这一课中,你将学会如何从文件加载3D模型,并且平滑的从一个模型变换为另一个模型. 欢迎来到这激动人心的一课,在这一课里,我们将介绍模型的变形.需要注意的是各个模型必须要有相同的顶点,

NeHe OpenGL教程 第二十八课:贝塞尔曲面

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( [email protected] ) 这篇教程旨在介绍贝塞尔曲面,希望有比我更

NeHe OpenGL教程 第二十九课:Blt函数

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十九课:Blt函数 Blitter 函数: 类似于DirectDraw的blit函数,过时的技术,我们有实现了它.它非常的简单,就是把一块纹理贴到另一块纹理上. 这篇文章是有Andreas Lffler所写的,它写了一份原始的教