新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     >>计算机科学论坛<<     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 47-lesson 48【本教程全部传完】 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 29330 个阅读者浏览上一篇主题  刷新本主题   平板显示贴子 浏览下一篇主题
     * 贴子主题: [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 47-lesson 48【本教程全部传完】 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     一分之千 帅哥哟,离线,有人找我吗?射手座1984-11-30
      
      
      威望:1
      等级:研一(随老板参加了WWW大会还和Tim Berners-Lee合了影^_^)
      文章:632
      积分:4379
      门派:XML.ORG.CN
      注册:2006/12/31

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给一分之千发送一个短消息 把一分之千加入好友 查看一分之千的个人资料 搜索一分之千在『 C/C++编程思想 』的所有贴子 引用回复这个贴子 回复这个贴子 查看一分之千的博客楼主
    发贴心情 [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 47-lesson 48【本教程全部传完】

    第四十七课  四十八课源码


    第四十七课


    按此在新窗口浏览图片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);     // 禁用顶点脚本配置文件
       
    好了上面就是所有的内容了,简单吧.Cg就是这么简单


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    越学越无知

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2007/11/1 11:50:00
     
     GoogleAdSense射手座1984-11-30
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/27 17:06:11

    本主题贴数6,分页: [1]

     *树形目录 (最近20个回帖) 顶端 
    主题:  [推荐]NeHe OpenGL教程(中英文版附带VC++源码)Lesson 4..(7311字) - 一分之千,2007年11月1日
        回复:  这些都学会 差不多就入门了 谢谢楼主了!!(40字) - emc2010,2011年12月16日
        回复:  谢谢你!没了吗?(18字) - 长风万里,2007年11月1日
        回复:  Lesson: 48 ArcBall Rotation Control, Revisi..(8041字) - 一分之千,2007年11月1日
        回复:  第四十八课[IMG]http://www.owlei.com/DancingWind/P..(4302字) - 一分之千,2007年11月1日
        回复:  Lesson: 47 Using vertex and fragment (or pi..(20272字) - 一分之千,2007年11月1日

    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    78.125ms