diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CShadowVolumeSceneNode.cpp | 419 |
1 files changed, 419 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CShadowVolumeSceneNode.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CShadowVolumeSceneNode.cpp new file mode 100644 index 0000000..55c802a --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CShadowVolumeSceneNode.cpp | |||
@@ -0,0 +1,419 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "CShadowVolumeSceneNode.h" | ||
6 | #include "ISceneManager.h" | ||
7 | #include "IMesh.h" | ||
8 | #include "IVideoDriver.h" | ||
9 | #include "ICameraSceneNode.h" | ||
10 | #include "SViewFrustum.h" | ||
11 | #include "SLight.h" | ||
12 | #include "os.h" | ||
13 | |||
14 | namespace irr | ||
15 | { | ||
16 | namespace scene | ||
17 | { | ||
18 | |||
19 | |||
20 | //! constructor | ||
21 | CShadowVolumeSceneNode::CShadowVolumeSceneNode(const IMesh* shadowMesh, ISceneNode* parent, | ||
22 | ISceneManager* mgr, s32 id, bool zfailmethod, f32 infinity) | ||
23 | : IShadowVolumeSceneNode(parent, mgr, id), | ||
24 | ShadowMesh(0), IndexCount(0), VertexCount(0), ShadowVolumesUsed(0), | ||
25 | Infinity(infinity), UseZFailMethod(zfailmethod) | ||
26 | { | ||
27 | #ifdef _DEBUG | ||
28 | setDebugName("CShadowVolumeSceneNode"); | ||
29 | #endif | ||
30 | setShadowMesh(shadowMesh); | ||
31 | setAutomaticCulling(scene::EAC_OFF); | ||
32 | } | ||
33 | |||
34 | |||
35 | //! destructor | ||
36 | CShadowVolumeSceneNode::~CShadowVolumeSceneNode() | ||
37 | { | ||
38 | if (ShadowMesh) | ||
39 | ShadowMesh->drop(); | ||
40 | } | ||
41 | |||
42 | |||
43 | void CShadowVolumeSceneNode::createShadowVolume(const core::vector3df& light, bool isDirectional) | ||
44 | { | ||
45 | SShadowVolume* svp = 0; | ||
46 | core::aabbox3d<f32>* bb = 0; | ||
47 | |||
48 | // builds the shadow volume and adds it to the shadow volume list. | ||
49 | |||
50 | if (ShadowVolumes.size() > ShadowVolumesUsed) | ||
51 | { | ||
52 | // get the next unused buffer | ||
53 | |||
54 | svp = &ShadowVolumes[ShadowVolumesUsed]; | ||
55 | svp->set_used(0); | ||
56 | |||
57 | bb = &ShadowBBox[ShadowVolumesUsed]; | ||
58 | } | ||
59 | else | ||
60 | { | ||
61 | ShadowVolumes.push_back(SShadowVolume()); | ||
62 | svp = &ShadowVolumes.getLast(); | ||
63 | |||
64 | ShadowBBox.push_back(core::aabbox3d<f32>()); | ||
65 | bb = &ShadowBBox.getLast(); | ||
66 | } | ||
67 | svp->reallocate(IndexCount*5); | ||
68 | ++ShadowVolumesUsed; | ||
69 | |||
70 | // We use triangle lists | ||
71 | Edges.set_used(IndexCount*2); | ||
72 | u32 numEdges = 0; | ||
73 | |||
74 | numEdges=createEdgesAndCaps(light, svp, bb); | ||
75 | |||
76 | // for all edges add the near->far quads | ||
77 | for (u32 i=0; i<numEdges; ++i) | ||
78 | { | ||
79 | const core::vector3df &v1 = Vertices[Edges[2*i+0]]; | ||
80 | const core::vector3df &v2 = Vertices[Edges[2*i+1]]; | ||
81 | const core::vector3df v3(v1+(v1 - light).normalize()*Infinity); | ||
82 | const core::vector3df v4(v2+(v2 - light).normalize()*Infinity); | ||
83 | |||
84 | // Add a quad (two triangles) to the vertex list | ||
85 | #ifdef _DEBUG | ||
86 | if (svp->size() >= svp->allocated_size()-5) | ||
87 | os::Printer::log("Allocation too small.", ELL_DEBUG); | ||
88 | #endif | ||
89 | svp->push_back(v1); | ||
90 | svp->push_back(v2); | ||
91 | svp->push_back(v3); | ||
92 | |||
93 | svp->push_back(v2); | ||
94 | svp->push_back(v4); | ||
95 | svp->push_back(v3); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | |||
100 | #define IRR_USE_ADJACENCY | ||
101 | #define IRR_USE_REVERSE_EXTRUDED | ||
102 | |||
103 | u32 CShadowVolumeSceneNode::createEdgesAndCaps(const core::vector3df& light, | ||
104 | SShadowVolume* svp, core::aabbox3d<f32>* bb) | ||
105 | { | ||
106 | u32 numEdges=0; | ||
107 | const u32 faceCount = IndexCount / 3; | ||
108 | |||
109 | if(faceCount >= 1) | ||
110 | bb->reset(Vertices[Indices[0]]); | ||
111 | else | ||
112 | bb->reset(0,0,0); | ||
113 | |||
114 | // Check every face if it is front or back facing the light. | ||
115 | for (u32 i=0; i<faceCount; ++i) | ||
116 | { | ||
117 | const core::vector3df v0 = Vertices[Indices[3*i+0]]; | ||
118 | const core::vector3df v1 = Vertices[Indices[3*i+1]]; | ||
119 | const core::vector3df v2 = Vertices[Indices[3*i+2]]; | ||
120 | |||
121 | #ifdef IRR_USE_REVERSE_EXTRUDED | ||
122 | FaceData[i]=core::triangle3df(v0,v1,v2).isFrontFacing(light); | ||
123 | #else | ||
124 | FaceData[i]=core::triangle3df(v2,v1,v0).isFrontFacing(light); | ||
125 | #endif | ||
126 | |||
127 | if (UseZFailMethod && FaceData[i]) | ||
128 | { | ||
129 | #ifdef _DEBUG | ||
130 | if (svp->size() >= svp->allocated_size()-5) | ||
131 | os::Printer::log("Allocation too small.", ELL_DEBUG); | ||
132 | #endif | ||
133 | // add front cap from light-facing faces | ||
134 | svp->push_back(v2); | ||
135 | svp->push_back(v1); | ||
136 | svp->push_back(v0); | ||
137 | |||
138 | // add back cap | ||
139 | const core::vector3df i0 = v0+(v0-light).normalize()*Infinity; | ||
140 | const core::vector3df i1 = v1+(v1-light).normalize()*Infinity; | ||
141 | const core::vector3df i2 = v2+(v2-light).normalize()*Infinity; | ||
142 | |||
143 | svp->push_back(i0); | ||
144 | svp->push_back(i1); | ||
145 | svp->push_back(i2); | ||
146 | |||
147 | bb->addInternalPoint(i0); | ||
148 | bb->addInternalPoint(i1); | ||
149 | bb->addInternalPoint(i2); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | // Create edges | ||
154 | for (u32 i=0; i<faceCount; ++i) | ||
155 | { | ||
156 | // check all front facing faces | ||
157 | if (FaceData[i] == true) | ||
158 | { | ||
159 | const u16 wFace0 = Indices[3*i+0]; | ||
160 | const u16 wFace1 = Indices[3*i+1]; | ||
161 | const u16 wFace2 = Indices[3*i+2]; | ||
162 | |||
163 | const u16 adj0 = Adjacency[3*i+0]; | ||
164 | const u16 adj1 = Adjacency[3*i+1]; | ||
165 | const u16 adj2 = Adjacency[3*i+2]; | ||
166 | |||
167 | // add edges if face is adjacent to back-facing face | ||
168 | // or if no adjacent face was found | ||
169 | #ifdef IRR_USE_ADJACENCY | ||
170 | if (adj0 == i || FaceData[adj0] == false) | ||
171 | #endif | ||
172 | { | ||
173 | // add edge v0-v1 | ||
174 | Edges[2*numEdges+0] = wFace0; | ||
175 | Edges[2*numEdges+1] = wFace1; | ||
176 | ++numEdges; | ||
177 | } | ||
178 | |||
179 | #ifdef IRR_USE_ADJACENCY | ||
180 | if (adj1 == i || FaceData[adj1] == false) | ||
181 | #endif | ||
182 | { | ||
183 | // add edge v1-v2 | ||
184 | Edges[2*numEdges+0] = wFace1; | ||
185 | Edges[2*numEdges+1] = wFace2; | ||
186 | ++numEdges; | ||
187 | } | ||
188 | |||
189 | #ifdef IRR_USE_ADJACENCY | ||
190 | if (adj2 == i || FaceData[adj2] == false) | ||
191 | #endif | ||
192 | { | ||
193 | // add edge v2-v0 | ||
194 | Edges[2*numEdges+0] = wFace2; | ||
195 | Edges[2*numEdges+1] = wFace0; | ||
196 | ++numEdges; | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | return numEdges; | ||
201 | } | ||
202 | |||
203 | |||
204 | void CShadowVolumeSceneNode::setShadowMesh(const IMesh* mesh) | ||
205 | { | ||
206 | if (ShadowMesh == mesh) | ||
207 | return; | ||
208 | if (ShadowMesh) | ||
209 | ShadowMesh->drop(); | ||
210 | ShadowMesh = mesh; | ||
211 | if (ShadowMesh) | ||
212 | { | ||
213 | ShadowMesh->grab(); | ||
214 | Box = ShadowMesh->getBoundingBox(); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | void CShadowVolumeSceneNode::updateShadowVolumes() | ||
220 | { | ||
221 | const u32 oldIndexCount = IndexCount; | ||
222 | const u32 oldVertexCount = VertexCount; | ||
223 | |||
224 | const IMesh* const mesh = ShadowMesh; | ||
225 | if (!mesh) | ||
226 | return; | ||
227 | |||
228 | // create as much shadow volumes as there are lights but | ||
229 | // do not ignore the max light settings. | ||
230 | const u32 lightCount = SceneManager->getVideoDriver()->getDynamicLightCount(); | ||
231 | if (!lightCount) | ||
232 | return; | ||
233 | |||
234 | // calculate total amount of vertices and indices | ||
235 | |||
236 | VertexCount = 0; | ||
237 | IndexCount = 0; | ||
238 | ShadowVolumesUsed = 0; | ||
239 | |||
240 | u32 i; | ||
241 | u32 totalVertices = 0; | ||
242 | u32 totalIndices = 0; | ||
243 | const u32 bufcnt = mesh->getMeshBufferCount(); | ||
244 | |||
245 | for (i=0; i<bufcnt; ++i) | ||
246 | { | ||
247 | const IMeshBuffer* buf = mesh->getMeshBuffer(i); | ||
248 | totalIndices += buf->getIndexCount(); | ||
249 | totalVertices += buf->getVertexCount(); | ||
250 | } | ||
251 | |||
252 | // allocate memory if necessary | ||
253 | |||
254 | Vertices.set_used(totalVertices); | ||
255 | Indices.set_used(totalIndices); | ||
256 | FaceData.set_used(totalIndices / 3); | ||
257 | |||
258 | // copy mesh | ||
259 | for (i=0; i<bufcnt; ++i) | ||
260 | { | ||
261 | const IMeshBuffer* buf = mesh->getMeshBuffer(i); | ||
262 | |||
263 | const u16* idxp = buf->getIndices(); | ||
264 | const u16* idxpend = idxp + buf->getIndexCount(); | ||
265 | for (; idxp!=idxpend; ++idxp) | ||
266 | Indices[IndexCount++] = *idxp + VertexCount; | ||
267 | |||
268 | const u32 vtxcnt = buf->getVertexCount(); | ||
269 | for (u32 j=0; j<vtxcnt; ++j) | ||
270 | Vertices[VertexCount++] = buf->getPosition(j); | ||
271 | } | ||
272 | |||
273 | // recalculate adjacency if necessary | ||
274 | if (oldVertexCount != VertexCount || oldIndexCount != IndexCount) | ||
275 | calculateAdjacency(); | ||
276 | |||
277 | core::matrix4 mat = Parent->getAbsoluteTransformation(); | ||
278 | mat.makeInverse(); | ||
279 | const core::vector3df parentpos = Parent->getAbsolutePosition(); | ||
280 | |||
281 | // TODO: Only correct for point lights. | ||
282 | for (i=0; i<lightCount; ++i) | ||
283 | { | ||
284 | const video::SLight& dl = SceneManager->getVideoDriver()->getDynamicLight(i); | ||
285 | core::vector3df lpos = dl.Position; | ||
286 | if (dl.CastShadows && | ||
287 | fabs((lpos - parentpos).getLengthSQ()) <= (dl.Radius*dl.Radius*4.0f)) | ||
288 | { | ||
289 | mat.transformVect(lpos); | ||
290 | createShadowVolume(lpos); | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | |||
295 | |||
296 | //! pre render method | ||
297 | void CShadowVolumeSceneNode::OnRegisterSceneNode() | ||
298 | { | ||
299 | if (IsVisible) | ||
300 | { | ||
301 | SceneManager->registerNodeForRendering(this, scene::ESNRP_SHADOW); | ||
302 | ISceneNode::OnRegisterSceneNode(); | ||
303 | } | ||
304 | } | ||
305 | |||
306 | //! renders the node. | ||
307 | void CShadowVolumeSceneNode::render() | ||
308 | { | ||
309 | video::IVideoDriver* driver = SceneManager->getVideoDriver(); | ||
310 | |||
311 | if (!ShadowVolumesUsed || !driver) | ||
312 | return; | ||
313 | |||
314 | driver->setTransform(video::ETS_WORLD, Parent->getAbsoluteTransformation()); | ||
315 | |||
316 | for (u32 i=0; i<ShadowVolumesUsed; ++i) | ||
317 | { | ||
318 | bool drawShadow = true; | ||
319 | |||
320 | if (UseZFailMethod && SceneManager->getActiveCamera()) | ||
321 | { | ||
322 | // Disable shadows drawing, when back cap is behind of ZFar plane. | ||
323 | |||
324 | SViewFrustum frust = *SceneManager->getActiveCamera()->getViewFrustum(); | ||
325 | |||
326 | core::matrix4 invTrans(Parent->getAbsoluteTransformation(), core::matrix4::EM4CONST_INVERSE); | ||
327 | frust.transform(invTrans); | ||
328 | |||
329 | core::vector3df edges[8]; | ||
330 | ShadowBBox[i].getEdges(edges); | ||
331 | |||
332 | core::vector3df largestEdge = edges[0]; | ||
333 | f32 maxDistance = core::vector3df(SceneManager->getActiveCamera()->getPosition() - edges[0]).getLength(); | ||
334 | f32 curDistance = 0.f; | ||
335 | |||
336 | for(int j = 1; j < 8; ++j) | ||
337 | { | ||
338 | curDistance = core::vector3df(SceneManager->getActiveCamera()->getPosition() - edges[j]).getLength(); | ||
339 | |||
340 | if(curDistance > maxDistance) | ||
341 | { | ||
342 | maxDistance = curDistance; | ||
343 | largestEdge = edges[j]; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | if (!(frust.planes[scene::SViewFrustum::VF_FAR_PLANE].classifyPointRelation(largestEdge) != core::ISREL3D_FRONT)) | ||
348 | drawShadow = false; | ||
349 | } | ||
350 | |||
351 | if(drawShadow) | ||
352 | driver->drawStencilShadowVolume(ShadowVolumes[i], UseZFailMethod, DebugDataVisible); | ||
353 | else | ||
354 | { | ||
355 | core::array<core::vector3df> triangles; | ||
356 | driver->drawStencilShadowVolume(triangles, UseZFailMethod, DebugDataVisible); | ||
357 | } | ||
358 | } | ||
359 | } | ||
360 | |||
361 | |||
362 | //! returns the axis aligned bounding box of this node | ||
363 | const core::aabbox3d<f32>& CShadowVolumeSceneNode::getBoundingBox() const | ||
364 | { | ||
365 | return Box; | ||
366 | } | ||
367 | |||
368 | |||
369 | //! Generates adjacency information based on mesh indices. | ||
370 | void CShadowVolumeSceneNode::calculateAdjacency() | ||
371 | { | ||
372 | Adjacency.set_used(IndexCount); | ||
373 | |||
374 | // go through all faces and fetch their three neighbours | ||
375 | for (u32 f=0; f<IndexCount; f+=3) | ||
376 | { | ||
377 | for (u32 edge = 0; edge<3; ++edge) | ||
378 | { | ||
379 | const core::vector3df& v1 = Vertices[Indices[f+edge]]; | ||
380 | const core::vector3df& v2 = Vertices[Indices[f+((edge+1)%3)]]; | ||
381 | |||
382 | // now we search an_O_ther _F_ace with these two | ||
383 | // vertices, which is not the current face. | ||
384 | u32 of; | ||
385 | |||
386 | for (of=0; of<IndexCount; of+=3) | ||
387 | { | ||
388 | // only other faces | ||
389 | if (of != f) | ||
390 | { | ||
391 | bool cnt1 = false; | ||
392 | bool cnt2 = false; | ||
393 | |||
394 | for (s32 e=0; e<3; ++e) | ||
395 | { | ||
396 | if (v1.equals(Vertices[Indices[of+e]])) | ||
397 | cnt1=true; | ||
398 | |||
399 | if (v2.equals(Vertices[Indices[of+e]])) | ||
400 | cnt2=true; | ||
401 | } | ||
402 | // one match for each vertex, i.e. edge is the same | ||
403 | if (cnt1 && cnt2) | ||
404 | break; | ||
405 | } | ||
406 | } | ||
407 | |||
408 | // no adjacent edges -> store face number, else store adjacent face | ||
409 | if (of >= IndexCount) | ||
410 | Adjacency[f + edge] = f/3; | ||
411 | else | ||
412 | Adjacency[f + edge] = of/3; | ||
413 | } | ||
414 | } | ||
415 | } | ||
416 | |||
417 | |||
418 | } // end namespace scene | ||
419 | } // end namespace irr | ||