一、
OpenSG
中的基本数学类型
1、
基本数据类型(Datatypes)
为了开发跨平台的程序,OpenSG定义自己的基本数据类型
1
、整型
[U]intN: N = {8,16,32,64}
U : unsigned
无符号整型
2
、浮点型
RealN N= {32
,64,128}
二、OpenGL中的结构类型
1
、向量(数组)
1
、向量的定义
Vec N {b,ub, s,us,f,d,ld}
b is Int8
ub is UInt8
s is Int16
us is UInt16
f is Real32
d is Real64
ld is Real128
2
、向量的使用
向量的定义:Vec3f v = Vec3f{0.1,2,3}
获取向量的模(向量二犯数):
Real32 l = v.length()
或者 float l = v.length()
获取向量值的平方根:v.squareLength()
向量规格化:v.normalize()
向量的叉乘:v.cross(w)
向量的点乘:v.dot(w)
获取向量的单个元素:Real32 c1 = v[0]
向量的加法:Vec3f s = v + s
向量的相等比较:if(v==w)
2、
点(points)
点与向量类似,定义和计算方法均大体相同,只是点被赋予了特出意
义。而向量没有被赋予特出含义。
注意:点没有点乘和规格化。
1、
点的定义
Pnt3f p = Pnt3f(1,2,3)
2、
点的运算
点转换为向量:v = p.subZero()
向量转换为点:p = v.addToZero()
3、
颜色(Color)
颜色是三维或着四维向量。
颜色的定义:Color3f c = Color3f{0.5,0.5,1.0}
颜色的意义:三维颜色中的元素依次代表RGB的值,四维颜色中的
元素依次代表RGBA。其中A代表透明度(alpha)
4、
矩阵
1、
矩阵的初始化
方法一:用全部数据初始化,以行为顺序
Matrix m ;
m = Matrix(1,0,0,0,0,2,0,2,0,0,1,3,0,0,0,1)
方法二:用向量初始化,以列为顺序
Matrix m ;
Vec4f v1 = (1,0,0,0)
Vec4f v2 = (0,2,0,0)
Vec4f v3 = (0,0,1,0)
Vec4f v4 = (2,2,3,1)
m = Matrix(v1,v2,v3,v4)
2、
矩阵的运算
设置矩阵为单位矩阵I:m.setIdentity()
设置矩阵比例因子:m.setScale(1,2,1)
设置矩阵转换因子:m.setTranslate(2,2,3)
矩阵与向量乘:
Vec3f a = Vec3f(1,2,3) ;
Vec3f result ;
m.mult(a,result) ;
5
、四元组(Quaternions)
四元组为解决坐标旋转问题而专门设置,其参数由一个向量和一个角度或弧度组成。
1
、四元组的定义:Quaternion q;
2
、四元组的使用:
Quaternion q;
Matrix m;
m.setIdentity();
q = Quaternion(Vec3f(0,1,0),(30+t/180)*pi); //
使用弧度计算
q.setValueAsAxisDeg(Vec3f(0,1,0),90); //
使用角度计算
m.setRotation(q); //
矩阵以四元组q为基准旋转
注:当定义一个矩阵时,用setIdentity()将其设置为单位矩阵是很好
的编成习惯,如同在c/c++中在定义变量时首先初始化一样。
三、结点与核心(Nodes and Core)
1
、结点(Nodes)
注:在OpenSG中节点只用于表示层次关系,OpenSG中的所有图形、图
像都是有节点构成的整体,是一个有节点构成的树形结构。节点由节点数据部分和指向子节点的指针组成,该数据部分的数据类型师核心(core)类型,通过setCore()可以设置节点的数据字段,通过setChild()来设置指向子节点的指针字段,但节点的指向子节点的指针可以有多个。也可以理解为节点是结构树中的节点,而core就是节点中的数据字段,节点可以添加子节点,就如同数据结构中在树中添加子节点一样。
1
、Nodes的定义
NodePtr grandpa = Node::create();
NodePtr aunt = Node::create();
NodePtr mother = Node::create();
NodePtr me = Node::create()
;
注1:在OpenSG中我们定义变量多用静态函数create()创建,其返回类型为objectPtr,而不是直接创建,但是对于以上所讲的基本数学类型和基本结构类型可直接创建。
注2:一个objectPtr只能指向一个object,与c/c++中的指针不同,不能够指向数组。但能够使用数组指针来指向数组。
注3:当使用objectPtr是最好先判断一下该指针是否为空,就如同在c/c++中一样,我们操作一个指向不确定地址的指针是很危险的,我们可以将其与NullFC比较,不可以与NULL比较。
2
、Nodes的操作
添加子节点:
beginEditCP(mother);
mother->addChild(me);
endEditCP(mother);
删除子节点:
beginEditCP(mother);
mother->subChild(me);
endEditCP(mother);
设置转换核心:tranNode.setCore(transCore);
给节点命名:setName(mother,”mother”);
获取节点的名字:getName(mother);
获取节点的最小包围立方体:n->getValume(true/false)
3、
OpenSG
中的指针处理机制
在c/c++中由程序员自己控制指针的申请(new)与释放(delete)在 java中提出垃圾回收机制,当系统空闲时执行垃圾回收进程,回收程序中已经没用的指针(确切讲是内存,在java中没有指针的概念),对于c/c++机制来讲速度快,但非常复杂,在OpenSG中有大量的指针,并且相互关联,给指针的控制带来难度,但OpenSG是用于处理图形的在某方面讲需要速度,但java的垃圾回收机制速度慢,也不适合于OpenSG,OpenSG自己提供了一套指针管理机制,给每个指针定义一个引用数,当引用数变为零时,系统回收该指针,此时该指针变为不可用指针。此种做法有些类似于unix
中的文件的引用数,当该文件的引用数减到零时,该文件被彻底删除。
例如:一下程序可以编译,但不能执行,即会出现运行时错误。
Node a = Node::create();
Node b = Node::create();
Node c = Node::create();
// we add "a" as a child to "b"
beginEditCP(b);
b->addChild(a);
endEditCP(b);
//no, we want "a" to be a child of "c"
beginEditCP(b);
// this removes "a" as a child of "b"
b->subChild(a); //
当此句之行完毕时a被释放
endEditCP(b);
//and now add it to "c"
beginEditCP(c);
c->addChild(a);
endeditCP(c);
该程序应该做如下更改:
NodePtr a = Node::create();
NodePtr b = Node::create();
NodePtr c = Node::create();
// all reference counts of a,b and c are 0
// we add "a" as a child to "b"
beginEditCP(b);
b->addChild(a);
// "a" now has a reference count of 1,
// because adding it as a child increases
// the count by one
endEditCP(b);
//no, we want "a" to be a child of "c"
beginEditCP(b);
// first we increase the reference count
addRefCP(a); //
增加引用数
// reference count of "a" is now 2
// this removes "a" as a child of "b"
b->subChild(a);
// reference count is now 1 again
endEditCP(b);
//and now add it to "c"
beginEditCP(c);
c->addChild(a);
// and the reference count is now 2
// to avoid problems we decrease the count by hand
subRefCP(a); //
减少引用数
// and now the count is 1 as it should be
endeditCP(c);
利用RefPtr实现Ptr引用数的自动管理:
PefPtr
是一种特殊指针,能够自动的增加和减少指针的引用数。
#include <OpenSG/OSGRefPtr.h>
void moveNode(NodePtr parent, NodePtr newparent, int childnum)
{
RefPtr<NodePtr> c = parent->getChild(childnum); // refcount++, to make sure it survives
beginEditCP(parent);
parent->subChild(c); // refcount--, but the RefPtr keeps it safe
endEditCP(parent);
beginEditCP(newparent);
newparent->addChild(c);
endEditCP(newparent);
} // refcount--, as the RefPtr is destroyed
RefPtr<NodePtr> a = Node::create(); // we use this Node, keep it alive
beginEditCP(a);
a->addChild(Node::create()); // the new nodes refcount is now 1
endEditCP(a);
RefPtr<NodePtr> b = Node::create(); // keep this alive, too
moveNode(a, b, 0);
// a has no children now, b has one
5、
OpenSG
中的最小包围立方体
最小立方体是能够包围特定物体的最小的立方体,它通常可用于碰撞检测。
定义包围立方体:DynamicVolume vol = n->getVolume(false);
将立方体置空:vol.setEmpty();
设置包围立方体:
vol.emtendBy(Pnt3f(0,0,0));
vol.extendBy(Pnt3f(100,100,100));
设置包围立方体为静态的:vol.setStatic(true);
设置包围立方体是有效的:vol.setValid(true)
6、
核心(Cores)
必须为每一个节点设置对应得核心,否则程序是错误的,一个节点只能且只能对应一个核心。在遍历节点树时当遇到没有核心的节点时认为该树结束,其后面的节点不被遍历。
1、
组核心(Group Core)
Group Core 没有实际功能,但是它可以作为一个核心被添加到节点上,并且能够添加到任何类型的节点上,使得该节点可以添加子节点,该节点如同其他Field Container Container 一样必须使用Create创建。
GroupPtr g = GroupPtr::create();
2、
变换核心(Transformation Core)
Transformation Core
可以被添加到一个节点上,完成对该节点的子节点进行图形变换(子节点不可超过五层)。在OpenSG中变换节点只对变换矩阵的子节点有效。
变换核心的定义:TransformPtr ptr = TransformPtr:create()
变换核心设置变换矩阵:ptr->setMatrix(m)
直接定义带变换核心的节点:
NodePtr transNode = makeCoreNode<Transform>(&transCor)
3、
几何图形核心
用于定义标准几何图形,在OpenSG中有标准函数实现。
二、
容器
1
、领域容器
在OpenSG中领域容器类是所有类的基类,creater()方法均从此继承。对于一个特定的类的指针而言,我们可以通过特定方法得到该指针所对应类的名称和类的ID,该技术类似于java中的反射机制。
获得指针所对应得类名:getTypeName()
获得指针所对应的类ID:getTypeId()
容器分为单一容器和多容器,单一容器只能存放一个对象,而多容器与STL中的容器类似,可以存放多个对象。
多容器的循环显示:
for
(MFNodePtr::iterator it = grandpa->getMFChildren()->getValues().begin(); it != grandpa->getMFChildren()->getValues().end();it++)
{
SLOG << getName(*it) <<endLog;
}
获得节点的子节点个数:getNChildren()
在修改物体属性时,我们将修改部分代码放在beginEditCP和
endEditCP
中间,起到对资源加锁的作用,当程序是多进程时起到保护资源的作用。
2、
核心节点指针
核心节点指针将核心和节点组合在一起,使得操作更加的方便。
核心节点的定义:
CoredNodePtr<Geometry> cnpGeo = CoredNodePtr<Geometry>::create()
或者:
Typedef CoredNodePtr<Geometry> GeometryNodePtr
GeometryNodePtr box = GeometryNodePtr::create()
box = makeBoxGeo(0.5,0.5,0.5,1,1,1)
3、
标准几何图形
makePlane(xsize, ysize, resHor, resVer);
makeBox(xsize,ysize,zsize, resHor, resVer, resDepth);
makeCone(height, bottomRadius, resSides, doSide, doBottom);
makeCylinder(height, radius, resSides, doSide, doTop, doBottom);
makeTorus(innerRadius, outerRadius, resSides, resRings);
makeSphere(resDepth, radius);
makeLatLongSphere(resLat, resLong, radius);
makeConicalFrustum(height, topRadius, bottomRadius, doSide, doTop, doBottom);
4
、变换几何图形
复杂几何图形是由标准几何图形经过一次或多次图形变换得到的
1、
定义一个基本图形核心(最终图形由该图形变换得到)
2、
定义一个变换矩阵,可能需要经过多次变换才能得到最终结果。
3、
定义一个变换核心,该核心用于存放变换矩阵。
4、
定义一个节点,设置该节点的核心为变换核心,该节点的子节点为基本图形核心。
三、
图像纹理与材质
1、
图像的读取
OpenSG
支持png,jpeg,tiff,gif,ppm,fgb,sgi等图像格式,我们可以利用读取得图像来作为我们的物体的纹理。
ImagePtr img = Image::create()
Img->read(“myVeryNiceImageFile.jpg”)
2、
纹理的使用
我们可以定义一个物体并且利用从外界读取得图像作为该物体的纹理,具体实现如下:
1、
包含运用纹理所需的头文件
#include <OpenSG/OSGSimpleTextureMaterial.h>
#include <OpenSG/OSGImage.h>
2、
定义一个图像指针并读取外部文件
ImagePtr img = Image::create()
Img->read(“image/bricks.jpg”)
3、
定义一个SimpleTextureMaterialPtr并指向图像指针
SimpleTextureMaterialPtr tex = SimpleTextureMaterial::create()
Tex
->setImage(img);
4、 定义物体设置其材质为图像
boxGeo->setMaterial(tex);
5、 定义节点,将设置完材质的物体作为核心
NodePtr n = Node::create()
beginEditCP(n,Node::CoreFiledMask);
n->setCore(boxGeg);
endEditCP(n,Node::CorFiledMask);
3、 场景的读取和保存
#include <OpenSG/OSGSceneFileHandler.h>
场景的读取:NodePtr n = SceneFileHandler::the().read(filename)
场景的写入:SceneFileHandler::the().write(n,filename)
将场景写入文件:
FILE * outFile = fopen(“data/output.bin”,”wb”);
BINWriter writer(outFile);
//编译尚未通过
writer.writer(scene);