Osg阴影与光照
1.预定义几何体
osg::Shape类,直接继承自osg::Object是各种内嵌几何体的基类,可用于剔除和碰撞检测,还可用于生成预定义的几何体对象。
预定义的几何体对象可以与osg::Drawable的子类osg::ShapeDrawable关联,生成可绘制对象。
osg::ref_ptr<osg::Geode> QUtils::createBall(float radius)
{
ref_ptr<TessellationHints> hints = new TessellationHints;
hints->setDetailRatio(2.0f);
ShapeDrawable* shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f),
radius * 1.5f), hints.get());
shape->setColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f));
osg::ref_ptr<osg::Geode> geode_1 = new osg::Geode;
geode_1->addDrawable(shape);
return geode_1;
}
TessellationHints(精度),值越小,精度越小.
2.纹理与材质
在OpenGL中定义了六种纹理表达方式
- 一维纹理
- 二维纹理
- 二维纹理数组
- 三位纹理
- 立方图纹理
- 矩形纹理
在osg中,继承Texture类的纹理映射类有八种,多了两种分别为Texture2DMultisample类以及TextureBuffer类
osg中纹理坐标分别为S T R三个方向,分别对应坐标系中的X Y Z三个坐标轴, 几维纹理代表在几个方向上有变化。
纹理坐标与顶点一一对应,像数学中的映射。
ref_ptr<Group> QUtils::createBall(float radius)
{
//shape
ref_ptr<Group> root = new Group;
ref_ptr<TessellationHints> hints = new TessellationHints;
hints->setDetailRatio(2.0f);
ShapeDrawable* shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f),
radius * 1.5f), hints.get());
shape->setColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f));
osg::ref_ptr<osg::Geode> geode_1 = new osg::Geode;
geode_1->addDrawable(shape);
//旋转
ref_ptr<MatrixTransform> transform_2 = new MatrixTransform;
transform_2->addChild(geode_1.get());
transform_2->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Z_AXIS, inDegrees(8.0f)));
root->addChild(transform_2.get());
//材质
ref_ptr<Material> matirial = new Material;
matirial->setColorMode(Material::DIFFUSE);
matirial->setAmbient(Material::FRONT_AND_BACK, Vec4(0, 1, 0, 1));//设置材质的光照颜色
//设置材质的混合光颜色
matirial->setDiffuse(osg::Material::FRONT_AND_BACK,osg::Vec4(1.0,1.0,1.0,0.5));
matirial->setSpecular(Material::FRONT_AND_BACK, Vec4(1, 0.5, 1, 1));//设置镜面反射光颜色
matirial->setShininess(Material::FRONT_AND_BACK, 64.0f);//设置影像店的大小
root->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), StateAttribute::ON);
//读取图片设置为纹理
osg::ref_ptr<osg::Texture2D> qjTexture = new osg::Texture2D;
qjTexture->setDataVariance(osg::Object::DYNAMIC);
osg::ref_ptr<osg::Image> qjImage =
osgDB::readImageFile("D:\\MyDocuments\\c++_works\\osgTest\\osgTest\\Images\\world.bmp");
qjTexture->setImage(qjImage.get());
geode_1->getOrCreateStateSet()->setTextureAttributeAndModes(0,qjTexture,osg::StateAttribute::ON);
return root;
}
### 3.位置变换
osg::PositionAttitudeTransform继承于osg::Transform, 主要作用是提供模型的位置变换、大小缩放、原点位置的设置以及坐标系的变换。
osg::MatrixTransform也继承于osg::Transform. 主要作用是负责场景中的矩阵变换、矩阵的运算以及坐标系变换。
osg::MatrixTransform和osg::PositionAttitudeTransform的几点区别:
- osg::MatrixTransform按照我们给的顺序组合各种变换,比如我们先定义平移、在定义旋转和缩放,那么MatrixTransform的矩阵是 M = TRS,也就是所它会严格按照我们指定的顺序执行操作。指定的顺序不同时产生的结果差异巨大。
- osg::PositionAttitudeTransform同时几个接口来获得平移、旋转和缩放矩阵。不管我们设置的顺序如何,它的结果矩阵M=SRT(先缩放再旋转最后平移)总是按固定的顺序进行。除此之外osg::PositionAttitudeTransform还可以设置旋转和缩放的轴心位置(一般来说旋转和缩放是以原点为轴心进行的),但是PositionAttitudeTransform提供了让我们以其他位置为轴心进行旋转和缩放。
如果我们想用MatrixTranform实现与PositionAttitudeTransform同样的效果,那么就必须设置三个矩阵相乘的顺序是SRT。如果PositionAttitudeTransform设置了轴心位置,那么在作平移和旋转变换的时候还需要注意应该先平移到轴心位置,再旋转(和缩放),再平移回去。
### 4.osg::NodePath与osgFX
NodePath类对象,可以存储节点的路径,如点拾取时,得到的就是一个NodePath
osgFX是一个OpenSceneGraph的附加库,是一个用于实现一致、完备、可重用的特殊效果的构架工具,其效果可以添加到OSG的节点中。它同时还包含了一系列预定义好的特殊效果。 对于OSG而言,特效就是一个Node节点。它与其它节点类的特性完全相同,因此可以关联到场景图形中的任意位置。
osgFX::Effect类是一个多子节点的组节点。它使用addChild()方法和其它节点关联。 在特效类中设置的可视属性将被关联到它的子节点上,与此相类似,Transform节点也会将坐标变换的信息应用到其子节点上。Effect中的各种属性不会在其子节点以外生效。
如果用户想要将某一种特效应用到自己的图形子树上,那么需要遵循下面的步骤: 1、创建所需特效的实例,例如,osgFX::Scribe; 2、必要的话,使用特效类的方法设置特效属性; 3、调用Effect::addChild()方法,将图形子树与特效节点相关联; 4、将特效节点与场景图形关联。
下面的例子中使用了刻线(scribe)特效:
osg::ref_ptr<osg::Node> my_node = osgDB::readNodeFile(“cow.osg”);
osg::ref_ptr<osgFX::Scribe> scribe_fx = new osgFX::Scribe;
scribe_fx->addChild(my_node.get());
scribe_fx->setEnabled(true);
root->addChild(scribe_fx.get());
选中物体高亮显示。
void pick(osg::ref_ptr<osgViewer::View> view, float x, float y)
{
osg::ref_ptr<osg::Node> node = new osg::Node();
osg::ref_ptr<osg::Group> parent = new osg::Group();
//创建一个线段交集检测函数
osgUtil::LineSegmentIntersector::Intersections intersections;
if (view->computeIntersections(x, y, intersections))
{
osgUtil::LineSegmentIntersector::Intersection intersection = *intersections.begin();
osg::NodePath& nodePath = intersection.nodePath;
//得到选择的物体
node = (nodePath.size()>=1)?nodePath[nodePath.size()-1]:0;
parent = (nodePath.size()>=2)?dynamic_cast<osg::Group*>(nodePath[nodePath.size()-2]):0;
}
//用一种高亮显示来显示物体已经被选中
if (parent.get() && node.get())
{
osg::ref_ptr<osgFX::Scribe> parentAsScribe = dynamic_cast<osgFX::Scribe*>(parent.get());
if (!parentAsScribe)
{
//如果对象选择到,高亮显示
osg::ref_ptr<osgFX::Scribe> scribe = new osgFX::Scribe();
scribe->addChild(node.get());
parent->replaceChild(node.get(),scribe.get());
}
else
{
//如果没有没有选择到,则移除高亮显示的对象
osg::Node::ParentList parentList = parentAsScribe->getParents();
for(osg::Node::ParentList::iterator itr=parentList.begin();
itr!=parentList.end();
++itr)
{
(*itr)->replaceChild(parentAsScribe.get(),node.get());
}
}
}
}
效果图:
参考: