OSG八面体切分球

**

OSG八面体切分球

                                                 ----南师大一码农

**
///
/应老师要求,对八面体进行切分,即对每个正三角形进行切分,切分三次之后,将每个三角形的顶点坐标投影到球心坐标,绘制成球,并实现放大缩小拖放等功能。/
///
///实现步骤:
/*

  1. 绘制八面体,采用(0,0,1),(1,0,0),(0,1,0),(-1,0,0),(0,-1,0),(0,0,-1)五个点绘制,当然刚开始有人尝试使用TRIANGLE_STRIP实现,亲测迷花眼,遂调用显示列表实现,建立一个显示列表,绘制每一个正三角形,在主函数中调用八次,参数为向量(存储每个点的的坐标),函数返回值为组结点
  2. 主函数中生成位置变换节点,将八面体进行移位。
  3. 新生成一个显示列表,采用递归的思想,核心思想为求得每个拆分点的坐标,比那个将其转化为单位向量,即求得它在球心坐标的投影,再调用Triangle函数绘制三角形。
    4.主函数调用生成
    */
    ///

///
/源代码/
///

#include <iostream>

#include <osgViewer/Viewer>

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

#include<osg/Node>
#include<osg/Geode>
#include<osg/Group>

#include<osgUtil/Optimizer>

#include<math.h>

#include<osgGA/StateSetManipulator>
#include<osg/PositionAttitudeTransform>


//将八面体的顶点信息设为全局变量
osg::Vec3 vz1 = osg::Vec3(0.0f, 0.0f, 1.0f);//Z+
osg::Vec3 vx1 = osg::Vec3(1.0f, 0.0f, 0.0f);//X+
osg::Vec3 vy1 = osg::Vec3(0.0f, 1.0f, 0.0f);//Y+
osg::Vec3 vx0 = osg::Vec3(-1.0f, 0.0f, 0.0f);//X-
osg::Vec3 vy0 = osg::Vec3(0.0f, -1.0f, 0.0f);//Y-
osg::Vec3 vz0 = osg::Vec3(0.0f, 0.0f, -1.0f);//Z-

osg::ref_ptr<osg::Node> Triangle(osg::Vec3 v1, osg::Vec3 v2, osg::Vec3 v3)
{
    osg::ref_ptr<osg::Geode>geode = new osg::Geode();
    osg::ref_ptr<osg::Geometry>geom = new osg::Geometry();
    osg::ref_ptr<osg::Vec3Array>v = new osg::Vec3Array();
    v1.normalize();
    v2.normalize();
    v3.normalize();
    v->push_back(v1);
    v->push_back(v2);
    v->push_back(v3);
    geom->setVertexArray(v.get());
    geom->setNormalArray(v.get());
    geom->setNormalBinding(osg::Geometry::BIND_OVERALL);
    //添加图元,绘图基元为三角形,即解析顶点数据,PrimitiveSet是虚基类,需要DrawArrays来实现数据渲染
    geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, v->size()));
    //将Geometry对象添加到叶节点,并作为显示列表的返回值返回
    geode->addDrawable(geom.get());
    return geode.get();
}

osg::ref_ptr<osg::Node>DOhTOBall(float v1x, float v1y, float v1z, float v2x, float v2y, float v2z, float v3x, float v3y, float v3z, osg::Vec3 v1, osg::Vec3 v2, osg::Vec3 v3,int num)
{

    if (num == 1)
    {
        osg::ref_ptr<osg::Group> node = new osg::Group;
        //得到两个顶点中间的切分点坐标
        float Ax = (v1x + v2x) / 2;
        float Ay = (v1y + v2y) / 2;
        float Az = (v1z + v2z) / 2;
        //求得A点的单位向量,即其为A点投影到球心坐标系的坐标
        float x = 1.0f / sqrt(Ax*Ax + Ay * Ay + Az * Az);
        Ax *= x;
        Ay *= x;
        Az *= x;

        float Bx = (v1x + v3x) / 2;
        float By = (v1y + v3y) / 2;
        float Bz = (v1z + v3z) / 2;
        x = 1.0f / sqrt(Bx*Bx + By * By + Bz * Bz);
        Bx *= x;
        By *= x;
        Bz *= x;
        float Cx = (v2x + v3x) / 2;
        float Cy = (v2y + v3y) / 2;
        float Cz = (v2z + v3z) / 2;
        x = 1 / sqrt(Cx*Cx + Cy * Cy + Cz * Cz);
        Cx *= x;
        Cy *= x;
        Cz *= x;
        osg::Vec3 vA = osg::Vec3(Ax, Ay, Az);
        osg::Vec3 vB = osg::Vec3(Bx, By, Bz);
        osg::Vec3 vC = osg::Vec3(Cx, Cy, Cz);

        node->addChild(Triangle(v1,vA,vB));
        node->addChild(Triangle(vA,v2,vC));
        node->addChild(Triangle(vA,vB,vC));
        node->addChild(Triangle(vB,vC,v3));
        return node.get();
    }
    else
    {
        osg::ref_ptr<osg::Group> node = new osg::Group;
        //得到两个顶点中间的切分点坐标
        float Ax = (v1x + v2x) / 2;
        float Ay = (v1y + v2y) / 2;
        float Az = (v1z + v2z) / 2;
        //求得A点的单位向量,即其为A点投影到球心坐标系的坐标
        float x = 1.0f / sqrt(Ax*Ax + Ay * Ay + Az * Az);
        Ax *= x;
        Ay *= x;
        Az *= x;

        float Bx = (v1x + v3x) / 2;
        float By = (v1y + v3y) / 2;
        float Bz = (v1z + v3z) / 2;
        x = 1.0f / sqrt(Bx*Bx + By * By + Bz * Bz);
        Bx *= x;
        By *= x;
        Bz *= x;
        float Cx = (v2x + v3x) / 2;
        float Cy = (v2y + v3y) / 2;
        float Cz = (v2z + v3z) / 2;
        x = 1 / sqrt(Cx*Cx + Cy * Cy + Cz * Cz);
        Cx *= x;
        Cy *= x;
        Cz *= x;
        osg::Vec3 vA = osg::Vec3(Ax, Ay, Az);
        osg::Vec3 vB = osg::Vec3(Bx, By, Bz);
        osg::Vec3 vC = osg::Vec3(Cx, Cy, Cz);


        node->addChild(DOhTOBall(v1x,v1y,v1z,Ax,Ay,Az,Bx,By,Bz,v1,vA,vB,num-1));
        node->addChild(DOhTOBall(Ax, Ay, Az,v2x,v2y,v2z, Cx, Cy, Cz, vA, v2, vC, num - 1));
        node->addChild(DOhTOBall( Ax, Ay, Az, Bx, By, Bz, Cx, Cy, Cz,  vA, vB,vC, num - 1));
        node->addChild(DOhTOBall( Bx, By, Bz, Cx, Cy, Cz, v3x,v3y,v3z,vB, vC, v3, num - 1));
        return node.get();
    }
}
int main(int argc, char** argv)
{
    osg::ref_ptr<osgViewer::Viewer>viewer = new osgViewer::Viewer();
    //转化为网格模式,记住按W键
    viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));

    osg::ref_ptr<osg::Group> root = new osg::Group();
    //必须使用组结点
    osg::ref_ptr<osg::Group> geode = new osg::Group();
    int num = 3;//标志切分的次数
    //绘制八面体
    geode->addChild(Triangle(vz1,vy1,vx1));//z+,y+,x+
    geode->addChild(Triangle(vz1,vy1,vx0));//z+,y+,x-
    geode->addChild(Triangle(vz1,vy0,vx0));//z+,y-,x-
    geode->addChild(Triangle(vz1,vy0,vx1));//z+,y-,x+
    geode->addChild(Triangle(vz0,vy1,vx1));//z-,y+,x+
    geode->addChild(Triangle(vz0, vy1, vx0));//z-,y+,x-
    geode->addChild(Triangle(vz0, vy0, vx0));//z-,y-,x-
    geode->addChild(Triangle(vz0, vy0, vx1));//z-,y-,x+
    //设置位置变换节点
    osg::ref_ptr<osg::PositionAttitudeTransform>part = new osg::PositionAttitudeTransform();
    part->setPosition(osg::Vec3(-10.0f, 0.0f, 0.0f));
    part->addChild(geode.get());
    root->addChild(part.get());

    //绘制切分球
    root->addChild(DOhTOBall(0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, vz1, vy1, vx1,num));//z+,y+,x+
    root->addChild(DOhTOBall(0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, vz1, vy1, vx0,num));//z+,y+,x-
    root->addChild(DOhTOBall(0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, vz1, vy0, vx0,num));//z+,y-,x-
    root->addChild(DOhTOBall(0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, vz1, vy0, vx1,num));//z+,y-,x+
    root->addChild(DOhTOBall(0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, vz0, vy1, vx1,num));//z-,y+,x+
    root->addChild(DOhTOBall(0.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f, 0.0f, vz0, vy1, vx0,num));//z-,y+,x-
    root->addChild(DOhTOBall(0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 0.0f, vz0, vy0, vx0,num));//z-,y-,x-
    root->addChild(DOhTOBall(0.0f, 0.0f, -1.0f, 0.0f, -1.0f, 0.0f, 1.0f, 0.0f, 0.0f, vz0, vy0, vx1,num));//z-,y-,x+


    osgUtil::Optimizer optimizer;
    optimizer.optimize(root.get());//注意这边是.optimize

    viewer->setSceneData(root.get());
    viewer->realize();
    viewer->run();
    return 0;
}

///
/成果展示/
///
无法实现截图,求大神告知方法。初学者,作为一次记录,不喜勿喷。但欢迎指正,互相学习!----------南师大地科院小码农


猜你喜欢

转载自blog.csdn.net/weixin_39697067/article/details/81773701