2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
7 Copyright (c) 2000-2006 Torus Knot Software Ltd
8 Also see acknowledgements in Readme.html
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22 http://www.gnu.org/copyleft/lesser.txt.
24 You may alternatively use this source under the terms of a specific version of
25 the OGRE Unrestricted License provided you have obtained such a license from
26 Torus Knot Software Ltd.
27 -----------------------------------------------------------------------------
29 #include "OgreStableHeaders.h"
30 #include "OgreLight.h"
31 #include "OgreEdgeListBuilder.h"
32 #include "OgreOptimisedUtil.h"
35 const LightList
& ShadowRenderable::getLights(void) const
41 // ------------------------------------------------------------------------
42 void ShadowCaster::updateEdgeListLightFacing(EdgeData
* edgeData
,
43 const Vector4
& lightPos
)
45 edgeData
->updateTriangleLightFacing(lightPos
);
47 // ------------------------------------------------------------------------
48 void ShadowCaster::generateShadowVolume(EdgeData
* edgeData
,
49 const HardwareIndexBufferSharedPtr
& indexBuffer
, const Light
* light
,
50 ShadowRenderableList
& shadowRenderables
, unsigned long flags
)
52 // Edge groups should be 1:1 with shadow renderables
53 assert(edgeData
->edgeGroups
.size() == shadowRenderables
.size());
55 EdgeData::EdgeGroupList::const_iterator egi
, egiend
;
56 ShadowRenderableList::const_iterator si
;
58 Light::LightTypes lightType
= light
->getType();
60 // pre-count the size of index data we need since it makes a big perf difference
61 // to GL in particular if we lock a smaller area of the index buffer
62 size_t preCountIndexes
= 0;
64 si
= shadowRenderables
.begin();
65 egiend
= edgeData
->edgeGroups
.end();
66 for (egi
= edgeData
->edgeGroups
.begin(); egi
!= egiend
; ++egi
, ++si
)
68 const EdgeData::EdgeGroup
& eg
= *egi
;
69 bool firstDarkCapTri
= true;
71 EdgeData::EdgeList::const_iterator i
, iend
;
72 iend
= eg
.edges
.end();
73 for (i
= eg
.edges
.begin(); i
!= iend
; ++i
)
75 const EdgeData::Edge
& edge
= *i
;
77 // Silhouette edge, when two tris has opposite light facing, or
78 // degenerate edge where only tri 1 is valid and the tri light facing
79 char lightFacing
= edgeData
->triangleLightFacings
[edge
.triIndex
[0]];
80 if ((edge
.degenerate
&& lightFacing
) ||
81 (!edge
.degenerate
&& (lightFacing
!= edgeData
->triangleLightFacings
[edge
.triIndex
[1]])))
86 // Are we extruding to infinity?
87 if (!(lightType
== Light::LT_DIRECTIONAL
&&
88 flags
& SRF_EXTRUDE_TO_INFINITY
))
94 // Use McGuire et al method, a triangle fan covering all silhouette
95 // edges and one point (taken from the initial tri)
96 if (flags
& SRF_INCLUDE_DARK_CAP
)
100 firstDarkCapTri
= false;
104 preCountIndexes
+= 3;
113 if (flags
& SRF_INCLUDE_LIGHT_CAP
)
115 // Iterate over the triangles which are using this vertex set
116 EdgeData::TriangleList::const_iterator ti
, tiend
;
117 EdgeData::TriangleLightFacingList::const_iterator lfi
;
118 ti
= edgeData
->triangles
.begin() + eg
.triStart
;
119 tiend
= ti
+ eg
.triCount
;
120 lfi
= edgeData
->triangleLightFacings
.begin() + eg
.triStart
;
121 for ( ; ti
!= tiend
; ++ti
, ++lfi
)
123 const EdgeData::Triangle
& t
= *ti
;
124 assert(t
.vertexSet
== eg
.vertexSet
);
125 // Check it's light facing
128 preCountIndexes
+= 3;
138 // Lock index buffer for writing, just enough length as we need
139 unsigned short* pIdx
= static_cast<unsigned short*>(
140 indexBuffer
->lock(0, sizeof(unsigned short) * preCountIndexes
,
141 HardwareBuffer::HBL_DISCARD
));
142 size_t numIndices
= 0;
144 // Iterate over the groups and form renderables for each based on their
146 si
= shadowRenderables
.begin();
147 egiend
= edgeData
->edgeGroups
.end();
148 for (egi
= edgeData
->edgeGroups
.begin(); egi
!= egiend
; ++egi
, ++si
)
150 const EdgeData::EdgeGroup
& eg
= *egi
;
151 // Initialise the index start for this shadow renderable
152 IndexData
* indexData
= (*si
)->getRenderOperationForUpdate()->indexData
;
153 indexData
->indexStart
= numIndices
;
154 // original number of verts (without extruded copy)
155 size_t originalVertexCount
= eg
.vertexData
->vertexCount
;
156 bool firstDarkCapTri
= true;
157 unsigned short darkCapStart
;
159 EdgeData::EdgeList::const_iterator i
, iend
;
160 iend
= eg
.edges
.end();
161 for (i
= eg
.edges
.begin(); i
!= iend
; ++i
)
163 const EdgeData::Edge
& edge
= *i
;
165 // Silhouette edge, when two tris has opposite light facing, or
166 // degenerate edge where only tri 1 is valid and the tri light facing
167 char lightFacing
= edgeData
->triangleLightFacings
[edge
.triIndex
[0]];
168 if ((edge
.degenerate
&& lightFacing
) ||
169 (!edge
.degenerate
&& (lightFacing
!= edgeData
->triangleLightFacings
[edge
.triIndex
[1]])))
171 size_t v0
= edge
.vertIndex
[0];
172 size_t v1
= edge
.vertIndex
[1];
175 // Inverse edge indexes when t1 is light away
179 /* Note edge(v0, v1) run anticlockwise along the edge from
180 the light facing tri so to point shadow volume tris outward,
181 light cap indexes have to be backwards
183 We emit 2 tris if light is a point light, 1 if light
184 is directional, because directional lights cause all
185 points to converge to a single point at infinity.
187 First side tri = near1, near0, far0
188 Second tri = far0, far1, near1
190 'far' indexes are 'near' index + originalVertexCount
191 because 'far' verts are in the second half of the
194 assert(v1
< 65536 && v0
< 65536 && (v0
+ originalVertexCount
) < 65536 &&
195 "Vertex count exceeds 16-bit index limit!");
196 *pIdx
++ = static_cast<unsigned short>(v1
);
197 *pIdx
++ = static_cast<unsigned short>(v0
);
198 *pIdx
++ = static_cast<unsigned short>(v0
+ originalVertexCount
);
201 // Are we extruding to infinity?
202 if (!(lightType
== Light::LT_DIRECTIONAL
&&
203 flags
& SRF_EXTRUDE_TO_INFINITY
))
205 // additional tri to make quad
206 *pIdx
++ = static_cast<unsigned short>(v0
+ originalVertexCount
);
207 *pIdx
++ = static_cast<unsigned short>(v1
+ originalVertexCount
);
208 *pIdx
++ = static_cast<unsigned short>(v1
);
213 // Use McGuire et al method, a triangle fan covering all silhouette
214 // edges and one point (taken from the initial tri)
215 if (flags
& SRF_INCLUDE_DARK_CAP
)
219 darkCapStart
= static_cast<unsigned short>(v0
+ originalVertexCount
);
220 firstDarkCapTri
= false;
224 *pIdx
++ = darkCapStart
;
225 *pIdx
++ = static_cast<unsigned short>(v1
+ originalVertexCount
);
226 *pIdx
++ = static_cast<unsigned short>(v0
+ originalVertexCount
);
236 if (flags
& SRF_INCLUDE_LIGHT_CAP
)
238 // separate light cap?
239 if ((*si
)->isLightCapSeparate())
241 // update index count for this shadow renderable
242 indexData
->indexCount
= numIndices
- indexData
->indexStart
;
244 // get light cap index data for update
245 indexData
= (*si
)->getLightCapRenderable()->getRenderOperationForUpdate()->indexData
;
246 // start indexes after the current total
247 indexData
->indexStart
= numIndices
;
250 // Iterate over the triangles which are using this vertex set
251 EdgeData::TriangleList::const_iterator ti
, tiend
;
252 EdgeData::TriangleLightFacingList::const_iterator lfi
;
253 ti
= edgeData
->triangles
.begin() + eg
.triStart
;
254 tiend
= ti
+ eg
.triCount
;
255 lfi
= edgeData
->triangleLightFacings
.begin() + eg
.triStart
;
256 for ( ; ti
!= tiend
; ++ti
, ++lfi
)
258 const EdgeData::Triangle
& t
= *ti
;
259 assert(t
.vertexSet
== eg
.vertexSet
);
260 // Check it's light facing
263 assert(t
.vertIndex
[0] < 65536 && t
.vertIndex
[1] < 65536 &&
264 t
.vertIndex
[2] < 65536 &&
265 "16-bit index limit exceeded!");
266 *pIdx
++ = static_cast<unsigned short>(t
.vertIndex
[0]);
267 *pIdx
++ = static_cast<unsigned short>(t
.vertIndex
[1]);
268 *pIdx
++ = static_cast<unsigned short>(t
.vertIndex
[2]);
275 // update index count for current index data (either this shadow renderable or its light cap)
276 indexData
->indexCount
= numIndices
- indexData
->indexStart
;
281 // Unlock index buffer
282 indexBuffer
->unlock();
284 // In debug mode, check we didn't overrun the index buffer
285 assert(numIndices
<= indexBuffer
->getNumIndexes() &&
286 "Index buffer overrun while generating shadow volume!! "
287 "You must increase the size of the shadow index buffer.");
290 // ------------------------------------------------------------------------
291 void ShadowCaster::extrudeVertices(
292 const HardwareVertexBufferSharedPtr
& vertexBuffer
,
293 size_t originalVertexCount
, const Vector4
& light
, Real extrudeDist
)
295 assert (vertexBuffer
->getVertexSize() == sizeof(float) * 3
296 && "Position buffer should contain only positions!");
298 // Extrude the first area of the buffer into the second area
299 // Lock the entire buffer for writing, even though we'll only be
300 // updating the latter because you can't have 2 locks on the same
302 float* pSrc
= static_cast<float*>(
303 vertexBuffer
->lock(HardwareBuffer::HBL_NORMAL
));
305 // TODO: We should add extra (ununsed) vertices ensure source and
306 // destination buffer have same alignment for slight performance gain.
307 float* pDest
= pSrc
+ originalVertexCount
* 3;
309 OptimisedUtil::getImplementation()->extrudeVertices(
311 pSrc
, pDest
, originalVertexCount
);
313 vertexBuffer
->unlock();
316 // ------------------------------------------------------------------------
317 void ShadowCaster::extrudeBounds(AxisAlignedBox
& box
, const Vector4
& light
, Real extrudeDist
) const
319 Vector3 extrusionDir
;
323 // Parallel projection guarantees min/max relationship remains the same
324 extrusionDir
.x
= -light
.x
;
325 extrusionDir
.y
= -light
.y
;
326 extrusionDir
.z
= -light
.z
;
327 extrusionDir
.normalise();
328 extrusionDir
*= extrudeDist
;
329 box
.setExtents(box
.getMinimum() + extrusionDir
,
330 box
.getMaximum() + extrusionDir
);
334 Vector3 oldMin
, oldMax
, currentCorner
;
335 // Getting the original values
336 oldMin
= box
.getMinimum();
337 oldMax
= box
.getMaximum();
338 // Starting the box again with a null content
341 // merging all the extruded corners
344 currentCorner
= oldMin
;
345 extrusionDir
.x
= currentCorner
.x
- light
.x
;
346 extrusionDir
.y
= currentCorner
.y
- light
.y
;
347 extrusionDir
.z
= currentCorner
.z
- light
.z
;
348 extrusionDir
.normalise();
349 extrusionDir
*= extrudeDist
;
350 box
.merge(currentCorner
+ extrusionDir
);
353 // only z has changed
354 currentCorner
.z
= oldMax
.z
;
355 extrusionDir
.z
= currentCorner
.z
- light
.z
;
356 extrusionDir
.normalise();
357 extrusionDir
*= extrudeDist
;
358 box
.merge(currentCorner
+ extrusionDir
);
361 currentCorner
.y
= oldMax
.y
;
362 extrusionDir
.y
= currentCorner
.y
- light
.y
;
363 extrusionDir
.normalise();
364 extrusionDir
*= extrudeDist
;
365 box
.merge(currentCorner
+ extrusionDir
);
368 currentCorner
.z
= oldMin
.z
;
369 extrusionDir
.z
= currentCorner
.z
- light
.z
;
370 extrusionDir
.normalise();
371 extrusionDir
*= extrudeDist
;
372 box
.merge(currentCorner
+ extrusionDir
);
375 currentCorner
.x
= oldMax
.x
;
376 extrusionDir
.x
= currentCorner
.x
- light
.x
;
377 extrusionDir
.normalise();
378 extrusionDir
*= extrudeDist
;
379 box
.merge(currentCorner
+ extrusionDir
);
382 currentCorner
.z
= oldMax
.z
;
383 extrusionDir
.z
= currentCorner
.z
- light
.z
;
384 extrusionDir
.normalise();
385 extrusionDir
*= extrudeDist
;
386 box
.merge(currentCorner
+ extrusionDir
);
389 currentCorner
.y
= oldMin
.y
;
390 extrusionDir
.y
= currentCorner
.y
- light
.y
;
391 extrusionDir
.normalise();
392 extrusionDir
*= extrudeDist
;
393 box
.merge(currentCorner
+ extrusionDir
);
396 currentCorner
.z
= oldMin
.z
;
397 extrusionDir
.z
= currentCorner
.z
- light
.z
;
398 extrusionDir
.normalise();
399 extrusionDir
*= extrudeDist
;
400 box
.merge(currentCorner
+ extrusionDir
);
405 // ------------------------------------------------------------------------
406 Real
ShadowCaster::getExtrusionDistance(const Vector3
& objectPos
, const Light
* light
) const
408 Vector3 diff
= objectPos
- light
->getDerivedPosition();
409 return light
->getAttenuationRange() - diff
.length();