您的位置:首页 > 运维架构

OpenGL Shading Language 入门之 Hello World

2015-03-31 14:31 267 查看
帛裂七弦原创作品,转载请注明 http://blog.sina.com.cn/blqx

不管什么语言第一步都是 Hello 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”就是进行这方面的工作。





文本操作 “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);

}
下面就是最关键的部分 整个设置着色器的步骤是:

创造空白顶点着色器

读取着色器源代码文件

将着色器源代码字符串数组提交给空白的着色器

编译源代码

创造空白程序对象

将着色器对象附加到程序对象

链接程序对象

安装程序

主要操作 “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;

}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: