用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十二课
来源:互联网 发布:淘宝网限制购买商品 编辑:程序博客网 时间:2024/05/20 05:53
简介
这节课我们将讨论凹凸纹理技术,使用凹凸纹理可以让物体表面更有质感。本节课实现的其实是一种被称为浮雕纹理的技术(Emboss Bump Mapping),并不能算真正的凹凸纹理实现方式(It is a Hack)。
光滑的表面它上面各点法线的方向是一致的,凹凸纹理通过扰乱它表面的法线方向,在进行光照计算的时候(像素光照计算)会使得光滑表面产生明暗不同的颜色,从而"欺骗"我们的大脑,让我们以为它的表面是凹凸不平的。凹凸纹理最早是由James F. Blinn在1978年提的
NeHe课程中的实现原理可以参考凹凸纹理随笔, 在开始之前先说明一下NeHe课程中的实现方式:
NeHe教程中通过空格切换在三种模式下进行:
1. 未使用多重纹理(MultiTexture)技术进行凹凸纹理处理
2.使用多重纹理(MultiTexture)技术进行凹凸纹理处理
3.渲染不带凹凸纹理的场景
这三个过程分别对应doMesh1TexelUnits、doMesh1Texe2Units、doMeshNoBumps三个函数。本课只实现了在1情形下的凹凸纹理。2的实现也在源码中,但是未找到对应的OpenGL API,希望知道的读者指点一二。
下面简单说一下Emboss Bump Mapping的实现过程:
浮雕纹理需要对模型表面贴两次纹理,第一次纹理的纹理坐标不进行偏移、第二次的纹理坐标会在光照方向上进行偏移。偏移量的计算方法可以参考PPT Emboss Bump Mapping
实现
首先和NeHe教程一下初始化我们需要的纹理:
这里面需要使用osg中的Image类和处理Image的ImageUtil中的内容:部分代码如下:
osg::Image *image1 = new osg::Image;image1 = osgDB::readImageFile("Data/Base.bmp");texture[0] = new osg::Texture2D;texture[0]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);texture[0]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);texture[0]->setImage(image1);texture[1] = new osg::Texture2D;texture[1]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);texture[1]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);texture[1]->setImage(image1);另外我们需要把进行纹理贴图的图像亮度减半,代码如下:
osg::Image *image2 = new osg::Image;image2 = osgDB::readImageFile("Data/Bump.bmp");osg::offsetAndScaleImage(image2, osg::Vec4(), osg::Vec4(0.5, 0.5, 0.5, 1)); // RGB值都减半bump[0] = new osg::Texture2D;bump[0]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);bump[0]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);bump[0]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);bump[0]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);bump[0]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));bump[0]->setImage(image2);此外反转图像RGB值,使得凹的纹理变成凸的纹理:
osg::Image *image3 = osgDB::readImageFile("Data/Bump.bmp");osg::offsetAndScaleImage(image3, osg::Vec4(), osg::Vec4(0.5,0.5,0.5,1));osg::offsetAndScaleImage(image3, osg::Vec4(-128, -128, -128, 1), osg::Vec4(-1,-1,-1,1));invbump[0] = new osg::Texture2D;invbump[0]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);invbump[0]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);invbump[0]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);invbump[0]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);invbump[0]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));invbump[0]->setImage(image3);创建正常显示立方体的代码在createCube函数中。
为了进行凹凸纹理,我们先设置第一次纹理部分,代码如下:
可以看到这一次贴的纹理的纹理坐标并没有偏移,全部用到了data中的原始数据
osg::Geode* createUpMappingCube(){osg::Geode *cubeGeode = new osg::Geode;osg::Geometry *cubeGeometry = new osg::Geometry;osg::Vec3Array *vertices = new osg::Vec3Array;osg::Vec3Array *normals = new osg::Vec3Array;osg::Vec2Array *texcoords = new osg::Vec2Array;for (unsigned i = 0; i < 24; ++i){texcoords->push_back(osg::Vec2(data[5*i],data[5*i + 1])); //第一次贴纹理不需要偏移vertices->push_back(osg::Vec3(data[5*i + 2], data[5*i +3], data[5*i + 4]));}cubeGeometry->setVertexArray(vertices);cubeGeometry->setTexCoordArray(0, texcoords);cubeGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertices->size()));cubeGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, false);cubeGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, bump[1]);osg::Depth *depth = new osg::Depth(osg::Depth::LEQUAL);cubeGeometry->getOrCreateStateSet()->setAttributeAndModes(depth);cubeGeode->addDrawable(cubeGeometry);return cubeGeode;}在进行第二次贴纹理时由于要把光源位置变换到物体表面的切空间中,需要获取此时模型的模型视图矩阵,在设置中难以获得,在回调中获取:
//第二次贴纹理,这里面并没有纹理坐标,因为纹理坐标需要偏移,在回调中计算osg::Geode* createDownMappingCube(){osg::Geode *cubeGeode = new osg::Geode;osg::Geometry *cubeGeometry = new osg::Geometry;cubeGeometry->setUpdateCallback(new TextureCallback());osg::Vec3Array *vertices = new osg::Vec3Array;for (unsigned i = 0; i < 24; ++i){vertices->push_back(osg::Vec3(data[5*i + 2], data[5*i +3], data[5*i + 4]));}cubeGeometry->setVertexArray(vertices);cubeGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertices->size()));cubeGeode->addDrawable(cubeGeometry);return cubeGeode;}
接下来看看回调实现:(只给出部分代码)
virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable){osg::Geometry *geometry = drawable->asGeometry();if (!geometry)return;osg::Vec2Array *textureArray = dynamic_cast<osg::Vec2Array*>(geometry->getTexCoordArray(0));if(textureArray)return;textureArray = new osg::Vec2Array;osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());osg::Vec3 lightPos(LightPosition[0], LightPosition[1], LightPosition[2]); //获取当前模型视图矩阵osg::Matrix currentModelViewMatrix = computeLocalToWorld(nv->getNodePath()) * g_viewer->getCamera()->getViewMatrix();//反转模型视图矩阵 osg::Matrix currentInvModelViewerMatrix = osg::Matrix::inverse(currentModelViewMatrix);//将光源变换到物体建模坐标系下 osg::Vec3 lightInObjectSpace = lightPos * currentInvModelViewerMatrix;//////////////////////////////////////////////////////////////////////////for (int i=0; i<4; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize(); //获取切空间中在S、T轴上的偏移量 double deltaS = orientation * osg::Vec3(1,0,0) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}最后把这三次的结果添加到场景中
osg::Switch *switchNode = new osg::Switch;g_switch = switchNode;rotateYAxis->addChild(switchNode);switchNode->addChild(createUpMappingCube());switchNode->addChild(createDownMappingCube());switchNode->addChild(createCube());在交互操作中设置显示和隐藏原始的模型:
if (ea.getKey() == osgGA::GUIEventAdapter::KEY_E){if (g_switch->getValue(2) == true){g_switch->setValue(2, false);}else{g_switch->setValue(2, true); }}编译运行程序:
附:本课源码(源码中可能存在错误和不足,仅供参考)
#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/LightSource>#include <osg/ImageUtils>#include <osg/Texture2D>#include <osg/BlendFunc>#include <osg/Depth>#include <osg/TexEnv>#include <osg/TexEnvCombine>//////////////////////////////////////////////////////////////////////////const float MaxEmboss = 0.008f;boolmultitextureSupported = false;bool useMultitexture = true;osgViewer::View *g_viewer;osg::Switch *g_switch;osg::Switch *g_switchMulti;GLfloatxrot;GLfloatyrot;GLfloat xspeed;GLfloat yspeed;GLfloatz=-5.0f;GLuintfilter=1;osg::Texture2D*texture[3];osg::Texture2D*bump[3];osg::Texture2D*invbump[3];osg::Texture2D*glLogo;osg::Texture2D*multiLogo;GLfloat LightAmbient[]= { 0.2f, 0.2f, 0.2f};GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f};GLfloat LightPosition[] = { 0.0f, 0.0f, 2.0f};GLfloat data[]= {// FRONT FACE0.0f, 0.0f,-1.0f, -1.0f, +1.0f,1.0f, 0.0f,+1.0f, -1.0f, +1.0f,1.0f, 1.0f,+1.0f, +1.0f, +1.0f,0.0f, 1.0f,-1.0f, +1.0f, +1.0f,// BACK FACE1.0f, 0.0f,-1.0f, -1.0f, -1.0f,1.0f, 1.0f,-1.0f, +1.0f, -1.0f,0.0f, 1.0f,+1.0f, +1.0f, -1.0f,0.0f, 0.0f,+1.0f, -1.0f, -1.0f,// Top Face0.0f, 1.0f,-1.0f, +1.0f, -1.0f,0.0f, 0.0f,-1.0f, +1.0f, +1.0f,1.0f, 0.0f,+1.0f, +1.0f, +1.0f,1.0f, 1.0f,+1.0f, +1.0f, -1.0f,// Bottom Face1.0f, 1.0f,-1.0f, -1.0f, -1.0f,0.0f, 1.0f,+1.0f, -1.0f, -1.0f,0.0f, 0.0f,+1.0f, -1.0f, +1.0f,1.0f, 0.0f,-1.0f, -1.0f, +1.0f,// Right Face1.0f, 0.0f,+1.0f, -1.0f, -1.0f,1.0f, 1.0f,+1.0f, +1.0f, -1.0f,0.0f, 1.0f,+1.0f, +1.0f, +1.0f,0.0f, 0.0f,+1.0f, -1.0f, +1.0f,// Left Face0.0f, 0.0f,-1.0f, -1.0f, -1.0f,1.0f, 0.0f,-1.0f, -1.0f, 1.0f,1.0f, 1.0f,-1.0f, 1.0f, 1.0f,0.0f, 1.0f,-1.0f, 1.0f, -1.0f};////////////////////////////////////////////////////////////////////////////FindFirstNamedNodeVisitor用来遍历寻找与指定名称相同的节点class FindFirstNamedNodeVisitor : public osg::NodeVisitor{public:FindFirstNamedNodeVisitor(const std::string& name): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _name(name), _foundNode(NULL) {} virtual void apply(osg::Node& node) { if (node.getName()==_name) { _foundNode = &node; return; } traverse(node); } std::string _name; osg::Node *_foundNode;};////////////////////////////////////////////////////////////////////////////RotateCallbackclass RotateCallback : public osg::NodeCallback{public:RotateCallback(osg::Vec3d rotateAxis, double rotateSpeed) : osg::NodeCallback(), _rotateAxis(rotateAxis), _rotateSpeed(rotateSpeed), _rotateAngle(0.0) { //Nop } void setRotateSpeed(double speed) { _rotateSpeed = speed; } double getRotateSpeed() const { return _rotateSpeed; } virtual void operator()(osg::Node* node, osg::NodeVisitor* nv) { osg::MatrixTransform *currentMT = dynamic_cast<osg::MatrixTransform*>(node); if (currentMT) { //获取当前的平移位置 osg::Vec3d currentTranslate = currentMT->getMatrix().getTrans(); osg::Matrix newMatrix = osg::Matrix::rotate(_rotateAngle, _rotateAxis) * osg::Matrix::translate(currentTranslate); currentMT->setMatrix(newMatrix); _rotateAngle += _rotateSpeed; } traverse(node, nv); }private:osg::Vec3d _rotateAxis;//旋转轴double _rotateSpeed;//旋转速度double _rotateAngle;//当前旋转的角度};////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////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){FindFirstNamedNodeVisitor fnv("yRotMT");root->accept(fnv);osg::Node *mtNode = fnv._foundNode;osg::MatrixTransform *yRotMT = dynamic_cast<osg::MatrixTransform*>(mtNode);if (!yRotMT)return false;RotateCallback *rotCallback = dynamic_cast<RotateCallback*>(yRotMT->getUpdateCallback());if (!rotCallback)return false;double speed = rotCallback->getRotateSpeed();speed += 0.02;rotCallback->setRotateSpeed(speed);}if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right){FindFirstNamedNodeVisitor fnv("yRotMT");root->accept(fnv);osg::Node *mtNode = fnv._foundNode;osg::MatrixTransform *yRotMT = dynamic_cast<osg::MatrixTransform*>(mtNode);if (!yRotMT)return false;RotateCallback *rotCallback = dynamic_cast<RotateCallback*>(yRotMT->getUpdateCallback());if (!rotCallback)return false;double speed = rotCallback->getRotateSpeed();speed -= 0.02;rotCallback->setRotateSpeed(speed);}if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Up){FindFirstNamedNodeVisitor fnv("xRotMT");root->accept(fnv);osg::Node *mtNode = fnv._foundNode;osg::MatrixTransform *xRotMT = dynamic_cast<osg::MatrixTransform*>(mtNode);if (!xRotMT)return false;RotateCallback *rotCallback = dynamic_cast<RotateCallback*>(xRotMT->getUpdateCallback());if (!rotCallback)return false;double speed = rotCallback->getRotateSpeed();speed += 0.02;rotCallback->setRotateSpeed(speed);}if (ea.getKey()== osgGA::GUIEventAdapter::KEY_Down){FindFirstNamedNodeVisitor fnv("xRotMT");root->accept(fnv);osg::Node *mtNode = fnv._foundNode;osg::MatrixTransform *xRotMT = dynamic_cast<osg::MatrixTransform*>(mtNode);if (!xRotMT)return false;RotateCallback *rotCallback = dynamic_cast<RotateCallback*>(xRotMT->getUpdateCallback());if (!rotCallback)return false;double speed = rotCallback->getRotateSpeed();speed -= 0.02;rotCallback->setRotateSpeed(speed);}if (ea.getKey() == osgGA::GUIEventAdapter::KEY_E){if (g_switch->getValue(2) == true){g_switch->setValue(2, false);}else{g_switch->setValue(2, true); }}}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, 0.5) );camera->setClearDepth(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);g_viewer = this;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;};////////////////////////////////////////////////////////////////////////////创建纹理:代码中只是用到第二个纹理bump[1]和invbmp[1]void initTextures(){osg::Image *image1 = new osg::Image;image1 = osgDB::readImageFile("Data/Base.bmp");texture[0] = new osg::Texture2D;texture[0]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);texture[0]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);texture[0]->setImage(image1);texture[1] = new osg::Texture2D;texture[1]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);texture[1]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);texture[1]->setImage(image1);texture[2] = new osg::Texture2D;texture[2]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);texture[2]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_NEAREST);texture[2]->setImage(image1);osg::Image *image2 = new osg::Image;image2 = osgDB::readImageFile("Data/Bump.bmp");osg::offsetAndScaleImage(image2, osg::Vec4(), osg::Vec4(0.5, 0.5, 0.5, 1));bump[0] = new osg::Texture2D;bump[0]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);bump[0]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);bump[0]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);bump[0]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);bump[0]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));bump[0]->setImage(image2);bump[1] = new osg::Texture2D;bump[1]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);bump[1]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);bump[1]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);bump[1]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);bump[1]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));bump[1]->setImage(image2);bump[2] = new osg::Texture2D;bump[2]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);bump[2]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_NEAREST);bump[2]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);bump[2]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);bump[2]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));bump[2]->setImage(image2);osg::Image *image3 = osgDB::readImageFile("Data/Bump.bmp");osg::offsetAndScaleImage(image3, osg::Vec4(), osg::Vec4(0.5,0.5,0.5,1));osg::offsetAndScaleImage(image3, osg::Vec4(-128, -128, -128, 1), osg::Vec4(-1,-1,-1,1));invbump[0] = new osg::Texture2D;invbump[0]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST);invbump[0]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST);invbump[0]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);invbump[0]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);invbump[0]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));invbump[0]->setImage(image3);invbump[1] = new osg::Texture2D;invbump[1]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);invbump[1]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);invbump[1]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);invbump[1]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);invbump[1]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));invbump[1]->setImage(image3);invbump[2] = new osg::Texture2D;invbump[2]->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);invbump[2]->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_NEAREST);invbump[2]->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);invbump[2]->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);invbump[2]->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));invbump[2]->setImage(image3);osg::Image *glLogoAlpha = osgDB::readImageFile("Data/OpenGL_ALPHA.bmp");osg::Image *glLogoImage = osgDB::readImageFile("Data/OpenGL.bmp");osg::Image *glLogoCombo = new osg::Image;glLogoCombo->allocateImage(glLogoImage->s(), glLogoImage->t(), 1, GL_RGBA, glLogoImage->getDataType());unsigned char *comboData = glLogoCombo->data();for (int i = 0; i < glLogoImage->s() * glLogoImage->t(); ++i){comboData[4*i+3] = glLogoAlpha->data()[i*3];comboData[4*i] = glLogoImage->data()[i*3];comboData[4*i+1] = glLogoImage->data()[i*3+1];comboData[4*i+2] = glLogoImage->data()[i*3+2];}glLogo = new osg::Texture2D;glLogo->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);glLogo->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);glLogo->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);glLogo->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);glLogo->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));glLogo->setImage(glLogoCombo);osg::Image *glMultiAlpha = osgDB::readImageFile("Data/multi_on_alpha.bmp");osg::Image *glMultiImage = osgDB::readImageFile("Data/multi_on.bmp");osg::Image *glMultiCombo = new osg::Image;glMultiCombo->allocateImage(glLogoImage->s(), glLogoImage->t(), 1, GL_RGBA, glLogoImage->getDataType());unsigned char *multiComboData = glMultiCombo->data();for (int i = 0; i < glMultiImage->s() * glMultiImage->t(); ++i){multiComboData[4*i+3] = glMultiAlpha->data()[i*3];multiComboData[4*i] = glMultiImage->data()[i*3];multiComboData[4*i+1] = glMultiImage->data()[i*3+1];multiComboData[4*i+2] = glMultiImage->data()[i*3+2];}multiLogo = new osg::Texture2D;multiLogo->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);multiLogo->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);multiLogo->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP);multiLogo->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP);multiLogo->setBorderColor(osg::Vec4(0.5, 0.5, 0.5, 1.0));multiLogo->setImage(glMultiCombo);}osg::Group *createLogo(){osg::Group *logoGroup = new osg::Group;osg::Depth *depth = new osg::Depth(osg::Depth::ALWAYS);osg::BlendFunc *blendFunc = new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE_MINUS_SRC_ALPHA);osg::Geode *logoGeode = new osg::Geode;osg::Geometry *logoGeometry = new osg::Geometry;osg::Vec3Array *logoVertices = new osg::Vec3Array;logoVertices->push_back(osg::Vec3(0.23f, -0.4f,-1.0f));logoVertices->push_back(osg::Vec3(0.53f, -0.4f,-1.0f));logoVertices->push_back(osg::Vec3(0.53f, -0.25f,-1.0f));logoVertices->push_back(osg::Vec3(0.23f, -0.25f,-1.0f));osg::Vec2Array *textureVertices = new osg::Vec2Array;textureVertices->push_back(osg::Vec2(0.0f,0.0f));textureVertices->push_back(osg::Vec2(1.0f,0.0f));textureVertices->push_back(osg::Vec2(1.0f,1.0f));textureVertices->push_back(osg::Vec2(0.0f,1.0f));logoGeometry->setVertexArray(logoVertices);logoGeometry->setTexCoordArray(0, textureVertices);logoGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));logoGeometry->getOrCreateStateSet()->setAttributeAndModes(depth);logoGeometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);logoGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, glLogo);logoGeode->addDrawable(logoGeometry);osg::Geode *multiGeode = new osg::Geode;osg::Geometry *multiGeometry = new osg::Geometry;osg::Vec3Array *multiVertices = new osg::Vec3Array;multiVertices->push_back(osg::Vec3(-0.53f, -0.4f,-1.0f));multiVertices->push_back(osg::Vec3(-0.33f, -0.4f,-1.0f));multiVertices->push_back(osg::Vec3(-0.33f, -0.3f,-1.0f));multiVertices->push_back(osg::Vec3(-0.53f, -0.3f,-1.0f));osg::Vec2Array *tVertices = new osg::Vec2Array;textureVertices->push_back(osg::Vec2(0.0f,0.0f));textureVertices->push_back(osg::Vec2(1.0f,0.0f));textureVertices->push_back(osg::Vec2(1.0f,1.0f));textureVertices->push_back(osg::Vec2(0.0f,1.0f));multiGeometry->setVertexArray(multiVertices);multiGeometry->setTexCoordArray(0, tVertices);multiGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, 4));multiGeometry->getOrCreateStateSet()->setAttributeAndModes(depth);multiGeometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);multiGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, multiLogo);multiGeode->addDrawable(multiGeometry);logoGroup->addChild(logoGeode);logoGroup->addChild(multiGeode);return logoGroup;}osg::Geode*createCube(){osg::Geode *cubeGeode = new osg::Geode;osg::Geometry *cubeGeometry = new osg::Geometry;osg::Vec3Array *vertices = new osg::Vec3Array;osg::Vec3Array *normals = new osg::Vec3Array;osg::Vec2Array *texcoords = new osg::Vec2Array;for (unsigned i = 0; i < 24; ++i){texcoords->push_back(osg::Vec2(data[5*i],data[5*i + 1]));vertices->push_back(osg::Vec3(data[5*i + 2], data[5*i +3], data[5*i + 4]));}normals->push_back(osg::Vec3(0.0f, 0.0f, +1.0f));normals->push_back(osg::Vec3(0.0f, 0.0f,-1.0f));normals->push_back(osg::Vec3(0.0f, 1.0f, 0.0f));normals->push_back(osg::Vec3(0.0f,-1.0f, 0.0f));normals->push_back(osg::Vec3(1.0f, 0.0f, 0.0f));normals->push_back(osg::Vec3(-1.0f, 0.0f, 0.0f));cubeGeometry->setVertexArray(vertices);cubeGeometry->setTexCoordArray(0, texcoords);cubeGeometry->setNormalArray(normals, osg::Array::BIND_PER_PRIMITIVE_SET);cubeGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertices->size()));cubeGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texture[1]);osg::BlendFunc *blendFunc = new osg::BlendFunc(osg::BlendFunc::DST_COLOR, osg::BlendFunc::SRC_COLOR);cubeGeometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);osg::Depth *depth = new osg::Depth(osg::Depth::LEQUAL);cubeGeometry->getOrCreateStateSet()->setAttributeAndModes(depth);osg::TexEnv *texEnv = new osg::TexEnv(osg::TexEnv::MODULATE);cubeGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, texEnv);cubeGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);cubeGeode->addDrawable(cubeGeometry);return cubeGeode;}osg::Geode* createUpMappingCube(){osg::Geode *cubeGeode = new osg::Geode;osg::Geometry *cubeGeometry = new osg::Geometry;osg::Vec3Array *vertices = new osg::Vec3Array;osg::Vec3Array *normals = new osg::Vec3Array;osg::Vec2Array *texcoords = new osg::Vec2Array;for (unsigned i = 0; i < 24; ++i){texcoords->push_back(osg::Vec2(data[5*i],data[5*i + 1]));vertices->push_back(osg::Vec3(data[5*i + 2], data[5*i +3], data[5*i + 4]));}cubeGeometry->setVertexArray(vertices);cubeGeometry->setTexCoordArray(0, texcoords);cubeGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertices->size()));cubeGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, false);cubeGeometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, bump[1]);osg::Depth *depth = new osg::Depth(osg::Depth::LEQUAL);cubeGeometry->getOrCreateStateSet()->setAttributeAndModes(depth);cubeGeode->addDrawable(cubeGeometry);return cubeGeode;}class TextureCallback : public osg::Drawable::UpdateCallback{public:TextureCallback(){ }virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable){osg::Geometry *geometry = drawable->asGeometry();if (!geometry)return;osg::Vec2Array *textureArray = dynamic_cast<osg::Vec2Array*>(geometry->getTexCoordArray(0));if(textureArray)return;textureArray = new osg::Vec2Array;osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());osg::Vec3 lightPos(LightPosition[0], LightPosition[1], LightPosition[2]);osg::Matrix currentModelViewMatrix = computeLocalToWorld(nv->getNodePath()) * g_viewer->getCamera()->getViewMatrix();osg::Matrix currentInvModelViewerMatrix = osg::Matrix::inverse(currentModelViewMatrix);osg::Vec3 lightInObjectSpace = lightPos * currentInvModelViewerMatrix;//////////////////////////////////////////////////////////////////////////for (int i=0; i<4; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(1,0,0) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=4; i<8; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(-1, 0, 0) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=8; i<12; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(1, 0, 0) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,0,-1) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=12; i<16; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(0, -1, 0) * MaxEmboss;double deltaT = orientation * osg::Vec3(-1,0,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=16; i<20; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(0, 0, -1) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=20; i<24; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(0, 0, 1) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}geometry->setTexCoordArray(0, textureArray);geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, invbump[1]);geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, false);osg::BlendFunc *blendFunc = new osg::BlendFunc(osg::BlendFunc::ONE, osg::BlendFunc::ONE);geometry->getOrCreateStateSet()->setAttributeAndModes(blendFunc);osg::Depth *depth = new osg::Depth(osg::Depth::LEQUAL);geometry->getOrCreateStateSet()->setAttributeAndModes(depth);}};osg::Geode* createDownMappingCube(){osg::Geode *cubeGeode = new osg::Geode;osg::Geometry *cubeGeometry = new osg::Geometry;cubeGeometry->setUpdateCallback(new TextureCallback());osg::Vec3Array *vertices = new osg::Vec3Array;for (unsigned i = 0; i < 24; ++i){vertices->push_back(osg::Vec3(data[5*i + 2], data[5*i +3], data[5*i + 4]));}cubeGeometry->setVertexArray(vertices);cubeGeometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS, 0, vertices->size()));cubeGeode->addDrawable(cubeGeometry);return cubeGeode;}////////////////////////////////////////////////////////////////////////////Method 2:Using MultiTexture to Render////TODO:使用MultiTexture的方式:// TODO: 未在OpenGL文档中查询到//glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);//glTexEnvf (GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_REPLACE);//不清楚是否是新的扩展,请读者指点//////////////////////////////////////////////////////////////////////////#if 0class MultiTextureUpdateCallback : public osg::Drawable::UpdateCallback{public:virtual void update(osg::NodeVisitor* nv, osg::Drawable* drawable){osg::Geometry *geometry = drawable->asGeometry();if (!geometry)return;osg::Vec2Array *textureArray = dynamic_cast<osg::Vec2Array*>(geometry->getTexCoordArray(1));if(textureArray)return;textureArray = new osg::Vec2Array;osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array*>(geometry->getVertexArray());osg::Vec3 lightPos(LightPosition[0], LightPosition[1], LightPosition[2]);osg::Matrix currentModelViewMatrix = computeLocalToWorld(nv->getNodePath()) * g_viewer->getCamera()->getViewMatrix();osg::Matrix currentInvModelViewerMatrix = osg::Matrix::inverse(currentModelViewMatrix);osg::Vec3 lightInObjectSpace = lightPos * currentInvModelViewerMatrix;//////////////////////////////////////////////////////////////////////////for (int i=0; i<4; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(1,0,0) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=4; i<8; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(-1, 0, 0) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=8; i<12; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(1, 0, 0) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,0,-1) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=12; i<16; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(0, -1, 0) * MaxEmboss;double deltaT = orientation * osg::Vec3(-1,0,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=16; i<20; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(0, 0, -1) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}for (int i=20; i<24; i++) {osg::Vec3 pos = vertices->at(i);osg::Vec3 orientation = lightInObjectSpace - pos;orientation.normalize();double deltaS = orientation * osg::Vec3(0, 0, 1) * MaxEmboss;double deltaT = orientation * osg::Vec3(0,1,0) * MaxEmboss;textureArray->push_back(osg::Vec2(data[5*i]+deltaS,data[5*i + 1]+deltaT));}geometry->setTexCoordArray(1, textureArray);geometry->getOrCreateStateSet()->setTextureAttributeAndModes(1, invbump[1]);osg::TexEnv *tex2Env = new osg::TexEnv(osg::TexEnv::ADD);geometry->getOrCreateStateSet()->setTextureAttributeAndModes(0, tex2Env);geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, false);}};#endifosg::Node*buildScene(){initTextures();osg::Group *root = new osg::Group;osg::MatrixTransform *zoomMT = new osg::MatrixTransform;zoomMT->setMatrix(osg::Matrix::translate(0.0, 0.0, -5.0));osg::MatrixTransform *rotateXAxis = new osg::MatrixTransform;rotateXAxis->setName("xRotMT");RotateCallback *xRotCallback = new RotateCallback(osg::X_AXIS, 0.0);rotateXAxis->setUpdateCallback(xRotCallback);zoomMT->addChild(rotateXAxis);osg::MatrixTransform *rotateYAxis = new osg::MatrixTransform;rotateYAxis->setName("yRotMT");RotateCallback *yRotCallback = new RotateCallback(osg::Y_AXIS, 0.0);rotateYAxis->setUpdateCallback(yRotCallback);rotateXAxis->addChild(rotateYAxis);osg::Switch *switchNode = new osg::Switch;g_switch = switchNode;rotateYAxis->addChild(switchNode);switchNode->addChild(createUpMappingCube());switchNode->addChild(createDownMappingCube());switchNode->addChild(createCube());root->addChild(zoomMT);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();}
- 用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教程 - 第十六课
- [递推dp] zoj 3747 Attack on Titans
- 今天五一劳动节,祝大家节日快乐!
- Monitor
- oracle的timestamp类型数据转换成yyyymmddhhmi24格式
- 安卓学习140501:组件——Activities与Intents
- 用OpenSceneGraph实现的NeHe OpenGL教程 - 第二十二课
- 算法的时间复杂度和空间复杂度(1)
- nyoj 298 点的变换
- Zstack之例程GenericApp分析笔记2
- VirtualBox的四种网络连接方式
- A + B Problem Too 2101
- Unix环境高级编程:1-2 基础知识、标准化
- connect-mongo使用简介
- UVA - 120 - Stacks of Flapjacks