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的几点区别:

  1. osg::MatrixTransform按照我们给的顺序组合各种变换,比如我们先定义平移、在定义旋转和缩放,那么MatrixTransform的矩阵是 M = TRS,也就是所它会严格按照我们指定的顺序执行操作。指定的顺序不同时产生的结果差异巨大。
  2. 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());
          }
      }
  }

}

效果图:

效果图

参考:

  1. OSG向场景中添加osgParticle粒子效果
  2. my coding.net
  3. osg设置透明
  4. osg纹理映射
  5. osg::MatrixTransform和osg::PositionAttitudeTransform异同
  6. osgFX - 开发者简明手册