**
OSG八面体切分球
----南师大一码农
**
///
/应老师要求,对八面体进行切分,即对每个正三角形进行切分,切分三次之后,将每个三角形的顶点坐标投影到球心坐标,绘制成球,并实现放大缩小拖放等功能。/
///
///实现步骤:
/*
- 绘制八面体,采用(0,0,1),(1,0,0),(0,1,0),(-1,0,0),(0,-1,0),(0,0,-1)五个点绘制,当然刚开始有人尝试使用TRIANGLE_STRIP实现,亲测迷花眼,遂调用显示列表实现,建立一个显示列表,绘制每一个正三角形,在主函数中调用八次,参数为向量(存储每个点的的坐标),函数返回值为组结点
- 主函数中生成位置变换节点,将八面体进行移位。
- 新生成一个显示列表,采用递归的思想,核心思想为求得每个拆分点的坐标,比那个将其转化为单位向量,即求得它在球心坐标的投影,再调用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;
}
///
/成果展示/
///