基于MFC的OpenGL shader编程--我的第一个shader

一.环境配置

由于微软公司为了推销自己的产品DirectX,击败OpenGL,因此现在的windows操作系统只支持OpenGL1.1版本,而现在的OpengGL版本已经发展到了3.1,并且只有2.0以上的版本才支持GLSL语言,所以我们必须对操作系统上的OpenGL进行升级,那么应该如何升级呢?实际上,下载OpenGL2.0以上的开发库是没用的,因为windows只支持1.1版本。所以,要想解决这个问题,只能使用OpenGL扩展。这里我建议(也是许多人建议的)大家使用GLEW扩展库,因为它使用起来较为简单。

第一步:下载GLEW库。网址:

 

 

http://glew.sourceforge.net/index.html

第二步:解压缩文件,将include文件夹内的所有头文件添加到VC98/INCLUDE/GL中,将lib文件夹内的所有文件添加到VC98/LIB中,再将bin文件夹内的所有dll文件添加到C盘windows/system32中,OK了,其他文件就不要管了。

第三步:新建工程,在工程-》设置-》link中添加opengl32.lib glu32.lib glew32s.lib

第四步:在stdAfx.h中添加如下语句:

#define GLEW_STATIC 1

#include <glew.h>     (由于glew头文件中已经包含了对gl.h和glu.h的包含,因此这里没有必要include。

第五步:配置OpenGL基本环境,详见上一篇文章《基于MFC的opengl编程》。

第六步:在InitOpenGL函数中添加如下代码:

GLenum err=glewInit();//初始化glew

if(err!=GLEW_OK)

MessageBox("failed to init glew!");

第七步:完成。

二、建立并导入shader文件。

分别建立两个文本文件,将shader源码写入其中,并将名字分别设置为temp.vert和temp.frag。然后将这两个文件复制到工程所在的目录下。

temp.vert的内容如下:

uniform float CoolestTemp;
uniform float TempRange;
attribute float VertexTemp;
varying float Temperature;
void main(void)
{
Temperature=(VertexTemp-CoolestTemp)/TempRange;
gl_Position=gl_ModelViewProjectionMatrix*gl_Vertex;
}

temp.frag的内容如下:

uniform vec3 CoolestColor;
uniform vec3 HottestColor;
varying float Temperature;
void main(void)
{
vec3 color=mix(CoolestColor,HottestColor,Temperature);
gl_FragColor=vec4(color,1.0);
}

这两个shader的作用是定义三角形三个顶点的温度,并根据温度对颜色进行插值。

三、编写连接shader与opengl的函数

//获得shader文件中字符的个数。

int ShaderSize(char *filename)
{
 FILE *fp;
 int count;
 fp=fopen(filename,"rt");
 if(!fp)
  MessageBox("error");
 rewind(fp);
 fseek(fp,0,SEEK_END);
 count=ftell(fp);
 rewind(fp);
 fclose(fp);
 return count;
}

//将shader文件中的代码读取到字符串中,并返回该字符串的指针。

GLchar *ReadShaderSource(char *filename, int len)
{
 GLchar *shader;
 shader=(GLchar*)malloc(sizeof(char)*(len+1));
 FILE *fp;
 memset(shader,0,len+1);
 fp=fopen(filename,"rt+");
 if(!fp)
  MessageBox("error");
 fseek(fp,0,SEEK_SET);
 fread(shader,sizeof(char),len,fp);
 fclose(fp);
 return shader;
}

int InstallShaders( GLchar *Vertex, GLchar *Fragment)
{
  GLint vertCompiled, fragCompiled;    // status values

    GLint linked;

 

    // Create a vertex shader object and a fragment shader object

 

    vertexShaderObject = glCreateShader(GL_VERTEX_SHADER);

    fragmentShaderObject = glCreateShader(GL_FRAGMENT_SHADER);

 

    // Load source code strings into shaders

 

    glShaderSource(vertexShaderObject, 1, (const char **)&Vertex, NULL);

    glShaderSource(fragmentShaderObject, 1, (const char **)&Fragment, NULL);

 

    // Compile the brick vertex shader, and print out

    // the compiler log file.

 

    glCompileShader(vertexShaderObject);

    glGetShaderiv(vertexShaderObject, GL_COMPILE_STATUS, &vertCompiled);

 

    // Compile the brick vertex shader, and print out

    // the compiler log file.

 

    glCompileShader(fragmentShaderObject);

    glGetShaderiv(fragmentShaderObject, GL_COMPILE_STATUS, &fragCompiled);

 

    if (!vertCompiled || !fragCompiled)

        MessageBox("error");

 

    // Create a program object and attach the two compiled shaders

 

    programObject = glCreateProgram();

    glAttachShader(programObject, vertexShaderObject);

    glAttachShader(programObject, fragmentShaderObject);

 

    // Link the program object and print out the info log

 

    glLinkProgram(programObject);

    glGetProgramiv(programObject, GL_LINK_STATUS, &linked);

 

    if (!linked)

        MessageBox("error");

/* int infologlength;
 int charswrriten;
char *infolog;
    // Install program object as part of current state

 glGetShaderiv(vertexShaderObject,GL_INFO_LOG_LENGTH,&infologlength);
infolog=(char*)malloc(infologlength);
 glGetShaderInfoLog(vertexShaderObject,infologlength,&charswrriten,infolog);
 MessageBox(infolog);
glGetShaderiv(fragmentShaderObject,GL_INFO_LOG_LENGTH,&infologlength);
infolog=(char*)malloc(infologlength);
 glGetShaderInfoLog(fragmentShaderObject,infologlength,&charswrriten,infolog);
 MessageBox(infolog);*/

//以上的代码被注释起来,作用是获得shader编译后的错误报告,用于调试,由于已经调试成功,这里就不需要这些代码了

    glUseProgram(programObject);

 

    // Set up initial uniform values

    glUniform1f(glGetUniformLocation(programObject, "CoolestTemp"), 0.0f);

    glUniform1f(glGetUniformLocation(programObject, "TempRange"), 1.0f);

    glUniform3f(glGetUniformLocation(programObject, "CoolestColor"), 0.0, 0.0, 1.0);

    glUniform3f(glGetUniformLocation(programObject, "HottestColor"), 1.0, 0.0, 0.0);

 

    return 1;


}

将这三个函数添加到VIEW类当中。注意,InstallShaer函数中的vertexShaderObject   fragmentShaderObject以及programObject是VIEW类下的成员变量,需要大家手动添加到view类中。这三个变量都是GLuint类型。

同时,在view类中添加vertexShaderSource和fragmentShaderSource这两个变量,用于接收ReadShaderSource函数返回的指针。这两个变量都是GLchar*型。

在函数InitializeOpenGL中添加如下代码:

vertexShaderSource=ReadShaderSource("temp.vert",ShaderSize("temp.vert"));
 fragmentShaderSource=ReadShaderSource("temp.frag",ShaderSize("temp.frag"));
 InstallShaders(vertexShaderSource,fragmentShaderSource);

这样的话,shader源码就被编译为机器代码,加载到显卡上从而成为了OpenGL状态的一部分。

四、编写OpenGL绘图函数。

void RenderScene()
{
 glTranslatef(0.0,0.0,-3.0); 
GLint tempLoc = glGetAttribLocationARB(programObject, "VertexTemp");

         glBegin(GL_TRIANGLES);

                   glVertexAttrib1f(tempLoc, 0.0f);        

                   glVertex3f(1.0f,0.0f,0.0f);

                   glVertexAttrib1f(tempLoc, 0.5f);

                   glVertex3f(-1.0f,0.0f,0.0f);

                   glVertexAttrib1f(tempLoc, 1.0f);

                   glVertex3f(0.0f,1.0f,0.0f);

         glEnd();


 glLoadIdentity();
}

将该函数添加到VIEW类下。

在Ondraw()函数下写入如下代码:

::glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 RenderScene();
 ::glFlush();
 ::SwapBuffers(m_pDC->GetSafeHdc());

五、运行程序

这时候,你就会看到一个彩色三角形出现在屏幕上了!

说明:如果你的显卡为集成显卡或显卡驱动版本太低,则无法运行这段程序。

qq:756459676

邮箱:[email protected]

欢迎各位指正错误。

你可能感兴趣的:(编程,object,mfc,FP,compiler,shader)