如果你还手里有老老版 OpenGL编程指南 ,打开来看一看,在真正开始用 OpenGL绘制图形时,使用的是下面的API:
glBegin(GL_TRIANGLES); // 绘制三角形
glVertex3f( 0.0f, 1.0f, 0.0f); // 上顶点
glVertex3f(-1.0f,-1.0f, 0.0f); // 左下
glVertex3f( 1.0f,-1.0f, 0.0f); // 右下
glEnd();
这就是已经被抛弃的 固定管线编程 。
http://blog.csdn.net/huutu
先去洗个脑,扔掉你所学过的那些 固定管线 编程 的OpenGL API,留下你脑袋里面的强大的图形数学知识,让我们进入可编程管线。
上图中虚线是 固定管线,黑色粗实线 是 可编程管线 。
可以看到这里 用了 顶点程序、片元程序字样,就是说,这两个过程是可编程的,要我们自己写代码去控制。
顶点程序就是常说的 顶点 Shader ,后缀一般是vsh , 片元程序 就是常说的 片段Shader,后缀一般是 fsh 。
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
好。
我们编写的 Shader 代码是可以运行在GPU上的,既然是作为一段程序,那么和我们平时写的C++代码一样,想要最后运行起来也要经过一个流程。
1、创建一个项目 glCreateProgram
2、创建一个代码文件 glCreateShader
3、输入代码 glShaderSource
4、编译代码 glCompileShader
5、查看编译是否错误 glGetShaderiv
6、把Shader添加到项目中 glAttachShader
7、链接每个Shader glLinkProgram
8、获取链接状态 glGetProgramiv
9、运行这个项目 glUseProgram
下面是一个Shader 的完整例子,包含上面的流程
#pragma once
#include
#include
#include
class ShaderID
{
public:
ShaderID()
{
m_shaderId = -1;
}
int m_shaderId;
};
//封装OpenGL 的glProgram的一些信息;
class GLProgram
{
public:
int m_programId;
ShaderID m_vertexShader;
ShaderID m_fragmentShader;
public:
GLProgram()
{
m_programId = -1;
}
public:
//加载shader并且创建glProgram;
bool createProgram(const char *vertex, const char *fragment)
{
bool error = false;
do
{
if (vertex)
{
//创建Shader;
m_vertexShader.m_shaderId = glCreateShader(GL_VERTEX_SHADER);
//源码;
glShaderSource(m_vertexShader.m_shaderId, 1, &vertex, 0);
//编译;
glCompileShader(m_vertexShader.m_shaderId);
GLint compileStatus;
glGetShaderiv(m_vertexShader.m_shaderId, GL_COMPILE_STATUS, &compileStatus);
error = (compileStatus == GL_FALSE);
if (error)
{
GLchar message[256];
glGetShaderInfoLog(m_vertexShader.m_shaderId, sizeof(message), 0, message);
assert((message && 0) != 0);
break;
}
}
if (fragment)
{
//创建Shader;
m_fragmentShader.m_shaderId = glCreateShader(GL_FRAGMENT_SHADER);
//源码;
glShaderSource(m_fragmentShader.m_shaderId, 1, &fragment, 0);
//编译;
glCompileShader(m_fragmentShader.m_shaderId);
GLint compileStatus;
glGetShaderiv(m_fragmentShader.m_shaderId, GL_COMPILE_STATUS, &compileStatus);
error = (compileStatus == GL_FALSE);
if (error)
{
GLchar message[256];
glGetShaderInfoLog(m_fragmentShader.m_shaderId, sizeof(message), 0, message);
assert((message && 0) != 0);
break;
}
}
//创建gl程序;
m_programId = glCreateProgram();
//代码添加到program中;
if (m_vertexShader.m_shaderId)
{
glAttachShader(m_programId, m_vertexShader.m_shaderId);
}
if (m_fragmentShader.m_shaderId)
{
glAttachShader(m_programId, m_fragmentShader.m_shaderId);
}
//链接;
glLinkProgram(m_programId);
GLint linkStatus;
glGetProgramiv(m_programId, GL_LINK_STATUS, &linkStatus);
if (linkStatus == GL_FALSE)
{
GLchar message[256];
glGetProgramInfoLog(m_programId, sizeof(message), 0, message);
assert((message && 0) != 0);
break;
}
//使用program;
//glUseProgram(m_programId);
} while (false);
if (error)
{
if (m_fragmentShader.m_shaderId)
{
glDeleteShader(m_fragmentShader.m_shaderId);
m_fragmentShader.m_shaderId = 0;
}
if (m_vertexShader.m_shaderId)
{
glDeleteShader(m_vertexShader.m_shaderId);
m_vertexShader.m_shaderId = 0;
}
if (m_programId)
{
glDeleteProgram(m_programId);
m_programId = 0;
}
}
return true;
}
virtual void begin()
{
glUseProgram(m_programId);
}
virtual void end()
{
glUseProgram(0);
}
};
一对简单的 Vertex Shader 和 Fragment Shader 可能长的像下面
const char* vertexShader=
{
"precision lowp float;"
"uniform mat4 m_mvp;"
"attribute vec3 m_position;"
"attribute vec4 m_color;"
"varying vec4 m_outColor;"
"void main()"
"{"
" vec4 pos=vec4(m_position,1);"
" gl_Position=m_mvp*pos;"
" m_outColor=m_color;"
"}"
};
const char* fragmentShader =
{
"precision lowp float;"
"varying vec4 m_outColor;"
"void main()"
"{"
" gl_FragColor=m_outColor;"
"}"
};
uniform 、attribute 都是变量修饰符。这两个修饰符修饰的变量 ,我们可以在 C++ 代码中获取到然后给他们赋值。
varying 修饰符修饰的变量代表在 Vertex 和 Fragment 之间传递。不能从C++代码中操作。
uniform mat4 m_mvp
我们从C++中传入 MVP 矩阵
attribute vec3 m_position
我们从C++中传入 顶点位置
attribute vec4 m_color
我们从C++中传入 顶点颜色
好了。下面就让我们来设置这些变量。
这里继承了上面的类
#pragma once
#include"GLProgram.h"
class GLProgram_Color :public GLProgram
{
public:
//传入shader中的值;
GLint m_position;
GLint m_color;
GLint m_mvp;
public:
GLProgram_Color()
{
m_position = -1;
m_color = -1;
m_mvp = -1;
}
~GLProgram_Color()
{}
GLint getPositionAttribute() const
{
return m_position;
}
GLint getColorAttribute() const
{
return m_color;
}
GLint getMVP() const
{
return m_mvp;
}
//attribute:只能在Vertexshader中使用;
//Unifrom:在Vertex和Fragment中共享使用,且不能被修改;
//Varying:从Vertex传递数据到Fragment中使用;
virtual bool Initialize()
{
const char* vertexShader=
{
"precision lowp float;"
"uniform mat4 m_mvp;"
"attribute vec3 m_position;"
"attribute vec4 m_color;"
"varying vec4 m_outColor;"
"void main()"
"{"
" vec4 pos=vec4(m_position,1);"
" gl_Position=m_mvp*pos;"
" m_outColor=m_color;"
"}"
};
const char* fragmentShader =
{
"precision lowp float;"
"varying vec4 m_outColor;"
"void main()"
"{"
" gl_FragColor=m_outColor;"
"}"
};
bool ret = createProgram(vertexShader, fragmentShader);
if (ret)
{
m_position = glGetAttribLocation(m_programId, "m_position");
m_color = glGetAttribLocation(m_programId, "m_color");
m_mvp = glGetUniformLocation(m_programId, "m_mvp");
}
return ret;
}
virtual void begin()
{
glUseProgram(m_programId);
glEnableVertexAttribArray(m_position);
glEnableVertexAttribArray(m_color);
}
virtual void end()
{
glDisableVertexAttribArray(m_position);
glDisableVertexAttribArray(m_color);
glUseProgram(0);
}
};
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn
可以看到,在创建Shader 并且编译成功之后,就可以获取 Shader 中的变量了。
bool ret = createProgram(vertexShader, fragmentShader);
if (ret)
{
m_position = glGetAttribLocation(m_programId, "m_position");
m_color = glGetAttribLocation(m_programId, "m_color");
m_mvp = glGetUniformLocation(m_programId, "m_mvp");
}
然后像下面这样去传入值 到这几个变量
glUniformMatrix4fv(m_program.m_mvp, 1, false, &proj[0][0]);
glVertexAttribPointer(m_program.m_position, 2, GL_FLOAT, false, sizeof(glm::vec3), pos);
glVertexAttribPointer(m_program.m_color, 4, GL_FLOAT, false, sizeof(glm::vec4), color);
这里说下MVP
MVP是一个矩阵,是由 模型矩阵 乘以 视图矩阵 乘以 投影矩阵 得来的,代表对世界坐标系中的一个点执行的一系列 操作。
想详细了解的请百度相关资料,关键字:OpenGL 矩阵变换
好了,我们在教程一的基础上添加了 一些修改,创建了Shader、给Shader设置了值,并且引入了一个三方库 GLM 来进行矩阵的计算。
示例程序下载:
http://pan.baidu.com/s/1eQjW5O2
转自http://blog.csdn.net/huutu http://www.thisisgame.com.cn