1 /* OpenSceneGraph example, osganimate.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16 * THE SOFTWARE.
17 */
18
19 #include <osg/Notify>
20 #include <osg/MatrixTransform>
21 #include <osg/PositionAttitudeTransform>
22 #include <osg/Geometry>
23 #include <osg/Geode>
24
25 #include <osgUtil/Optimizer>
26
27 #include <osgDB/Registry>
28 #include <osgDB/ReadFile>
29
30 #include <osgGA/TrackballManipulator>
31 #include <osgGA/FlightManipulator>
32 #include <osgGA/DriveManipulator>
33
34 #include <osgSim/OverlayNode>
35
36 #include <osgViewer/Viewer>
37 #include <iostream>
38
createAnimationPath(const osg::Vec3 & center,float radius,double looptime)39 osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
40 {
41 // set up the animation path
42 osg::AnimationPath* animationPath = new osg::AnimationPath;
43 animationPath->setLoopMode(osg::AnimationPath::LOOP);
44
45 int numSamples = 40;
46 float yaw = 0.0f;
47 float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
48 float roll = osg::inDegrees(30.0f);
49
50 double time=0.0f;
51 double time_delta = looptime/(double)numSamples;
52 for(int i=0;i<numSamples;++i)
53 {
54 osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
55 osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));
56
57 animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
58
59 yaw += yaw_delta;
60 time += time_delta;
61
62 }
63 return animationPath;
64 }
65
createBase(const osg::Vec3 & center,float radius)66 osg::Node* createBase(const osg::Vec3& center,float radius)
67 {
68
69
70
71 int numTilesX = 10;
72 int numTilesY = 10;
73
74 float width = 2*radius;
75 float height = 2*radius;
76
77 osg::Vec3 v000(center - osg::Vec3(width*0.5f,height*0.5f,0.0f));
78 osg::Vec3 dx(osg::Vec3(width/((float)numTilesX),0.0,0.0f));
79 osg::Vec3 dy(osg::Vec3(0.0f,height/((float)numTilesY),0.0f));
80
81 // fill in vertices for grid, note numTilesX+1 * numTilesY+1...
82 osg::Vec3Array* coords = new osg::Vec3Array;
83 int iy;
84 for(iy=0;iy<=numTilesY;++iy)
85 {
86 for(int ix=0;ix<=numTilesX;++ix)
87 {
88 coords->push_back(v000+dx*(float)ix+dy*(float)iy);
89 }
90 }
91
92 //Just two colours - black and white.
93 osg::Vec4Array* colors = new osg::Vec4Array;
94 colors->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f)); // white
95 colors->push_back(osg::Vec4(0.0f,0.0f,0.0f,1.0f)); // black
96
97 osg::ref_ptr<osg::DrawElementsUShort> whitePrimitives = new osg::DrawElementsUShort(GL_QUADS);
98 osg::ref_ptr<osg::DrawElementsUShort> blackPrimitives = new osg::DrawElementsUShort(GL_QUADS);
99
100 int numIndicesPerRow=numTilesX+1;
101 for(iy=0;iy<numTilesY;++iy)
102 {
103 for(int ix=0;ix<numTilesX;++ix)
104 {
105 osg::DrawElementsUShort* primitives = ((iy+ix)%2==0) ? whitePrimitives.get() : blackPrimitives.get();
106 primitives->push_back(ix +(iy+1)*numIndicesPerRow);
107 primitives->push_back(ix +iy*numIndicesPerRow);
108 primitives->push_back((ix+1)+iy*numIndicesPerRow);
109 primitives->push_back((ix+1)+(iy+1)*numIndicesPerRow);
110 }
111 }
112
113 // set up a single normal
114 osg::Vec3Array* normals = new osg::Vec3Array;
115 normals->push_back(osg::Vec3(0.0f,0.0f,1.0f));
116
117 osg::Geometry* geom = new osg::Geometry;
118 geom->setVertexArray(coords);
119
120 geom->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET);
121
122 geom->setNormalArray(normals, osg::Array::BIND_OVERALL);
123
124 geom->addPrimitiveSet(whitePrimitives.get());
125 geom->addPrimitiveSet(blackPrimitives.get());
126
127 osg::Geode* geode = new osg::Geode;
128 geode->addDrawable(geom);
129
130 return geode;
131 }
132
createMovingModel(const osg::Vec3 & center,float radius)133 osg::Node* createMovingModel(const osg::Vec3& center, float radius)
134 {
135 float animationLength = 10.0f;
136
137 osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);
138
139 osg::ref_ptr<osg::Group> model = new osg::Group;
140
141 osg::ref_ptr<osg::Node> glider = osgDB::readRefNodeFile("glider.osgt");
142 if (glider)
143 {
144 const osg::BoundingSphere& bs = glider->getBound();
145
146 float size = radius/bs.radius()*0.3f;
147 osg::MatrixTransform* positioned = new osg::MatrixTransform;
148 positioned->setDataVariance(osg::Object::STATIC);
149 positioned->setMatrix(osg::Matrix::translate(-bs.center())*
150 osg::Matrix::scale(size,size,size)*
151 osg::Matrix::rotate(osg::inDegrees(-90.0f),0.0f,0.0f,1.0f));
152
153 positioned->addChild(glider);
154
155 osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform;
156 xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0,1.0));
157 xform->addChild(positioned);
158
159 model->addChild(xform);
160 }
161
162 osg::ref_ptr<osg::Node> cessna = osgDB::readRefNodeFile("cessna.osgt");
163 if (cessna)
164 {
165 const osg::BoundingSphere& bs = cessna->getBound();
166
167 float size = radius/bs.radius()*0.3f;
168 osg::MatrixTransform* positioned = new osg::MatrixTransform;
169 positioned->setDataVariance(osg::Object::STATIC);
170 positioned->setMatrix(osg::Matrix::translate(-bs.center())*
171 osg::Matrix::scale(size,size,size)*
172 osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,1.0f));
173
174 positioned->addChild(cessna);
175
176 osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform;
177 xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
178 xform->addChild(positioned);
179
180 model->addChild(xform);
181 }
182
183 return model.release();
184 }
185
createModel(bool overlay,osgSim::OverlayNode::OverlayTechnique technique)186 osg::ref_ptr<osg::Group> createModel(bool overlay, osgSim::OverlayNode::OverlayTechnique technique)
187 {
188 osg::Vec3 center(0.0f,0.0f,0.0f);
189 float radius = 100.0f;
190
191 osg::ref_ptr<osg::Group> root = new osg::Group;
192
193 float baseHeight = center.z()-radius*0.5;
194 osg::ref_ptr<osg::Node> baseModel = createBase(osg::Vec3(center.x(), center.y(), baseHeight),radius);
195 osg::ref_ptr<osg::Node> movingModel = createMovingModel(center,radius*0.8f);
196
197 if (overlay)
198 {
199 osgSim::OverlayNode* overlayNode = new osgSim::OverlayNode(technique);
200 overlayNode->setContinuousUpdate(true);
201 overlayNode->setOverlaySubgraph(movingModel);
202 overlayNode->setOverlayBaseHeight(baseHeight-0.01);
203 overlayNode->addChild(baseModel);
204 root->addChild(overlayNode);
205 }
206 else
207 {
208
209 root->addChild(baseModel);
210 }
211
212 root->addChild(movingModel);
213
214 return root;
215 }
216
217
main(int argc,char ** argv)218 int main( int argc, char **argv )
219 {
220
221 bool overlay = false;
222 osg::ArgumentParser arguments(&argc,argv);
223 while (arguments.read("--overlay")) overlay = true;
224
225 osgSim::OverlayNode::OverlayTechnique technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY;
226 while (arguments.read("--object")) { technique = osgSim::OverlayNode::OBJECT_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY; overlay=true; }
227 while (arguments.read("--ortho") || arguments.read("--orthographic")) { technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_ORTHOGRAPHIC_OVERLAY; overlay=true; }
228 while (arguments.read("--persp") || arguments.read("--perspective")) { technique = osgSim::OverlayNode::VIEW_DEPENDENT_WITH_PERSPECTIVE_OVERLAY; overlay=true; }
229
230
231 // initialize the viewer.
232 osgViewer::Viewer viewer;
233
234 // load the nodes from the commandline arguments.
235 osg::ref_ptr<osg::Group> model = createModel(overlay, technique);
236 if (!model)
237 {
238 return 1;
239 }
240
241 // tilt the scene so the default eye position is looking down on the model.
242 osg::ref_ptr<osg::MatrixTransform> rootnode = new osg::MatrixTransform;
243 rootnode->setMatrix(osg::Matrix::rotate(osg::inDegrees(30.0f),1.0f,0.0f,0.0f));
244 rootnode->addChild(model);
245
246 // run optimization over the scene graph
247 osgUtil::Optimizer optimzer;
248 optimzer.optimize(rootnode);
249
250 // set the scene to render
251 viewer.setSceneData(rootnode);
252
253 viewer.setCameraManipulator(new osgGA::TrackballManipulator());
254
255 // viewer.setUpViewOnSingleScreen(1);
256
257 #if 0
258
259 // use of custom simulation time.
260
261 viewer.realize();
262
263 double simulationTime = 0.0;
264
265 while (!viewer.done())
266 {
267 viewer.frame(simulationTime);
268 simulationTime += 0.001;
269 }
270
271 return 0;
272 #else
273
274 // normal viewer usage.
275 return viewer.run();
276
277 #endif
278 }
279