zoukankan      html  css  js  c++  java
  • osg利用矩阵投影在平面上产生阴影

    效果:

      

    实现:

    PlaneShadowMatrix.h

    #include <osg/Matrix>
    #include <osg/Geode>
    class PlaneShadowMatrix {
    public:
        /************************************************************************/
        /* 功能:获取投影矩阵
           参数:vPoints[3] = 平面上不在一直线上的三个点,vLightPos = 光照的位置,destmat = 用来保存矩阵。
           作者:一梦
           时间:2018-11-14 11:37:39
           修订:无。
           修订时间:无。
        */
        /************************************************************************/
        void getShadowMatrix(osg::Vec3 vPoints[3], osg::Vec4 vLightPos, osg::Matrix &destMat);
    };

    PlaneShadowMatrix.cpp

    #include "PlaneShadowMatrix.h"
    void getPlaneEquation(osg::Vec3 &vPoint1, osg::Vec3 &vPoint2, osg::Vec3 &vPoint3, osg::Vec4 &vPlane);
    
    void getNormalVector(const osg::Vec3 &vP1, const osg::Vec3 &vP2, const osg::Vec3 &vP3, osg::Vec4 &vNormal);
    
    void subtractVectors(const osg::Vec3 &vFirst, const osg::Vec3 &vSecond, osg::Vec3 &vResult);
    
    void vectorCrossProduct(const osg::Vec3 &vU, const osg::Vec3 &vV, osg::Vec4 &vResult);
    
    void normalizeVector(osg::Vec4 &vNormal);
    
    float getVectorLength(const  osg::Vec4 &vVector);
    
    float getVectorLengthSqrd(const osg::Vec4 &vVector);
    
    void scaleVector(osg::Vec4 &vVector, const GLfloat fScale);
    
    void PlaneShadowMatrix::getShadowMatrix(osg::Vec3 vPoints[3], osg::Vec4 vLightPos, osg::Matrix &destMat){
        osg::Vec4 vPlaneEquation;
        float dot;
    
        getPlaneEquation(vPoints[0], vPoints[1], vPoints[2], vPlaneEquation);
    
        // Dot product of plane and light position
        dot =vPlaneEquation[0]*vLightPos[0] + 
            vPlaneEquation[1]*vLightPos[1] + 
            vPlaneEquation[2]*vLightPos[2] + 
            vPlaneEquation[3]*vLightPos[3];
    
        // Now do the projection
        // First column
        destMat(0,0) = dot - vLightPos[0] * vPlaneEquation[0];
        destMat(1,0) = 0.0f - vLightPos[0] * vPlaneEquation[1];
        destMat(2,0) = 0.0f - vLightPos[0] * vPlaneEquation[2];
        destMat(3,0) = 0.0f - vLightPos[0] * vPlaneEquation[3];
    
        // Second column
        destMat(0,1) = 0.0f - vLightPos[1] * vPlaneEquation[0];
        destMat(1,1) = dot - vLightPos[1] * vPlaneEquation[1];
        destMat(2,1) = 0.0f - vLightPos[1] * vPlaneEquation[2];
        destMat(3,1) = 0.0f - vLightPos[1] * vPlaneEquation[3];
    
        // Third Column
        destMat(0,2) = 0.0f - vLightPos[2] * vPlaneEquation[0];
        destMat(1,2) = 0.0f - vLightPos[2] * vPlaneEquation[1];
        destMat(2,2) = dot - vLightPos[2] * vPlaneEquation[2];
        destMat(3,2) = 0.0f - vLightPos[2] * vPlaneEquation[3];
    
        // Fourth Column
        destMat(0,3) = 0.0f - vLightPos[3] * vPlaneEquation[0];
        destMat(1,3) = 0.0f - vLightPos[3] * vPlaneEquation[1];
        destMat(2,3) = 0.0f - vLightPos[3] * vPlaneEquation[2];
        destMat(3,3) = dot - vLightPos[3] * vPlaneEquation[3];
        return ;
    }
    
    void getPlaneEquation(osg::Vec3 &vPoint1, osg::Vec3 &vPoint2, osg::Vec3 &vPoint3, osg::Vec4 &vPlane){
        // Get normal vector from three points. The normal vector is the first three coefficients
        // to the plane equation...
        getNormalVector(vPoint1, vPoint2, vPoint3, vPlane);
    
        // Final coefficient found by back substitution
        vPlane[3] = -(vPlane[0] * vPoint3[0] + vPlane[1] * vPoint3[1] + vPlane[2] * vPoint3[2]);
    }
    
    void getNormalVector(const osg::Vec3 &vP1, const osg::Vec3 &vP2, const osg::Vec3 &vP3, osg::Vec4 &vNormal){
        osg::Vec3 vV1, vV2;
    
        subtractVectors(vP2, vP1, vV1);
        subtractVectors(vP3, vP1, vV2);
    
        vectorCrossProduct(vV1, vV2, vNormal);
        normalizeVector(vNormal);
    }
    
    void subtractVectors(const osg::Vec3 &vFirst, const osg::Vec3 &vSecond, osg::Vec3 &vResult){
        vResult[0] = vFirst[0] - vSecond[0];
        vResult[1] = vFirst[1] - vSecond[1];
        vResult[2] = vFirst[2] - vSecond[2];
    }
    
    void vectorCrossProduct(const osg::Vec3 &vU, const osg::Vec3 &vV, osg::Vec4 &vResult){
        vResult[0] = vU[1]*vV[2] - vV[1]*vU[2];
        vResult[1] = -vU[0]*vV[2] + vV[0]*vU[2];
        vResult[2] = vU[0]*vV[1] - vV[0]*vU[1];
    }
    
    void normalizeVector(osg::Vec4 &vNormal){
        float fLength = 1.0f / getVectorLength(vNormal);
        scaleVector(vNormal, fLength); 
    }
    
    float getVectorLength(const  osg::Vec4 &vVector){
        return (GLfloat)sqrt(getVectorLengthSqrd(vVector)); 
    }
    
    float getVectorLengthSqrd(const osg::Vec4 &vVector){
        return (vVector[0]*vVector[0]) + (vVector[1]*vVector[1]) + (vVector[2]*vVector[2]); 
    }
    
    void scaleVector(osg::Vec4 &vVector, const GLfloat fScale){
        vVector[0] *= fScale; vVector[1] *= fScale; vVector[2] *= fScale; 
    }

    main.cpp

    #include <osg/Texture2D>
    #include <osg/Geometry>
    #include <osg/Geode>
    #include <osgDB/ReadFile>
    #include <osgUtil/SmoothingVisitor>
    #include <osgViewer/Viewer>
    #include <osg/PositionAttitudeTransform>
    #include <osg/MatrixTransform>
    #include <osgGA/TrackballManipulator>
    #include <osg/Material>
    
    #include "PlaneShadowMatrix.h"
    
    osg::Matrix shadowMarix;
    
    osg::Vec4 lightPos(30.0f,-10.0f,30.0f,1.0f);
    
    osg::Vec3 myarray[3];
    
    //物体回调函数,让其不断的旋转
    class RotateCallback : public osg::NodeCallback
    {
    public:
        RotateCallback() : _rotateZ(0.0) {}
    
        virtual void operator()( osg::Node* node, osg::NodeVisitor* nv )
        {
            osg::PositionAttitudeTransform* pat = dynamic_cast<osg::PositionAttitudeTransform*>( node );
            if ( pat )
            {
                osg::Quat quat( osg::DegreesToRadians(_rotateZ), osg::Z_AXIS );
                pat->setAttitude( quat );
                _rotateZ += 1.0;
            }
    
            
            traverse( node, nv );//访问器的下一个节点
        }
    
    protected:
        double _rotateZ;
    };
    //阴影回调函数,让其投影
    class ShadowCallback : public osg::NodeCallback
    {
    public:
            ShadowCallback() : rotateZ(0.0) {}
        virtual void operator()( osg::Node* node, osg::NodeVisitor* nv )
        {
            osg::MatrixTransform * mt = dynamic_cast<osg::MatrixTransform*>( node );
            if ( mt )
            {
                mt->setMatrix(shadowMarix);
            }
            traverse( node, nv );//访问器的下一个节点
        }
    protected:
        double rotateZ;
    };
    //创建灯光
    void createLight(osg::ref_ptr<osg::Group> lightRoot)
    {
        //lightRoot->addChild(node);
    
        //开启光照
        osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
        stateset = lightRoot->getOrCreateStateSet();
        stateset->setMode(GL_LIGHTING,osg::StateAttribute::ON);
        stateset->setMode(GL_LIGHT0,osg::StateAttribute::ON);
    
        //创建一个Light对象
        osg::ref_ptr<osg::Light> light = new osg::Light();
        light->setLightNum(0);
        //设置方向
        light->setDirection(osg::Vec3(1.0f,1.0f,-1.0f));
        //设置位置
        light->setPosition(lightPos);
        //设置环境光的颜色
        light->setAmbient(osg::Vec4(0.01f,0.01f,0.01f,1.0f));
        //设置散射光的颜色
        light->setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
    
         ////设置恒衰减指数
         //light->setConstantAttenuation(1.0f);
         ////设置线形衰减指数
         //light->setLinearAttenuation(0.0f);
         ////设置二次方衰减指数
         //light->setQuadraticAttenuation(0.0f);
    
        //创建光源
        osg::ref_ptr<osg::LightSource> lightSource = new osg::LightSource();
        lightSource->setLight(light.get());
    
        lightRoot->addChild(lightSource.get());
    
        return ;
    }
    //创建墙壁
    osg::Drawable* createHouseWall()
    {
        // House vertices
        osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
        //前面
        vertices->push_back( osg::Vec3( 0.0, 0.0, 4.0) );  // 0
        vertices->push_back( osg::Vec3( 0.0, 0.0, 0.0) );  // 1
        vertices->push_back( osg::Vec3( 4.0, 0.0, 4.0) );  // 2
        vertices->push_back( osg::Vec3( 4.0, 0.0, 0.0) );  // 3
        //右面
        vertices->push_back( osg::Vec3( 4.0, 4.0, 4.0) );  // 4
        vertices->push_back( osg::Vec3( 4.0, 4.0, 0.0) );  // 5
        //后面
        vertices->push_back( osg::Vec3( 0.0, 4.0, 4.0) );  // 6
        vertices->push_back( osg::Vec3( 0.0, 4.0, 0.0) );  // 7
        //左面
        vertices->push_back( osg::Vec3( 0.0, 0.0, 4.0) );  // 8
        vertices->push_back( osg::Vec3( 0.0, 0.0, 0.0) );  // 9
        
        // House normals
        osg::ref_ptr<osg::Vec3Array> normals = new osg::Vec3Array( 10 );
        //左前
        (*normals)[0].set(-1.0,-1.0, 0.0 );
        (*normals)[1].set(-1.0,-1.0, 0.0 );
        //右前
        (*normals)[2].set( 1.0,-1.0, 0.0 );
        (*normals)[3].set( 1.0,-1.0, 0.0 );
        //右后
        (*normals)[4].set( 1.0, 1.0, 0.0 );
        (*normals)[5].set( 1.0, 1.0, 0.0 );
        //左后
        (*normals)[6].set(-1.0, 1.0, 0.0 );
        (*normals)[7].set(-1.0, 1.0, 0.0 );
        //左前
        (*normals)[8].set(-1.0,-1.0, 0.0 );
        (*normals)[9].set(-1.0,-1.0, 0.0 );
        
        // House texture coordinates
        osg::ref_ptr<osg::Vec2Array> texcoords = new osg::Vec2Array( 10 );
        //前面的左0.3
        (*texcoords)[0].set( 0.0, 1.0 );
        (*texcoords)[1].set( 0.0, 0.0 );
        (*texcoords)[2].set( 1.0, 1.0 );
        (*texcoords)[3].set( 1.0, 0.0 );
    
        //右面0.2
           (*texcoords)[4].set( 0.0, 1.0 );
        (*texcoords)[5].set( 0.0, 0.0 );
    
        //后面0.3
        (*texcoords)[6].set( 1.0, 1.0 );
        (*texcoords)[7].set( 1.0, 0.0 );
        //左边0.2
        (*texcoords)[8].set( 0.0, 1.0 );
        (*texcoords)[9].set( 0.0, 0.0 );
    
        // House texture coordinates
        /*osg::ref_ptr<osg::Vec2Array> texcoords2 = new osg::Vec2Array( 10 );
    
    
          //右面0.2
    
        (*texcoords2)[4].set( 0.0, 1.0 );
        (*texcoords2)[5].set( 0.0, 0.0 );
        
    
        //后面0.3
        (*texcoords2)[6].set( 1.0, 1.0 );
        (*texcoords2)[7].set( 1.0, 0.0 );
        //左边0.2
        (*texcoords2)[8].set( 0.0, 1.0 );
        (*texcoords2)[9].set( 0.0, 0.0 );*/
    
        
        // Create wall geometry
        osg::ref_ptr<osg::Geometry> houseWall = new osg::Geometry;
        houseWall->setVertexArray( vertices.get() );
        houseWall->setTexCoordArray( 0, texcoords.get() );
        // houseWall->setTexCoordArray( 1, texcoords2.get() );
        houseWall->setNormalArray( normals.get() );
        houseWall->setNormalBinding( osg::Geometry::BIND_PER_VERTEX );
        houseWall->addPrimitiveSet( new osg::DrawArrays(osg::DrawArrays::QUAD_STRIP, 0, 10) );
        
        houseWall->getOrCreateStateSet()->setTextureAttributeAndModes( 0,new osg::Texture2D(osgDB::readImageFile("C:\55.jpg")) );
    
        // houseWall->getOrCreateStateSet()->setTextureAttributeAndModes( 1,new osg::Texture2D(osgDB::readImageFile("C:\55.jpg")) );
    
        return houseWall.release();
    } 
    //创建大地
    osg::Geometry* createGround(){
    
        osg::ref_ptr<osg::Vec3Array> vertices = new osg::Vec3Array;
        vertices->push_back(osg::Vec3(50,-50,-10));
        vertices->push_back(osg::Vec3(50,50,-5));
        vertices->push_back(osg::Vec3(-50,50,-5));
        vertices->push_back(osg::Vec3(-50,-50,-10));
    
        myarray[0] = osg::Vec3(50,-50,-9);
        myarray[1] = osg::Vec3(50,50,-4);
        myarray[2] = osg::Vec3(-50,50,-4);
    
        osg::ref_ptr<osg::Vec3Array> colours = new osg::Vec3Array;
        colours->push_back(osg::Vec3(255,255,0));
        colours->push_back(osg::Vec3(0,255,0));
        colours->push_back(osg::Vec3(0,255,0));
        colours->push_back(osg::Vec3(0,255,0));
    
    
        osg::Geometry *ground = new osg::Geometry;
        ground->setVertexArray(vertices);
        ground->addPrimitiveSet(new osg::DrawArrays(osg::DrawArrays::QUADS,0,4));
        ground->setColorArray(colours,osg::Array::BIND_PER_PRIMITIVE_SET);
        return ground;
    
    }
    
    int main( int argc, char** argv )
    {
        
        osg::Group *root = new osg::Group;
    
        //物体
        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
        geode->addDrawable( createHouseWall() );
    
        //影子
        osg::ref_ptr<osg::Geode> shadowGeode = new osg::Geode;
        shadowGeode->addDrawable( createHouseWall() );
    
        //旋转物体
        osg::ref_ptr<osg::PositionAttitudeTransform> pat = new osg::PositionAttitudeTransform;
        pat->addChild( geode );
        pat->setUpdateCallback( new RotateCallback );
    
        //旋转影子
        osg::ref_ptr<osg::PositionAttitudeTransform> shaDowPat = new osg::PositionAttitudeTransform;
        shaDowPat->addChild( shadowGeode );
        shaDowPat->setUpdateCallback( new RotateCallback );
    
        //投影
        osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform;
        mt->addChild( shaDowPat );
        mt->setUpdateCallback( new ShadowCallback );
        //mt->getOrCreateStateSet()->setMode(GL_DEPTH_TEST,osg::StateAttribute::OFF);
        mt->getOrCreateStateSet()->setMode(GL_LIGHTING,osg::StateAttribute::OFF);
        osg::Material *mm = new osg::Material;
        mm->setAmbient(osg::Material::Face::FRONT,osg::Vec4(0.0,0.0,0.0,1.0));
        mm->setDiffuse(osg::Material::Face::FRONT,osg::Vec4(0.0,0.0,0.0,1.0));
        mm->setSpecular(osg::Material::Face::FRONT,osg::Vec4(0.0,0.0,0.0,1.0));
        mt->getOrCreateStateSet()->setAttribute(mm);
    
    
        root->addChild(mt);
    
    
        root->addChild(pat);
        
    
        osg::ref_ptr<osg::Group> lightRoot = new osg::Group;
        createLight(lightRoot);
        root->addChild(lightRoot.get());
        root->addChild(createGround());
    
        osgViewer::Viewer viewer;
        viewer.setUpViewInWindow(20,20,400,400);
        viewer.setSceneData(root);
        viewer.setCameraManipulator(new osgGA::TrackballManipulator);
    
        PlaneShadowMatrix psm;
        psm.getShadowMatrix(myarray,lightPos,shadowMarix);
        //makeShadowMatrix(myarray,lightPos,shadowMarix);
    /*
        while (!viewer.done()){
            viewer.frame();
        }
        return 1; */
        return viewer.run();
    
        
    }

    总结:得到的矩阵与当前矩阵相乘,就是投影。

  • 相关阅读:
    Java DB 访问(三)mybatis mapper interface接口
    android stdio 安装后gradle 编译失败,设置代理不管用
    超星自动签到并邮件通知
    关于解决Mac使用docker安装SQL server for Linux 中文乱码问题
    Bom简单介绍
    grid-layout
    Position
    前端学习(注册表)
    关于学精通一门语言的个人看法(欢迎留言补充)
    Google 最新推出数据集搜索
  • 原文地址:https://www.cnblogs.com/airduce/p/9957252.html
Copyright © 2011-2022 走看看