OpenGL Shading Language 入门之 Hello World

帛裂七弦原创作品,转载请注明    http://blog.sina.com.cn/blqx

不管什么语言第一步都是  Hello World OpenGL <wbr>Shading <wbr>Language <wbr>入门之 <wbr>Hello <wbr>World
OpenGL Shading Language 的 “Hello World”一个旋转的茶壶:
 
这个例子在 windows下 采用 VC6.0 开发
首先确定你已经安装并可以正常使用  glew 和 glut 扩展库
下一步,新建一个控制台程序,项目加载库文件 glew32.lib
 
本项目一共5个文件
创建程序文件3个 “ogl3.cpp” “textfile.h” “textfile.cpp”
创建顶点着色器和片元着色器文件 “minimal.vert” 和 “minimal.frag” 并导入到项目中

顶点着色器 “minimal.vert” 程序代码:

// 顶点着色器

void main()
  // 下列三行运行结果一样

    gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * gl_Vertex;
//  gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
//  gl_Position = ftransform();

}

这个顶点着色器非常简单,就是将顶点坐标做模型视点变换和投影变化,得到裁剪坐标。

片元着色器 “minimal.frag” 程序代码:

// 片元着色器

void main()
{
    gl_FragColor = vec4(0.4,0.4,0.8,1.0);
}

这个片元着色器更加简单,输出一个固定的颜色

 
我们知道着色器的源代码是由OpenGl驱动程序进行编译和链接的,OpenGl驱动程序大部分是由显卡厂商提供的并作为显卡驱动的一部分,因此VC并不能编译和链接GLSL的源代码。VC要做的事是读取这个以文本形式存在的源代码,并将这些代码以字符形式存下来,提交给OpenGl驱动程序。所以我们的例子中需要文件操作方面的代码。“textfile.h” “textfile.cpp”就是进行这方面的工作。
未命名.JPG
 

文本操作 “textfile.h” 程序代码:

///
//
// FileName : textfile.h
// Creator : 帛裂七弦
// Date : 2008-04-01 14:20:07
// Comment : 读写文本文件(用于读取着色器的源代码.vert和.frag文件)
//
///

 

char *textFileRead(char *fn);///读取文件
int textFileWrite(char *fn, char *s);///写入文件


文本操作 “textfile.cpp” 程序代码:

///
//
// FileName : textfile.cpp
// Creator : 帛裂七弦
// Date : 2008-04-01 14:20:07
// Comment : 读写文本文件(用于读取着色器的源代码.vert和.frag文件)
//
///
#include
#include
#include

 
char *textFileRead(char *fn)
{
    FILE *fp;
    char *content = NULL;
    int count=0;

    if (fn != NULL)
    {
         ///打开文件
         fp = fopen(fn,"rt");
         if (fp != NULL)
         {
             fseek(fp, 0, SEEK_END);
             count = ftell(fp);
             rewind(fp);
             if (count > 0)
             {
                  content = (char *)malloc(sizeof(char) * (count+1));
                  count = fread(content,sizeof(char),count,fp);
                  content[count] = '\0';
              }
              fclose(fp);
          }
    }
    return content;
}


int textFileWrite(char *fn, char *s)
{
    FILE *fp;
    int status = 0;

    if (fn != NULL)
    {
        ///打开文件
        fp = fopen(fn,"w");
        if (fp != NULL)
        {
             if (fwrite(s,sizeof(char),strlen(s),fp) == strlen(s))
                 status = 1;
             fclose(fp);
         }
     }
     return(status);
}


 
下面就是最关键的部分 整个设置着色器的步骤是:
  1. 创造空白顶点着色器
  2. 读取着色器源代码文件
  3. 将着色器源代码字符串数组提交给空白的着色器
  4. 编译源代码
  5. 创造空白程序对象
  6. 将着色器对象附加到程序对象
  7. 链接程序对象
  8. 安装程序

主要操作 “ogl3.cpp” 程序代码:

注:新浪什么垃圾博客把注释全部都忽略了发不上去 注释只有写成**了。。

///
//
// FileName : ogl3.cpp
// Creator : 帛裂七弦
// Date : 2008-04-01 15:11:33
// Comment : GLSL入门
//
///
#include <stdio.h>
#include <stdlib.h>
#include <GL/glew.h>
#include <GL/glut.h>
#include "textfile.h"
#define printOpenGLError() printOglError(__FILE__, __LINE__)

 

static float degree = 0;///茶壶旋转的度数

 

**
* @brief 处理窗口大小改变
* @param  w 窗口的宽
* @param  h 窗口的高
**
void changeSize(int w, int h)
{
    ///重新定义视口
    glViewport(0, 0, w, h);

 

    ///重新设置投影变换
    if(h == 0) h = 1;/// 防止高为0产生除0错误
    float ratio = 1.0 * w / h;///宽高比
    glMatrixMode(GL_PROJECTION);///当前矩阵设为投影矩阵
    glLoadIdentity();///清空投影矩阵
    gluPerspective(45,ratio,1,1000);//重设投影矩阵

 

    ///模型视点变换
    glMatrixMode(GL_MODELVIEW);///当前矩阵设为模型视点矩阵
}

 

**
* @brief 显示函数
**
void renderScene(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);///清空颜色缓存和深度缓存
    glLoadIdentity();///清空模型视点矩阵

 

    ///视点变换
    gluLookAt(0.0,0.0,5.0,
              0.0,0.0,-1.0,
              0.0f,1.0f,0.0f);

 

    ///模型变换 旋转茶壶
    glRotatef(degree,0,1,1);

 

    ///绘制茶壶
    glutSolidTeapot(1);

 

    degree += 0.1;///旋转度数增加
    glutSwapBuffers();///交换缓存(双缓存模式)
}

 

**
* @brief 处理键盘事件 按下 Esc 退出程序
**
void processNormalKeys(unsigned char key, int x, int y)
{
    if(key == 27)
        exit(0);
}

 

**
* @brief 打印OpenGL错误信息
* @param  file 错误所在的文件
* @param  line 错误所在的行
* @return 1 OpenGL error
* @return 0 other  error
**
int printOglError(char *file, int line)
{
    GLenum glErr;
    int retCode = 0;

 

    glErr = glGetError();///获取错误
    while (glErr != GL_NO_ERROR)
    {
        printf("glError in file %s @ line %d: %s\n", file, line, gluErrorString(glErr));
        retCode = 1;
        glErr = glGetError();///获取下一个错误
    }
    return retCode;
}

 

**
* @brief 打印日志
**
void printInfoLog(GLhandleARB obj)
{
    int infologLength = 0;
    int charsWritten  = 0;
    char *infoLog;

 

    glGetObjectParameterivARB(obj, GL_OBJECT_INFO_LOG_LENGTH_ARB,
                                         &infologLength);

    if (infologLength > 0)
    {
        infoLog = (char *)malloc(infologLength);
        glGetInfoLogARB(obj, infologLength, &charsWritten, infoLog);
        printf("%s\n",infoLog);
        free(infoLog);
    }
}

 

**
* @brief 设置着色器
**
void setShaders()
{
    GLhandleARB v,f,p;
    char *vs = NULL,*fs = NULL;

 

    ///创造空白顶点着色器对象并返回其句柄
    v = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);   ///顶点着色器 v
    f = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB); ///片元着色器 f

 

    ///读取着色器源代码文件
    vs = textFileRead("minimal.vert");///顶点着色器源代码字符串
    fs = textFileRead("minimal.frag");///片元着色器源代码字符串

 

    ///加入到字符串数组
    const char * vv = vs;
    const char * ff = fs;


    /// 将着色器源代码字符串数组提交给空白的着色器
    /// glShaderSourceARB() 参数表:
    /// GLhandleARB shader        --- 着色器
    /// GLuint nstrings           --- 字符串数组中多少个元素 本例子就只有1个字符串
    /// const GLcharARB **strings --- 字符串数组
    /// GLint *lengths            --- 对应字符串数组的长度数组 NULL表示所有字符串以null结束
    
glShaderSourceARB(v, 1, &vv,NULL);
    glShaderSourceARB(f, 1, &ff,NULL);

 

    ///释放字符串所占用的内存空间
    free(vs);
    free(fs);

 

    ///编译源代码
    glCompileShaderARB(v);
    glCompileShaderARB(f);

 

    ///打印日志
    printInfoLog(v);
    printInfoLog(f);

 

    ///创造空白程序对象并返回其句柄
    p = glCreateProgramObjectARB();

 

    ///将着色器对象附加到程序对象
    glAttachObjectARB(p,v);
    glAttachObjectARB(p,f);

 

    ///链接程序对象 打印日志
    glLinkProgramARB(p);
    printInfoLog(p);

 

    ///安装程序对象
    glUseProgramObjectARB(p);
}
   

**
* @brief 主函数 程序入口
**
int main(int argc, char **argv)
{
    ///创建窗口相关函数
    glutInit(&argc, argv);///初始化GLUT并处理命令行参数
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);///深度缓存 双缓存 RGBA颜色模式
    glutInitWindowPosition(100,100);///窗口左上角位置
    glutInitWindowSize(320,320);///窗口大小
    glutCreateWindow("GLSL的第一步");///创建窗口

 

    ///注册各种回调函数
    glutDisplayFunc(renderScene);///注册显示回调函数 renderScene
    glutIdleFunc(renderScene);///注册后台管理函数(事件循环空闲时运行) renderScene
    glutReshapeFunc(changeSize);///注册窗口大小改变时的回调函数 changeSize
    glutKeyboardFunc(processNormalKeys);///注册键盘输入回调函数 processNormalKeys

 

    ///启动必须的功能
    glEnable(GL_DEPTH_TEST);///开启深度缓存测试
    glEnable(GL_CULL_FACE);///启动多边形剔除功能
    glClearColor(1.0,1.0,1.0,1.0);///指定清除颜色

 

    glewInit();///glew初始化
    ///检测是否支持基本的顶点着色器和片元着色器
    if(GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader)
    {
        printf("Ready for GLSL\n");
    }
    else
    {
        printf("No GLSL support\n");
        exit(1);
    }

 

    setShaders();///设置着色器
    glutMainLoop();///进入主循环
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值