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();
    
        
    }

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

  • 相关阅读:
    547. Friend Circles
    399. Evaluate Division
    684. Redundant Connection
    327. Count of Range Sum
    LeetCode 130 被围绕的区域
    LeetCode 696 计数二进制子串
    LeetCode 116 填充每个节点的下一个右侧节点
    LeetCode 101 对称二叉树
    LeetCode 111 二叉树最小深度
    LeetCode 59 螺旋矩阵II
  • 原文地址:https://www.cnblogs.com/airduce/p/9957252.html
Copyright © 2011-2022 走看看