查看: 1948|回复: 1

天空盒例子中纹理矩阵的设置

[复制链接]

该用户从未签到

发表于 2015-3-8 10:10:00 | 显示全部楼层 |阅读模式
     肖鹏的编程指南的例子中天空盒的例子,在回调函数中为什么将纹理矩阵设置成模型视图矩阵的逆矩阵,为什么是逆矩阵呢


/**********************************************************
*Write by FlySky
*zzuxp@163.com  http://www.OsgChina.org   
**********************************************************/

#include <osgViewer/Viewer>

#include <osg/Vec3>
#include <osg/Vec4>
#include <osg/Quat>
#include <osg/Matrix>
#include <osg/ShapeDrawable>
#include <osg/Geometry>
#include <osg/Geode>
#include <osg/Transform>
#include <osg/Material>
#include <osg/NodeCallback>
#include <osg/Depth>
#include <osg/CullFace>
#include <osg/TexMat>
#include <osg/TexGen>
#include <osg/TexEnv>
#include <osg/TextureCubeMap>

#include <osgDB/WriteFile>
#include <osgDB/ReadFile>

#include <osgUtil/Optimizer>
#include <osgGA/FirstPersonManipulator>

#include <iostream>

//读取立方图
osg::ref_ptr<osg::TextureCubeMap> readCubeMap()
{
        osg::ref_ptr<osg::TextureCubeMap> cubemap = new osg::TextureCubeMap;

        osg::ref_ptr<osg::Image> imagePosX = osgDB::readImageFile("right.jpg");
        osg::ref_ptr<osg::Image> imageNegX = osgDB::readImageFile("left.jpg");
        osg::ref_ptr<osg::Image> imagePosY = osgDB::readImageFile("front.jpg");
        osg::ref_ptr<osg::Image> imageNegY = osgDB::readImageFile("back.jpg");
        osg::ref_ptr<osg::Image> imagePosZ = osgDB::readImageFile("up.jpg");
        osg::ref_ptr<osg::Image> imageNegZ = osgDB::readImageFile("down.jpg");

        if (imagePosX.get() && imageNegX.get() && imagePosY.get() && imageNegY.get() && imagePosZ.get() && imageNegZ.get())
        {
                //设置立方图的六个面的贴图
                cubemap->setImage(osg::TextureCubeMap:OSITIVE_X, imagePosX.get());
                cubemap->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX.get());
                cubemap->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY.get());
                cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY.get());
                cubemap->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ.get());
                cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ.get());

                //设置纹理环绕模式
                cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
                cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
                cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);

                //设置滤波:线形和mipmap
                cubemap->setFilter(osg::Texture::MIN_FILTER, osg::Texture:INEAR_MIPMAP_LINEAR);
                cubemap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
        }

        return cubemap.get();
}

//更新立方体图纹理
struct TexMatCallback : public osg::NodeCallback
{
public:

        TexMatCallback(osg::TexMat& tm) :
          _texMat(tm)
          {
                  //
          }

          virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
          {
                  osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
                  if (cv)
                  {
                          //得到模型视图矩阵并设置旋转角度
                          const osg::Matrix& MV = *(cv->getModelViewMatrix());
                          const osg::Matrix R = osg::Matrix::rotate( osg:egreesToRadians(112.0f), 0.0f,0.0f,1.0f)*
                                  osg::Matrix::rotate( osg::DegreesToRadians(90.0f), 1.0f,0.0f,0.0f);

                          osg:uat q = MV.getRotate();
                          const osg::Matrix C = osg::Matrix::rotate( q.inverse() );

                          //设置纹理矩阵
                          _texMat.setMatrix( C*R);

                  }

                  traverse(node,nv);
          }

          //纹理矩阵
          osg::TexMat& _texMat;
};

//一个变换类,使天空盒绕视点旋转
class MoveEarthySkyWithEyePointTransform : public osg::Transform
{
public:
        //局部矩阵计算成世界矩阵
        virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
        {
                osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
                if (cv)
                {
                        osg::Vec3 eyePointLocal = cv->getEyeLocal();
                        matrix.preMult(osg::Matrix::translate(eyePointLocal));
                }
                return true;
        }

        //世界矩阵计算为局部矩阵
        virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
        {
                osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
                if (cv)
                {
                        osg::Vec3 eyePointLocal = cv->getEyeLocal();
                        matrix.postMult(osg::Matrix::translate(-eyePointLocal));
                }
                return true;
        }
};

//创建天空盒
osg::ref_ptr<osg::Node> createSkyBox(osg::Vec3&center,double radious)
{
        osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();

        //设置纹理映射方式,指定为替代方式,即纹理中的颜色代替原来的颜色
        osg::ref_ptr<osg::TexEnv> te = new osg::TexEnv;
        te->setMode(osg::TexEnv::REPLACE);
        stateset->setTextureAttributeAndModes(0, te.get(), osg::StateAttribute::ON| osg::StateAttribute::OVERRIDE);

        //自动生成纹理坐标,反射方式(REFLECTION_MAP)
        /*
        NORMAL_MAP 标准模式-立方图纹理
        REFLECTION_MAP 反射模式-球体纹理
        SPHERE_MAP 球体模型-球体纹理
        */
        osg::ref_ptr<osg::TexGen> tg = new osg::TexGen;
        tg->setMode(osg::TexGen::NORMAL_MAP);
        stateset->setTextureAttributeAndModes(0, tg.get(), osg::StateAttribute::ON| osg::StateAttribute::OVERRIDE);

        //设置纹理矩阵
        osg::ref_ptr<osg::TexMat> tm = new osg::TexMat;
        stateset->setTextureAttribute(0, tm.get());

        //设置立方图纹理
        osg::ref_ptr<osg::TextureCubeMap> skymap = readCubeMap();
        stateset->setTextureAttributeAndModes(0, skymap.get(), osg::StateAttribute::ON| osg::StateAttribute::OVERRIDE);

        stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
        stateset->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );

        //将深度设置为远平面
        osg::ref_ptr<osg::Depth> depth = new osg::Depth;
        depth->setFunction(osg::Depth::ALWAYS);
        depth->setRange(1.0,1.0);//远平面   
        stateset->setAttributeAndModes(depth, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);

        //设置渲染顺序为-1,先渲染
        stateset->setRenderBinDetails(-1,"RenderBin");

        osg::ref_ptr<osg::Drawable> drawable = new osg::ShapeDrawable(new osg::Sphere(center,radious));

        //把球体加入到叶节点
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        geode->setCullingActive(false);
        geode->setStateSet( stateset.get());
        geode->addDrawable(drawable.get());

        //设置变换
        osg::ref_ptr<osg::Transform> transform = new MoveEarthySkyWithEyePointTransform();
        transform->setCullingActive(false);
        transform->addChild(geode.get());

        osg::ref_ptr<osg::ClearNode> clearNode = new osg::ClearNode;
        clearNode->setCullCallback(new TexMatCallback(*tm));
        clearNode->addChild(transform.get());

        return clearNode.get();
}

int main()
{
        osg::ref_ptr<osgViewer::Viewer> viewer= new osgViewer::Viewer();

        osg::ref_ptr<osg::Group> rootnode = new osg::Group();

        //加入天空盒
       
        osg::ref_ptr<osg::Node>node1=osgDB::readNodeFile("skyplane.ive");
        rootnode->addChild(node1);
        osg::BoundingSphere bs=node1->getBound();
        osg::Vec3 &center=bs.center();
        double rad=bs.radius();

        rootnode->addChild(createSkyBox(center,rad));;

        //优化场景数据
        osgUtil::Optimizer optimzer;
        optimzer.optimize(rootnode.get());

        viewer->setSceneData(rootnode.get());
        viewer->setCameraManipulator(new osgGA::FirstPersonManipulator);
        viewer->realize();

        viewer->run();

        return 0 ;
}
QQ截图20150308100756.bmp

该用户从未签到

发表于 2015-5-15 20:32:23 | 显示全部楼层
我也有同样的疑惑,你现在清楚了么,如果清楚,还请赐教,不胜感激!
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表