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