aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8/source/Irrlicht/CShadowVolumeSceneNode.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libraries/irrlicht-1.8/source/Irrlicht/CShadowVolumeSceneNode.cpp419
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
14namespace irr
15{
16namespace scene
17{
18
19
20//! constructor
21CShadowVolumeSceneNode::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
36CShadowVolumeSceneNode::~CShadowVolumeSceneNode()
37{
38 if (ShadowMesh)
39 ShadowMesh->drop();
40}
41
42
43void 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
103u32 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
204void 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
219void 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
297void CShadowVolumeSceneNode::OnRegisterSceneNode()
298{
299 if (IsVisible)
300 {
301 SceneManager->registerNodeForRendering(this, scene::ESNRP_SHADOW);
302 ISceneNode::OnRegisterSceneNode();
303 }
304}
305
306//! renders the node.
307void 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
363const core::aabbox3d<f32>& CShadowVolumeSceneNode::getBoundingBox() const
364{
365 return Box;
366}
367
368
369//! Generates adjacency information based on mesh indices.
370void 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