aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/examples/26.OcclusionQuery/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/examples/26.OcclusionQuery/main.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/examples/26.OcclusionQuery/main.cpp213
1 files changed, 213 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/examples/26.OcclusionQuery/main.cpp b/src/others/irrlicht-1.8.1/examples/26.OcclusionQuery/main.cpp
new file mode 100644
index 0000000..17f64b2
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/examples/26.OcclusionQuery/main.cpp
@@ -0,0 +1,213 @@
1/** Example 026 OcclusionQuery
2
3This Tutorial shows how to speed up rendering by use of the
4OcclusionQuery feature. The usual rendering tries to avoid rendering of
5scene nodes by culling those nodes which are outside the visible area, the
6view frustum. However, this technique does not cope with occluded objects
7which are still in the line of sight, but occluded by some larger object
8between the object and the eye (camera). Occlusion queries check exactly that.
9The queries basically measure the number of pixels that a previous render
10left on the screen.
11Since those pixels cannot be recognized at the end of a rendering anymore,
12the pixel count is measured directly when rendering. Thus, one needs to render
13the occluder (the object in front) first. This object needs to write to the
14z-buffer in order to become a real occluder. Then the node is rendered and in
15case a z-pass happens, i.e. the pixel is written to the framebuffer, the pixel
16is counted in the query.
17The result of a query is the number of pixels which got through. One can, based
18on this number, judge if the scene node is visible enough to be rendered, or if
19the node should be removed in the next round. Also note that the number of
20pixels is a safe over approximation in general. The pixels might be overdrawn
21later on, and the GPU tries to avoid inaccuracies which could lead to false
22negatives in the queries.
23
24As you might have recognized already, we had to render the node to get the
25numbers. So where's the benefit, you might say. There are several ways where
26occlusion queries can help. It is often a good idea to just render the bbox
27of the node instead of the actual mesh. This is really fast and is a safe over
28approximation. If you need a more exact render with the actual geometry, it's
29a good idea to render with just basic solid material. Avoid complex shaders
30and state changes through textures. There's no need while just doing the
31occlusion query. At least if the render is not used for the actual scene. This
32is the third way to optimize occlusion queries. Just check the queries every
335th or 10th frame, or even less frequent. This depends on the movement speed
34of the objects and camera.
35*/
36
37#ifdef _MSC_VER
38// We'll also define this to stop MSVC complaining about sprintf().
39#define _CRT_SECURE_NO_WARNINGS
40#pragma comment(lib, "Irrlicht.lib")
41#endif
42
43#include <irrlicht.h>
44#include "driverChoice.h"
45
46using namespace irr;
47
48/*
49We need keyboard input events to switch some parameters
50*/
51class MyEventReceiver : public IEventReceiver
52{
53public:
54 // This is the one method that we have to implement
55 virtual bool OnEvent(const SEvent& event)
56 {
57 // Remember whether each key is down or up
58 if (event.EventType == irr::EET_KEY_INPUT_EVENT)
59 KeyIsDown[event.KeyInput.Key] = event.KeyInput.PressedDown;
60
61 return false;
62 }
63
64 // This is used to check whether a key is being held down
65 virtual bool IsKeyDown(EKEY_CODE keyCode) const
66 {
67 return KeyIsDown[keyCode];
68 }
69
70 MyEventReceiver()
71 {
72 for (u32 i=0; i<KEY_KEY_CODES_COUNT; ++i)
73 KeyIsDown[i] = false;
74 }
75
76private:
77 // We use this array to store the current state of each key
78 bool KeyIsDown[KEY_KEY_CODES_COUNT];
79};
80
81
82/*
83We create an irr::IrrlichtDevice and the scene nodes. One occluder, one
84occluded. The latter is a complex sphere, which has many triangles.
85*/
86int main()
87{
88 // ask user for driver
89 video::E_DRIVER_TYPE driverType=driverChoiceConsole();
90 if (driverType==video::EDT_COUNT)
91 return 1;
92
93 // create device
94 MyEventReceiver receiver;
95
96 IrrlichtDevice* device = createDevice(driverType,
97 core::dimension2d<u32>(640, 480), 16, false, false, false, &receiver);
98
99 if (device == 0)
100 return 1; // could not create selected driver.
101
102 video::IVideoDriver* driver = device->getVideoDriver();
103 scene::ISceneManager* smgr = device->getSceneManager();
104
105 smgr->getGUIEnvironment()->addStaticText(L"Press Space to hide occluder.", core::recti(10,10, 200,50));
106
107 /*
108 Create the node to be occluded. We create a sphere node with high poly count.
109 */
110 scene::ISceneNode * node = smgr->addSphereSceneNode(10, 64);
111 if (node)
112 {
113 node->setPosition(core::vector3df(0,0,60));
114 node->setMaterialTexture(0, driver->getTexture("../../media/wall.bmp"));
115 node->setMaterialFlag(video::EMF_LIGHTING, false);
116 }
117
118 /*
119 Now we create another node, the occluder. It's a simple plane.
120 */
121 scene::ISceneNode* plane = smgr->addMeshSceneNode(smgr->addHillPlaneMesh(
122 "plane", core::dimension2df(10,10), core::dimension2du(2,2)), 0, -1,
123 core::vector3df(0,0,20), core::vector3df(270,0,0));
124
125 if (plane)
126 {
127 plane->setMaterialTexture(0, driver->getTexture("../../media/t351sml.jpg"));
128 plane->setMaterialFlag(video::EMF_LIGHTING, false);
129 plane->setMaterialFlag(video::EMF_BACK_FACE_CULLING, true);
130 }
131
132 /*
133 Here we create the occlusion query. Because we don't have a plain mesh scene node
134 (ESNT_MESH or ESNT_ANIMATED_MESH), we pass the base geometry as well. Instead,
135 we could also pass a simpler mesh or the bounding box. But we will use a time
136 based method, where the occlusion query renders to the frame buffer and in case
137 of success (occlusion), the mesh is not drawn for several frames.
138 */
139 driver->addOcclusionQuery(node, ((scene::IMeshSceneNode*)node)->getMesh());
140
141 /*
142 We have done everything, just a camera and draw it. We also write the
143 current frames per second and the name of the driver to the caption of the
144 window to examine the render speedup.
145 We also store the time for measuring the time since the last occlusion query ran
146 and store whether the node should be visible in the next frames.
147 */
148 smgr->addCameraSceneNode();
149 int lastFPS = -1;
150 u32 timeNow = device->getTimer()->getTime();
151 bool nodeVisible=true;
152
153 while(device->run())
154 {
155 plane->setVisible(!receiver.IsKeyDown(irr::KEY_SPACE));
156
157 driver->beginScene(true, true, video::SColor(255,113,113,133));
158 /*
159 First, we draw the scene, possibly without the occluded element. This is necessary
160 because we need the occluder to be drawn first. You can also use several scene
161 managers to collect a number of possible occluders in a separately rendered
162 scene.
163 */
164 node->setVisible(nodeVisible);
165 smgr->drawAll();
166 smgr->getGUIEnvironment()->drawAll();
167
168 /*
169 Once in a while, here every 100 ms, we check the visibility. We run the queries,
170 update the pixel value, and query the result. Since we already rendered the node
171 we render the query invisible. The update is made blocking, as we need the result
172 immediately. If you don't need the result immediately, e.g. because you have other
173 things to render, you can call the update non-blocking. This gives the GPU more
174 time to pass back the results without flushing the render pipeline.
175 If the update was called non-blocking, the result from getOcclusionQueryResult is
176 either the previous value, or 0xffffffff if no value has been generated at all, yet.
177 The result is taken immediately as visibility flag for the node.
178 */
179 if (device->getTimer()->getTime()-timeNow>100)
180 {
181 driver->runAllOcclusionQueries(false);
182 driver->updateAllOcclusionQueries();
183 nodeVisible=driver->getOcclusionQueryResult(node)>0;
184 timeNow=device->getTimer()->getTime();
185 }
186
187 driver->endScene();
188
189 int fps = driver->getFPS();
190
191 if (lastFPS != fps)
192 {
193 core::stringw tmp(L"OcclusionQuery Example [");
194 tmp += driver->getName();
195 tmp += L"] fps: ";
196 tmp += fps;
197
198 device->setWindowCaption(tmp.c_str());
199 lastFPS = fps;
200 }
201 }
202
203 /*
204 In the end, delete the Irrlicht device.
205 */
206 device->drop();
207
208 return 0;
209}
210
211/*
212That's it. Compile and play around with the program.
213**/