前天晚上忘记更新读书笔记,现在补上,呵呵
p.s昨天到OMNIPLEX去看了“Harry Potter & Half-Blood Princes”,感觉还不错,接下来就是赶紧把哈7看完就等着看大结局了,霍霍~
言归正传:
3.2.1 Data Variance
数据变量
The osgViewer library supports threading model that allow the application main loop to continue before the draw traversal completes. This means Viewer::frame() can return while the draw traversal is still active. It also means that the draw traversal from the previous frame could overlap with the update traversal of the next frame. When you consider the implications of this threading model, it might seem impossible to avoid colliding with the draw traversal thread. However, OSG supplies a solution with the osg::Object::setDataVariance() method.
osgViewer库支持线程模型,该模型允许在绘制遍历完成之前,程序的主要循环可以执行。这就意味着在绘制执行的时候Viewer::frame() 可以有返回值。另外,这也表示前一帧的绘制遍历可以被下一帧执行更新遍历的时候所覆盖。仔细考虑这样的线程模型意味着什么,可能会觉得这样是会与绘制遍历所冲突的。然而,OSG提供了一个解决的方案,那就是osg::Object::setDataVariance()方法。
To set the Object data variance, call setDataVariance() with one of the Object::DataVariance enumerate values. Initially, data variance is UNSPECIFIED. Your application should change the data variance to either STATIC OR DYNAMIC.
通过调用setDataVariance(),赋予一个Object::DataVariance所包含的枚举值,可以设置对象的数据变量。初始的数据变量是不定的。通过程序可以把数据变量改为STATIC 或者DYNAMIC.
Cause of the crash
崩溃的原因
As you develop code to dynamically modify the scene graph, you might encounter an application crash or segmentation violation that occurs during the scene graph modification. Such crashes are almost always caused by modifying the scene graph during the cull or draw traversals.
因为你的代码可以实时的修改场景图想,你的程序可能会崩溃或者会导致场景修改中发生分割违例。在拣选和绘制遍历中修改场景,经常会导致这样的崩溃。
OSG ensures that the draw traversal returns only after processing all DYNAMIC Drawable and StateSet object data. The draw traversal may still be processing the render graph even after it has returned, but only STATIC data remains in the render graph at that point. If your scene graph contains very little DYNAMIC data and the draw traversal processes that data early in the frame, the draw traversal returns very quickly, freeing your application for other tasks.
OSG可以确保只能在所有的动态Drawable和StateSet对象数据都处理之后才能返回绘制遍历。甚至在图像渲染并返回之后,绘制遍历可能仍然在执行,但此时只有STATIC数据可以保存在渲染图像中。如果你的场景图形之包含了很少的动态数据,绘制遍历会在处理一帧图形的早期就已经处理过它,并且绘制遍历会快速的返回以完成你的程序,然后进行其他的工作。
If your application attempts to modify non-DYNAMIC Drawable or StateSet data, you could experience a thread collision as multiple threads attempt to access the same data. Most operating systems handle this by aborting your application process. For this reason, you should always mark data as DYNAMIC if your application modifies it.
如果你在程序中试图去修改non-DYNAMIC 的Drawable或者StateSet数据,因为会有其他的很多线程尝试去读取这个数据,这样就可能会导致线程冲突。大多数操作系统都是通过停止你的应用程序进程来处理这种冲突。因此,如果你的程序会修改该数据的话,那么就应该把它设为DYNAMIC。
The render graph contains references to only Drawable or StateSet objects. However, if your application intends to modify a Node, such as switching a child on or off in a Switch node, you should set the node’s data variance to DYNAMIC. This prevents the osgUtil::Optimizer from altering your scene graph structure.
渲染图像只包含对Drawalbe或StateSet对象的引用。然而,如果你在程序中试图去修改一个节点(诸如通过转换节点来启动或关闭一个子节点),那么在程序中,就应该把节点的数据变量设置为DYNAMIC. 这就防止了osgUtil::Optimizer对你的场景图形结构发出警告。
3.2.2 Callbacks
回调
OSG allows you to assign callbacks to Node and Drawable objects. OSG executes Node callbacks during the update and cull traversals, and executes Drawable callbacks during the cull and draw traversals. This section describes how to dynamically modify a Node during the update traversal using an osg::NodeCallback. OSG’s callback interface is based on the Callback design pattern.
OSG中,你可以为一个节点或Drawable对象分配一个回调。在更新和拣选遍历中,OSG会执行节点与Drawable回调。本小节将会阐述如何在更新遍历的时候运用osg::NodeCallback来实时的修改节点。OSG的回调接口是基于回调设计模式的。
To use a NodeCallback, your application should perform the following steps.
要使用NodeCallback,你的程序应该按照以下几步执行:
l Derive a new class from NodeCallback.
l Override the NodeCallback::operator() method. Code this method to perform the dynamic modification on your scene graph.
l Instantiate your new class derived from NodeCallback, and attach it to the Node that you want to modify using the Node::setUpdateCallback() mthod.
l 继承一个NodeCallback类
l 重写NodeCallback::operator() 方法。让该方法可以动态的修改场景图
l 初始化你继承自Node::setUpdateCallback()方法的类
OSG calls the operator()() method in your derived class during each update traversal, allowing your application to modify the Node.
OSG在你的继承类执行更新遍历的时候调用operator()方法,使得你可以修改Node
OSG passes two parameters to your operator()() method. The first parameter is the address of the Node associated with your callback. This is the Node that your callback dynamically modifies within the operator()() method. The second parameter is an osg::NodeVisitor address. The next section describes the NodeVisitor class, and for now you can ignore it.
OSG会向你的operator()()方法传递两个变量。第一个变量是与Callback相关联的Node的地址。该Node就是你的operator()()方法中会动态修改的节点。第二个参数是osg::NodeVisitor的地址。这将会在下一个小节中讲解。
To attach your NodeCallback to a Node, use the Node::setUpdateCallback() method. setUpdateCallback() takes one parameter, the address of a class derived from NodeCallback. The following code segment shows how to attach a NodeCallback to a node.
要想为一个节点附加NodeCallback,需使用Node::setUpdateCallback()方法。改方法需要一个参数,那就是继承自NodeCallback的类的地址。接下来的代码,就演示了如何为一个节点附加一个NodeCallback。
class RotateCB : public osg::NodeCallback
{
…
};
…
Node->setUpdateCallback( new RotateCB);
Multiple nodes can share callbacks. NodeCallback derives (indirectly) from Referenced, and Node keeps a ref_ptr<> to its update callback. When the last node referencing a callback is deleted, the NodeCallback reference count drops to zero, and it is also deleted. In the code above, your application doesn’t keep a pointer to the RotateCB object and doesn’t need to.
节点间可以共享callbacks。NodeCallback间接的继承自Referenced,同时,节点为它的更新回调保留了一个ref_ptr<>。当最后一个引用callback的节点被删除的时候,NodeCallback的引用计数降为0,此时,就会被删除。在上述代码中,程序并没有也不需要一个指向RotateCB对象的指针。
The book’s example code contains a Callback example that demonstrates the use of update callbacks. The code attaches a cow to two MatrixTransform nodes. The code derives a class from NodeCallback and attaches it to one of the two MatrixTransform objects. During the update traversal, the new NodeCallback modifies the matrix to rotate one of the cows.
本书中的代码包含的一个Callback的例子,该例子证明了如何使用更新回调。程需中,这个cow被附加了两个MatrixTransform节点。在更新遍历中,新的NodeCallback修改了矩阵从而使得cow被旋转。
Below shows the example code, which consists of three main parts. The first part defines a class called RotateCB, which derives from NodeCallback. The second part is a function called createScene(), which creates the scene graph. Note that when this function creates the first MatrixTransform object, called mtLeft, it assigns an update callback to mtLeft with the function call mtLeft->setUpdateCallback( new RotateCB). If you were to comment this line out and run the example, the cow wouldn’t rotate, the final part of the example is the main() entry point that creates a viewer and renders.
下面给出了这个例子的源代码,该代码包含三个主要部分。第一部分定义了一个叫做RotateCB的类,这个类继承自NodeCallback.第二部分是一个名为createScene()的函数,该函数创建了一个场景。注意,当这个函数创建第一个MatrixTransform对象mtLeft时,它为其分配了一个更新回调(mtLeft->setUpdateCallback(new RotateCB))。如果你将这一行代码注释掉,那么这个cow就不会被旋转了。最后一个部分是这个例子的主要entry点,它创建了一个viewer和renders。
The Callback Example Source Code
Callback例子的源代码
This example demonstrates the process of creating a NodeCallback to update the scene graph during the update traversal.
这个例子讲述了如何创建一个NodeCallback在更新遍历的时候更新场景图
#include <osgViewer/Viewer>
#include <osgGA/TrackballManipulator>
#include <osg/NodeCallback>
#include <osg/Camera>
#include <osg/Group>
#include <osg/MatrixTransform>
#include <osgDB/ReadFile>
//Derive a class from NodeCallBack to manipulate a
// MatrixTransform object’s matrix.
class RotateCB : pulic osg:: NodeCallback
{
public:
RotateCB() : _angle(0.){}
Virtural void operator()(osg::Node* node,
osg::NodeVisitor* nv)
{
// Normally, check to make sure we have an update
// visitor, not necessary in this simple example.
osg::MatrixTransform* mtLeft =
dynamic_cast<osg::MatrixTransform*>(node);
osg::Matrix mR, mT;
mT.makeTranslate(-6.,0.,0.);
mR.makeRotate( _angle, osg::Vec3(0.,0.,1.));
mTLeft->setMatrix(mR*mT);
// Increment the angle for the next from
_angle +=0.01;
// Continue traversing so that OSG can process
// any other nodes with callbacks.
traverse( node, nv);
}
protected:
double _angle;
};
// Create the scene graph. This is a Group root node with two
// MatrixTransform children, which both parent a single
// Geode loaded from the cos.osg model file.
osg::ref_ptr<osg::Node>
createScene()
{
// Load the cow model.
osg::Node* cow = osgDB::readNodeFile(“cow.osg”);
// Data variance is STATIC because we won’t modify it.
cow->setDataVariance( osg::Object::STATIC) ;
//Create a MatrixTransform to display the cow on the left
osg::ref_ptr<osg::MatrixTransform> mtLeft =
new osg::MatrixTransform;
mtLeft->setName(“Left Cow/nDYNAMIC”);
//set data variance to DYNAMIC to let OSG know that we
// will modify this node during the update traversal.
mtLeft->setDataVariance( osg::Object::DYNAMIC);
//set the update callback
mtLeft->setUpdateCallback( new RotateCB);
osg::Matrix m;
m.makeTranslate(-6.f, 0.f, 0.f);
mtLeft->setMatrix( m);
mtLeft->addChild( cow) ;
//Create the Group root node.
osg::ref_ptr<osg::Group> root = new osg::Group;
root->setName(“Root Node”);
// Data variance is STATIC because we won’t modify it
root->setDataVariance(osg::Object::STATIC);
root->addChild(mtLeft.get());
root->addChild(mtRight.get());
return root.get();
}
int main(int, char**)
{
//create the viewer and set its scene data to our scene
// graph created above.
osgViewer::Viewer viewer;
viewer.setSceneData( createScene().get());
// set the clear color to something other than chalky blue
viewer.getCamera()->setClearColor(
osg::Vec4(1.,1.,1.,1.));
//loop and render.OSG calls RotateCB::operator()()
//during the update traversal.
viewer.run();
}
RotateCB::operator()() contains a call to traverse(). This is member method of the osg::NodeCallback class. This call allows the update traversal (osgUtil::UpdateVisitor) to traverse the current group node children. Requiring a call to traverse() is a design feature that lets your NodeCallback perform either pre- or post-traversal processing, depending on where you place your code relative to the traverse() call. Omitting this call prevents OSG from executing child node callbacks. The following section discusses the NodeVisitor class in more detail.
RotateCB::operator()()调用traverse()。这是osg::NodeCallback类的成员方法。这个调用允许更新遍历去遍历当前group的所有子节点。要求调用traverse()是一个设计特性,这可以让你的NodeCallback完成提前或之后遍历的处理(这取决于调用的traverse()的代码的所处位置)。省去这一调用,将使得OSG不能执行子节点的回调。接下来的章节将会具体讨论NodeVisitor类。
如果一个节点可能会被修改,那么其数据变量应定义为DYNAMIC,反之,则定义为STATIC.
As this example illustrates, dynamically modifying a node is straightforward because attaching an update callback to a known node is trivial. The problem becomes more complex if your application modifies a node that is buried deep within a scene graph or selected interactively by a user. The next sections describe some methods in OSG for runtime node identification.
如例子中所示,动态修改一个节点是直接的。只有当你的程序修改一个在场景图中隐藏很深或者经由用户交互式而被选择的节点的时候,问题才会比较复杂。接下来的章节将会讲述一些如何在实时运行时候的修改节点的方法。