目录
1. 前言
OpenGL 3.3及以后版本抛弃了glEnable(),glColor(),glVertex(),glEnable()等这一套传统流程函数和管线,采用着色器语言GLSL来渲染三维场景。相对于传统的管线模式,色器语言GLSL渲染模型具有高度灵活性、高度可编程性,更能实现一些非常复杂的效果。本博文用osg和着色器语言GLSL来实现几个特效,以到达掌握在osg下操作着色器语言GLSL的效果。
2. 用GLSL实现五颜六色的奶牛
本项目通过着色器绘制奶牛,代码如下:
#include <osg/Node>
#include <osgViewer/Viewer>
#include <osg/Program>
#include <osgDB/ReadFile>
#include <osg/Shader>
#include <osgViewer/ViewerEventHandlers>
static const char* vertexShader = {
"varying vec4 color;\n"
"void main(void ){\n"
"color = gl_Vertex;\n"
"gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
"}\n"
};
static const char* fragShader = {
"varying vec4 color;\n"
"void main(void){\n"
" gl_FragColor = clamp(color,0.0,1.0);\n"
"}\n"
};
int main()
{
osg::ref_ptr<osg::Node>node = osgDB::readNodeFile("cow.osg");
if (nullptr == node)
{
OSG_WARN << "cow node is null!";
return 1;
}
osg::ref_ptr<osgViewer::Viewer> viewer = new osgViewer::Viewer;
osg::StateSet* ss = node->getOrCreateStateSet();
osg::Program* program = new osg::Program;
program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragShader));
program->addShader(new osg::Shader(osg::Shader::VERTEX, vertexShader));
ss->setAttributeAndModes(program, osg::StateAttribute::ON);
viewer->addEventHandler(new osgViewer::WindowSizeHandler);
viewer->setSceneData(node.get());
return viewer->run();
}
代码说明:
- osg::Program类从 osg::StateAttribute继承,封装了OPenGL中对着色器操作的glProgram之类的函数,通过addShader函数加入顶点着色器和片段着色器,之后加入奶牛节点的状态集类osg::StateSet对象中。
- 在顶点着色器vertexShader中通过如下代码:
"color = gl_Vertex;\n"
将奶牛未经过视图投影矩阵变换过的原始顶点(gl_Vertex表示的坐标)作为颜色值传递给color,接下来在片段着色器中利用该颜色,考虑到顶点坐标值可能不在[0, 1]区间,故用clamp进行截取,以保证颜色值在[0, 1]区间。该例子运行效果如下:
- 对于顶点着色器,必须对gl_Position赋值;对于片段着色器,必须对gl_FragColor赋值,也就说gl_Position、gl_FragColor必须都要赋值,否则奶牛不会显示。
- 注意:gl_FragColor、varying类型、gl_ModelViewProjectionMatrix 、gl_Vertex在GLSL 1.40之后的版本中移除了,因此在1.40以后的版本使用这些关键字会报错。
3. 用GLSL 4.3.0实现绘制三角形
GLSL 4.30实现绘制三角形代码如下:
#include <osg/shader>
#include <osg/Node>
#include <osgDB/ReadFile>
#include <osgDB/fileutils>
#include <osg/Geometry>
#include <osgViewer/viewer>
static const char* vertexShader = {
"#version 430 \n"
"layout (location=0) in vec3 VertexPosition;\n"
"layout (location=1) in vec4 VertexColor;\n"
"uniform mat4 mvp;\n"
"out vec4 Color;\n"
"out vec4 Position;\n"
"void main()\n"
"{\n"
" Color = VertexColor;\n"
" gl_Position = mvp*vec4(VertexPosition, 1.0);\n"
" }\n"
};
static const char* fragShader = {
"#version 430 \n"
"in vec4 Color;\n"
"layout (location=0) out vec4 FragColor;\n"
"void main() {\n"
" FragColor = Color;//vec4(0.5,0.5,0.5,0.4);\n"
"}\n"
};
osg::Node* CreateNode()
{
osg::Geode* geode = new osg::Geode;
osg::Geometry* polyGeom = new osg::Geometry();
osg::Vec3Array* vertices = new osg::Vec3Array();
vertices->push_back(osg::Vec3(-5, 0, 0));
vertices->push_back(osg::Vec3(5, 0, 0));
vertices->push_back(osg::Vec3(0, 0, 5));
// polyGeom->setVertexArray(vertices); // 非着色器的设置三角形顶点的方式
osg::ref_ptr<osg::Vec4Array> colorsArray = new osg::Vec4Array;
colorsArray->push_back(osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f));
colorsArray->push_back(osg::Vec4(0.0f,