OSG环境下,使用glsl绘制Bezier曲线,这个过程在几何着色器中实现。Bezier曲线的实现原理感兴趣的亲们可以自己百度一下,很多文章都写有,在这里就不赘述了。
在本例子中,使用的是4个控制点实现三次Bezier曲线。
直接贴代码:
#include <osgViewer/Viewer>
#include <osg/Program>
#include <osg/LineWidth>
#include <osgDB/ReadFile>
#include <osg\Geometry>
#include <osg/Drawable>
void LoadShader(osg::StateSet* stateset)
{
const std::string VertSource =
"#version 330 \n"
"layout (location = 0) in vec4 Position; \n"
"uniform vec4 color; \n"
"uniform mat4 osg_ModelViewProjectionMatrix; \n"
" \n"
"void main() \n"
"{ \n"
" gl_Position = osg_ModelViewProjectionMatrix * Position; \n"
"} \n"
"\n";
osg::Shader* VertShader = new osg::Shader(osg::Shader::VERTEX, VertSource);
const std::string FragSource =
"#version 330 \n"
" \n"
"uniform vec4 color; \n"
"layout (location = 0) out vec4 fragData; \n"
" \n"
"void main() \n"
"{ \n"
" fragData = color; \n"
"} \n"
"\n";
osg::Shader* FragShader = new osg::Shader(osg::Shader::FRAGMENT, FragSource);
const std::string GoemSource =
"#version 330 \n"
"layout(lines_adjacency) in; \n"/*基元类型模式lines_adjacency,输入图元邻接线,输入数组gl_in[]大小为4,刚好绘制三次bezier曲线需要四个控制点*/
"layout(line_strip) out; \n"
"layout(max_vertices = 200) out; \n"/*输出顶点数为segments+1*/
"uniform int segments;\n"
"void main(void)\n"
"{\n"
" float delta = 1.0 / float(segments);\n"
" vec4 v;\n"
" for ( int i=0; i<=segments; ++i )\n"
" {\n"
" float t = delta * float(i);\n"//插值计算参数t与segment关联起来
" float t2 = t * t;\n"
" float one_minus_t = 1.0 - t;\n"
" float one_minus_t2 = one_minus_t * one_minus_t;\n"
" v = gl_in[0].gl_Position * one_minus_t2 * one_minus_t +\n"/*gl_in[]的长度由输入图元模式决定,若输入图元模式为三角形,则大小为3*/
" gl_in[1].gl_Position * 3.0 * t * one_minus_t2 +\n"
" gl_in[2].gl_Position * 3.0 * t2 * one_minus_t +\n"
" gl_in[3].gl_Position * t2 * t;\n"
" gl_Position = v;\n"
" EmitVertex();\n"
" }\n"
" EndPrimitive();\n"
"}\n"
"\n";
osg::Shader* GoemShader = new osg::Shader(osg::Shader::GEOMETRY, GoemSource);
osg::Program* program = new osg::Program;
program->addShader(VertShader);
program->addShader(GoemShader);
program->addShader(FragShader);
int segments = 6;
stateset->setAttribute(program);
stateset->addUniform(new osg::Uniform("segments", segments));
osg::Vec4 color(0.0, 1.0, 0.5, 1.0);
stateset->addUniform(new osg::Uniform("color", color));
osg::ref_ptr<osg::LineWidth> linewith = new osg::LineWidth;
linewith->setWidth(2.0f);
stateset->setAttribute(linewith.get());
}
int main()
{
osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
vertices->push_back(osg::Vec3(0.0f, 0.0f, 0.0f));/*<起点>*/
vertices->push_back(osg::Vec3(1.0f, 1.0f, 1.0f));
vertices->push_back(osg::Vec3(2.0f, 1.0f, -1.0f));
vertices->push_back(osg::Vec3(3.0f, 0.0f, 0.0f));/*<终点>*/
osg::Geometry* geom = new osg::Geometry();
geom->setVertexArray(vertices);
geom->addPrimitiveSet(new osg::DrawArrays(GL_LINES_ADJACENCY, 0, 4));//DrawArrays()的绘制模式是若需要绘制两个三角形,则需要传6个顶点进顶点数组中
LoadShader(geom->getOrCreateStateSet());
const int width(800), height(450);
const std::string version("3.1");
osg::ref_ptr< osg::GraphicsContext::Traits > traits = new osg::GraphicsContext::Traits();
traits->x = 50; traits->y = 30;
traits->width = width; traits->height = height;
traits->windowDecoration = true;
traits->doubleBuffer = true;
traits->glContextVersion = version;
osg::ref_ptr< osg::GraphicsContext > gc = osg::GraphicsContext::createGraphicsContext(traits.get());
if (!gc.valid())
{
osg::notify(osg::FATAL) << "Unable to create OpenGL v" << version << " context." << std::endl;
return 0;
}
osgViewer::Viewer viewer;
// Create a Camera that uses the above OpenGL context.
osg::Camera* cam = viewer.getCamera();
cam->setGraphicsContext(gc.get());
// Must set perspective projection for fovy and aspect.
cam->setProjectionMatrix(osg::Matrix::perspective(30., (double)width / (double)height, 1., 100.));
// Unlike OpenGL, OSG viewport does *not* default to window dimensions.
cam->setViewport(new osg::Viewport(0, 0, width, height));
viewer.setSceneData(geom);
// for non GL3/GL4 and non GLES2 platforms we need enable the osg_ uniforms that the shaders will use,
// you don't need thse two lines on GL3/GL4 and GLES2 specific builds as these will be enable by default.
gc->getState()->setUseModelViewAndProjectionUniforms(true);
gc->getState()->setUseVertexAttributeAliasing(true);
return viewer.run();
}