OpenSceneGraph实现的NeHe OpenGL教程 - 第二十八课
来源:互联网 发布:淘宝漏洞1元买东西 编辑:程序博客网 时间:2024/05/17 01:47
简介
NeHe教程在这节课中向我们介绍了贝塞尔曲面,贝塞尔曲面是一种可以只使用很少的参数就可以描述出复杂曲面的一种数学工具。关于贝塞尔曲线的内容可以参考Bézier surface
实现
本课的实现过程非常简单,在理解了贝塞尔曲面之后利用贝塞尔曲面的计算公式计算出控制点和插值点坐标:
控制点线条的代码如下:
[cpp] view plain copy
- osg::Geode* createBezierControlLineGeode()
- {
- osg::Geode *geode = new osg::Geode;
- osg::Geometry *geometry = new osg::Geometry;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec3Array *colorArray = new osg::Vec3Array;
- colorArray->push_back(osg::Vec3(1.0, 0.0, 0.0));
- geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- geometry->setVertexArray(vertexArray);
- geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- for(int i=0;i<4;i++) { // draw the horizontal lines
- for(int j=0;j<4;j++)
- vertexArray->push_back(osg::Vec3(mybezier.anchors[i][j].x, mybezier.anchors[i][j].y, mybezier.anchors[i][j].z));
- }
- for(int i=0;i<4;i++) { // draw the vertical lines
- for(int j=0;j<4;j++)
- vertexArray->push_back(osg::Vec3(mybezier.anchors[j][i].x, mybezier.anchors[j][i].y, mybezier.anchors[j][i].z));
- }
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, vertexArray->size() / 2));
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, vertexArray->size() / 2, vertexArray->size() / 2));
- geode->addDrawable(geometry);
- return geode;
- }
[cpp] view plain copy
- osg::Geode* createBezierGeode(BEZIER_PATCH patch, int divs)
- {
- int u = 0, v;
- float py, px, pyold;
- POINT_3D temp[4];
- POINT_3D *last = (POINT_3D*)malloc(sizeof(POINT_3D)*(divs+1));
- // array of points to mark the first line of polys
- temp[0] = patch.anchors[0][3]; // the first derived curve (along x axis)
- temp[1] = patch.anchors[1][3];
- temp[2] = patch.anchors[2][3];
- temp[3] = patch.anchors[3][3];
- for (v=0;v<=divs;v++) { // create the first line of points
- px = ((float)v)/((float)divs); // percent along y axis
- // use the 4 points from the derives curve to calculate the points along that curve
- last[v] = Bernstein(px, temp);
- }
- osg::Geode *geode = new osg::Geode;
- osg::Geometry *geometry = new osg::Geometry;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec2Array *textureArray = new osg::Vec2Array;
- geometry->setVertexArray(vertexArray);
- geometry->setTexCoordArray(0, textureArray);
- osg::Vec3Array *colorArray = new osg::Vec3Array;
- colorArray->push_back(osg::Vec3(1, 1, 1));
- geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- for (u=1;u<=divs;u++) {
- py = ((float)u)/((float)divs); // Percent along Y axis
- pyold = ((float)u-1.0f)/((float)divs); // Percent along old Y axis
- temp[0] = Bernstein(py, patch.anchors[0]); // Calculate new bezier points
- temp[1] = Bernstein(py, patch.anchors[1]);
- temp[2] = Bernstein(py, patch.anchors[2]);
- temp[3] = Bernstein(py, patch.anchors[3]);
- for (v=0;v<=divs;v++) {
- px = ((float)v)/((float)divs); // Percent along the X axis
- textureArray->push_back(osg::Vec2(pyold, px)); // Apply the old texture coords
- vertexArray->push_back(osg::Vec3(last[v].x, last[v].y, last[v].z)); // Old Point
- last[v] = Bernstein(px, temp); // Generate new point
- textureArray->push_back(osg::Vec2(py, px)); // Apply the new texture coords
- vertexArray->push_back(osg::Vec3(last[v].x, last[v].y, last[v].z)); // New Point
- }
- }
- osg::Texture2D *bezierTex = new osg::Texture2D;
- bezierTex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- bezierTex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- bezierTex->setImage(osgDB::readImageFile("Data/NeHe.bmp"));
- geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, bezierTex);
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));
- geode->addDrawable(geometry);
- return geode;
- }
[cpp] view plain copy
- osg::Switch *switchLineAndGeodeSwitch = new osg::Switch;
- g_Swith = switchLineAndGeodeSwitch;
- rotZMT->addChild(switchLineAndGeodeSwitch);
- switchLineAndGeodeSwitch->addChild(createBezierControlLineGeode());
- switchLineAndGeodeSwitch->addChild(createBezierGeode(mybezier, divs));
- switchLineAndGeodeSwitch->setAllChildrenOn();
[cpp] view plain copy
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Space)
- {
- if (!g_Swith)
- return false;
- if (g_Swith->getValue(0)){
- g_Swith->setSingleChildOn(1);
- }else{
- g_Swith->setAllChildrenOn();
- }
- }
最后编译运行程序:
附:本课源码(源码中可能存在错误和不足,仅供参考)
[cpp] view plain copy
- #include "../osgNeHe.h"
- #include <QtCore/QTimer>
- #include <QtGui/QApplication>
- #include <QtGui/QVBoxLayout>
- #include <osgViewer/Viewer>
- #include <osgDB/ReadFile>
- #include <osgQt/GraphicsWindowQt>
- #include <osg/MatrixTransform>
- #include <osg/Texture2D>
- #include <osg/Switch>
- osg::MatrixTransform *g_ZRotMT = NULL;
- osg::Switch *g_Swith = NULL;
- typedef struct point_3d {
- double x, y, z;
- } POINT_3D;
- typedef struct bpatch {
- POINT_3D anchors[4][4];
- } BEZIER_PATCH;
- BEZIER_PATCH mybezier;
- int divs = 7;
- POINT_3D pointAdd(POINT_3D p, POINT_3D q) {
- p.x += q.x; p.y += q.y; p.z += q.z;
- return p;
- }
- POINT_3D pointTimes(double c, POINT_3D p) {
- p.x *= c; p.y *= c; p.z *= c;
- return p;
- }
- POINT_3D makePoint(double a, double b, double c) {
- POINT_3D p;
- p.x = a; p.y = b; p.z = c;
- return p;
- }
- // Calculates 3rd degree polynomial based on array of 4 points
- // and a single variable (u) which is generally between 0 and 1
- POINT_3D Bernstein(float u, POINT_3D *p) {
- POINT_3D a, b, c, d, r;
- a = pointTimes(pow(u,3), p[0]);
- b = pointTimes(3*pow(u,2)*(1-u), p[1]);
- c = pointTimes(3*u*pow((1-u),2), p[2]);
- d = pointTimes(pow((1-u),3), p[3]);
- r = pointAdd(pointAdd(a, b), pointAdd(c, d));
- return r;
- }
- //////////////////////////////////////////////////////////////////////////
- void initBezier(void) {
- mybezier.anchors[0][0] = makePoint(-0.75, -0.75, -0.5);
- mybezier.anchors[0][1] = makePoint(-0.25, -0.75, 0.0);
- mybezier.anchors[0][2] = makePoint(0.25, -0.75, 0.0);
- mybezier.anchors[0][3] = makePoint(0.75, -0.75, -0.5);
- mybezier.anchors[1][0] = makePoint(-0.75, -0.25, -0.75);
- mybezier.anchors[1][1] = makePoint(-0.25, -0.25, 0.5);
- mybezier.anchors[1][2] = makePoint(0.25, -0.25, 0.5);
- mybezier.anchors[1][3] = makePoint(0.75, -0.25, -0.75);
- mybezier.anchors[2][0] = makePoint(-0.75, 0.25, 0.0);
- mybezier.anchors[2][1] = makePoint(-0.25, 0.25, -0.5);
- mybezier.anchors[2][2] = makePoint(0.25, 0.25, -0.5);
- mybezier.anchors[2][3] = makePoint(0.75, 0.25, 0.0);
- mybezier.anchors[3][0] = makePoint(-0.75, 0.75, -0.5);
- mybezier.anchors[3][1] = makePoint(-0.25, 0.75, -1.0);
- mybezier.anchors[3][2] = makePoint(0.25, 0.75, -1.0);
- mybezier.anchors[3][3] = makePoint(0.75, 0.75, -0.5);
- }
- //////////////////////////////////////////////////////////////////////////
- //创建贝塞尔曲线
- osg::Geode* createBezierControlLineGeode()
- {
- osg::Geode *geode = new osg::Geode;
- osg::Geometry *geometry = new osg::Geometry;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec3Array *colorArray = new osg::Vec3Array;
- colorArray->push_back(osg::Vec3(1.0, 0.0, 0.0));
- geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- geometry->setVertexArray(vertexArray);
- geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- for(int i=0;i<4;i++) { // draw the horizontal lines
- for(int j=0;j<4;j++)
- vertexArray->push_back(osg::Vec3(mybezier.anchors[i][j].x, mybezier.anchors[i][j].y, mybezier.anchors[i][j].z));
- }
- for(int i=0;i<4;i++) { // draw the vertical lines
- for(int j=0;j<4;j++)
- vertexArray->push_back(osg::Vec3(mybezier.anchors[j][i].x, mybezier.anchors[j][i].y, mybezier.anchors[j][i].z));
- }
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, 0, vertexArray->size() / 2));
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINE_STRIP, vertexArray->size() / 2, vertexArray->size() / 2));
- geode->addDrawable(geometry);
- return geode;
- }
- osg::Geode* createBezierGeode(BEZIER_PATCH patch, int divs)
- {
- int u = 0, v;
- float py, px, pyold;
- POINT_3D temp[4];
- POINT_3D *last = (POINT_3D*)malloc(sizeof(POINT_3D)*(divs+1));
- // array of points to mark the first line of polys
- temp[0] = patch.anchors[0][3]; // the first derived curve (along x axis)
- temp[1] = patch.anchors[1][3];
- temp[2] = patch.anchors[2][3];
- temp[3] = patch.anchors[3][3];
- for (v=0;v<=divs;v++) { // create the first line of points
- px = ((float)v)/((float)divs); // percent along y axis
- // use the 4 points from the derives curve to calculate the points along that curve
- last[v] = Bernstein(px, temp);
- }
- osg::Geode *geode = new osg::Geode;
- osg::Geometry *geometry = new osg::Geometry;
- osg::Vec3Array *vertexArray = new osg::Vec3Array;
- osg::Vec2Array *textureArray = new osg::Vec2Array;
- geometry->setVertexArray(vertexArray);
- geometry->setTexCoordArray(0, textureArray);
- osg::Vec3Array *colorArray = new osg::Vec3Array;
- colorArray->push_back(osg::Vec3(1, 1, 1));
- geometry->setColorArray(colorArray, osg::Array::BIND_OVERALL);
- geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
- for (u=1;u<=divs;u++) {
- py = ((float)u)/((float)divs); // Percent along Y axis
- pyold = ((float)u-1.0f)/((float)divs); // Percent along old Y axis
- temp[0] = Bernstein(py, patch.anchors[0]); // Calculate new bezier points
- temp[1] = Bernstein(py, patch.anchors[1]);
- temp[2] = Bernstein(py, patch.anchors[2]);
- temp[3] = Bernstein(py, patch.anchors[3]);
- for (v=0;v<=divs;v++) {
- px = ((float)v)/((float)divs); // Percent along the X axis
- textureArray->push_back(osg::Vec2(pyold, px)); // Apply the old texture coords
- vertexArray->push_back(osg::Vec3(last[v].x, last[v].y, last[v].z)); // Old Point
- last[v] = Bernstein(px, temp); // Generate new point
- textureArray->push_back(osg::Vec2(py, px)); // Apply the new texture coords
- vertexArray->push_back(osg::Vec3(last[v].x, last[v].y, last[v].z)); // New Point
- }
- }
- osg::Texture2D *bezierTex = new osg::Texture2D;
- bezierTex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
- bezierTex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
- bezierTex->setImage(osgDB::readImageFile("Data/NeHe.bmp"));
- geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, bezierTex);
- geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLE_STRIP, 0, vertexArray->size()));
- geode->addDrawable(geometry);
- return geode;
- }
- //////////////////////////////////////////////////////////////////////////
- ////////////////////场景交互代码////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- class RotAxisCallback : public osg::NodeCallback
- {
- public:
- RotAxisCallback(const osg::Vec3& axis, double rotSpeed = 0.0, double currentAngle = 0.0)
- : _rotAxis(axis), _rotSpeed(rotSpeed), _currentAngle(currentAngle){ }
- virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
- {
- osg::MatrixTransform *rotMT = dynamic_cast<osg::MatrixTransform*>(node);
- if (!rotMT)
- return;
- rotMT->setMatrix(osg::Matrix::rotate(_currentAngle, _rotAxis));
- traverse(node, nv);
- }
- void setRotateAngle(double speed)
- {
- _currentAngle = speed;
- }
- double getRotateAngle() const
- {
- return _currentAngle;
- }
- private:
- osg::Vec3 _rotAxis;
- double _currentAngle;
- double _rotSpeed;
- };
- //////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////
- class ManipulatorSceneHandler : public osgGA::GUIEventHandler
- {
- public:
- ManipulatorSceneHandler()
- {
- }
- virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
- {
- osgViewer::Viewer *viewer = dynamic_cast<osgViewer::Viewer*>(&aa);
- if (!viewer)
- return false;
- if (!viewer->getSceneData())
- return false;
- if (ea.getHandled())
- return false;
- osg::Group *root = viewer->getSceneData()->asGroup();
- switch(ea.getEventType())
- {
- case(osgGA::GUIEventAdapter::KEYDOWN):
- {
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left)
- {
- if (!g_ZRotMT)
- return false;
- RotAxisCallback *rotCallback = dynamic_cast<RotAxisCallback*>(g_ZRotMT->getUpdateCallback());
- if (!rotCallback)
- return false;
- double speed = rotCallback->getRotateAngle();
- speed -= 0.02;
- rotCallback->setRotateAngle(speed);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right)
- {
- if (!g_ZRotMT)
- return false;
- RotAxisCallback *rotCallback = dynamic_cast<RotAxisCallback*>(g_ZRotMT->getUpdateCallback());
- if (!rotCallback)
- return false;
- double speed = rotCallback->getRotateAngle();
- speed += 0.02;
- rotCallback->setRotateAngle(speed);
- }
- if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Space)
- {
- if (!g_Swith)
- return false;
- if (g_Swith->getValue(0)){
- g_Swith->setSingleChildOn(1);
- }else{
- g_Swith->setAllChildrenOn();
- }
- }
- }
- default: break;
- }
- return false;
- }
- };
- class ViewerWidget : public QWidget, public osgViewer::Viewer
- {
- public:
- ViewerWidget(osg::Node *scene = NULL)
- {
- QWidget* renderWidget = getRenderWidget( createGraphicsWindow(0,0,100,100), scene);
- QVBoxLayout* layout = new QVBoxLayout;
- layout->addWidget(renderWidget);
- layout->setContentsMargins(0, 0, 0, 1);
- setLayout( layout );
- connect( &_timer, SIGNAL(timeout()), this, SLOT(update()) );
- _timer.start( 10 );
- }
- QWidget* getRenderWidget( osgQt::GraphicsWindowQt* gw, osg::Node* scene )
- {
- osg::Camera* camera = this->getCamera();
- camera->setGraphicsContext( gw );
- const osg::GraphicsContext::Traits* traits = gw->getTraits();
- camera->setClearColor( osg::Vec4(0.0, 0.0, 0.0, 1.0) );
- camera->setViewport( new osg::Viewport(0, 0, traits->width, traits->height) );
- camera->setProjectionMatrixAsPerspective(45.0f, static_cast<double>(traits->width)/static_cast<double>(traits->height), 0.1f, 100.0f );
- camera->setViewMatrixAsLookAt(osg::Vec3d(0, 0, 1), osg::Vec3d(0, 0, 0), osg::Vec3d(0, 1, 0));
- this->setSceneData( scene );
- addEventHandler(new ManipulatorSceneHandler);
- return gw->getGLWidget();
- }
- osgQt::GraphicsWindowQt* createGraphicsWindow( int x, int y, int w, int h, const std::string& name="", bool windowDecoration=false )
- {
- osg::DisplaySettings* ds = osg::DisplaySettings::instance().get();
- osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
- traits->windowName = name;
- traits->windowDecoration = windowDecoration;
- traits->x = x;
- traits->y = y;
- traits->width = w;
- traits->height = h;
- traits->doubleBuffer = true;
- traits->alpha = ds->getMinimumNumAlphaBits();
- traits->stencil = ds->getMinimumNumStencilBits();
- traits->sampleBuffers = ds->getMultiSamples();
- traits->samples = ds->getNumMultiSamples();
- return new osgQt::GraphicsWindowQt(traits.get());
- }
- virtual void paintEvent( QPaintEvent* event )
- {
- frame();
- }
- protected:
- QTimer _timer;
- };
- osg::Node* buildScene()
- {
- initBezier();
- osg::Group *root = new osg::Group;
- osg::MatrixTransform *zoomMT = new osg::MatrixTransform;
- zoomMT->setMatrix(osg::Matrix::translate(0.0f,0.0f,-4.0f));
- osg::MatrixTransform *rotXMT = new osg::MatrixTransform;
- rotXMT->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(-75.0), osg::X_AXIS));
- osg::MatrixTransform *rotZMT = new osg::MatrixTransform;
- rotZMT->addUpdateCallback(new RotAxisCallback(osg::Z_AXIS));
- g_ZRotMT = rotZMT;
- osg::Switch *switchLineAndGeodeSwitch = new osg::Switch;
- g_Swith = switchLineAndGeodeSwitch;
- rotZMT->addChild(switchLineAndGeodeSwitch);
- switchLineAndGeodeSwitch->addChild(createBezierControlLineGeode());
- switchLineAndGeodeSwitch->addChild(createBezierGeode(mybezier, divs));
- switchLineAndGeodeSwitch->setAllChildrenOn();
- root->addChild(zoomMT);
- zoomMT->addChild(rotXMT);
- rotXMT->addChild(rotZMT);
- return root;
- }
- int main( int argc, char** argv )
- {
- QApplication app(argc, argv);
- ViewerWidget* viewWidget = new ViewerWidget(buildScene());
- viewWidget->setGeometry( 100, 100, 640, 480 );
- viewWidget->show();
- return app.exec();
- }
0 0
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十八课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十八课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第三十八课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第四十八课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第三十八课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第四十八课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十四课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十五课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十六课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十九课
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十七课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十四课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十五课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十六课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十七课
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十九课
- c++中的std::shared_ptr和std::weak_ptr
- 多线程的使用(2) - NSOperation和NSOperationQueue
- Error:Failed to resolve: com.android.support:support-annotations:23.3.0
- day10_python2和python3的继承
- Codeforces 705C Thor (模拟)
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十八课
- jzoj 3076. 【备战NOIP2012图论专项模拟试题】位图
- php 自带过滤和转义函数
- TypeError: 'str' object is not callable
- 基于R-CNN的物体检测-CVPR 2014
- 通过ip地址及端口连接服务器
- php高手干货【必看】
- OpenSceneGraph实现的NeHe OpenGL教程 - 第二十九课
- ActiveMQ实现消息队列发送邮件