1 | /*
|
---|
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/
|
---|
6 |
|
---|
7 | Copyright (c) 2000-2005 The OGRE Team
|
---|
8 | Also see acknowledgements in Readme.html
|
---|
9 |
|
---|
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
|
---|
13 | version.
|
---|
14 |
|
---|
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.
|
---|
18 |
|
---|
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.
|
---|
23 | -----------------------------------------------------------------------------
|
---|
24 | */
|
---|
25 | #include "OgreStableHeaders.h"
|
---|
26 | #include "OgreLight.h"
|
---|
27 | #include "OgreEdgeListBuilder.h"
|
---|
28 |
|
---|
29 | namespace Ogre {
|
---|
30 | const LightList& ShadowRenderable::getLights(void) const
|
---|
31 | {
|
---|
32 | // return empty
|
---|
33 | static LightList ll;
|
---|
34 | return ll;
|
---|
35 | }
|
---|
36 | // ------------------------------------------------------------------------
|
---|
37 | void ShadowCaster::updateEdgeListLightFacing(EdgeData* edgeData,
|
---|
38 | const Vector4& lightPos)
|
---|
39 | {
|
---|
40 | edgeData->updateTriangleLightFacing(lightPos);
|
---|
41 | }
|
---|
42 | // ------------------------------------------------------------------------
|
---|
43 | void ShadowCaster::generateShadowVolume(EdgeData* edgeData,
|
---|
44 | HardwareIndexBufferSharedPtr indexBuffer, const Light* light,
|
---|
45 | ShadowRenderableList& shadowRenderables, unsigned long flags)
|
---|
46 | {
|
---|
47 | // Edge groups should be 1:1 with shadow renderables
|
---|
48 | assert(edgeData->edgeGroups.size() == shadowRenderables.size());
|
---|
49 |
|
---|
50 | EdgeData::EdgeGroupList::iterator egi, egiend;
|
---|
51 | ShadowRenderableList::iterator si;
|
---|
52 |
|
---|
53 | Light::LightTypes lightType = light->getType();
|
---|
54 |
|
---|
55 | // Lock index buffer for writing
|
---|
56 | unsigned short* pIdx = static_cast<unsigned short*>(
|
---|
57 | indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
|
---|
58 | size_t indexStart = 0;
|
---|
59 |
|
---|
60 | // Iterate over the groups and form renderables for each based on their
|
---|
61 | // lightFacing
|
---|
62 | si = shadowRenderables.begin();
|
---|
63 | egiend = edgeData->edgeGroups.end();
|
---|
64 | for (egi = edgeData->edgeGroups.begin(); egi != egiend; ++egi, ++si)
|
---|
65 | {
|
---|
66 | EdgeData::EdgeGroup& eg = *egi;
|
---|
67 | RenderOperation* lightShadOp = 0;
|
---|
68 | // Initialise the index bounds for this shadow renderable
|
---|
69 | RenderOperation* shadOp = (*si)->getRenderOperationForUpdate();
|
---|
70 | shadOp->indexData->indexCount = 0;
|
---|
71 | shadOp->indexData->indexStart = indexStart;
|
---|
72 | // original number of verts (without extruded copy)
|
---|
73 | size_t originalVertexCount = eg.vertexData->vertexCount;
|
---|
74 | bool firstDarkCapTri = true;
|
---|
75 | unsigned short darkCapStart;
|
---|
76 |
|
---|
77 | EdgeData::EdgeList::iterator i, iend;
|
---|
78 | iend = eg.edges.end();
|
---|
79 | for (i = eg.edges.begin(); i != iend; ++i)
|
---|
80 | {
|
---|
81 | EdgeData::Edge& edge = *i;
|
---|
82 |
|
---|
83 | // Silhouette edge, when two tris has opposite light facing, or
|
---|
84 | // degenerate edge where only tri 1 is valid and the tri light facing
|
---|
85 | EdgeData::Triangle &t1 = edgeData->triangles[edge.triIndex[0]];
|
---|
86 | if ((edge.degenerate && t1.lightFacing) ||
|
---|
87 | (!edge.degenerate && (t1.lightFacing ^ edgeData->triangles[edge.triIndex[1]].lightFacing)))
|
---|
88 | {
|
---|
89 | size_t v0 = edge.vertIndex[0];
|
---|
90 | size_t v1 = edge.vertIndex[1];
|
---|
91 | if (!t1.lightFacing)
|
---|
92 | {
|
---|
93 | // Inverse edge indexes when t1 is light away
|
---|
94 | std::swap(v0, v1);
|
---|
95 | }
|
---|
96 |
|
---|
97 | /* Note edge(v0, v1) run anticlockwise along the edge from
|
---|
98 | the light facing tri so to point shadow volume tris outward,
|
---|
99 | light cap indexes have to be backwards
|
---|
100 |
|
---|
101 | We emit 2 tris if light is a point light, 1 if light
|
---|
102 | is directional, because directional lights cause all
|
---|
103 | points to converge to a single point at infinity.
|
---|
104 |
|
---|
105 | First side tri = near1, near0, far0
|
---|
106 | Second tri = far0, far1, near1
|
---|
107 |
|
---|
108 | 'far' indexes are 'near' index + originalVertexCount
|
---|
109 | because 'far' verts are in the second half of the
|
---|
110 | buffer
|
---|
111 | */
|
---|
112 | *pIdx++ = v1;
|
---|
113 | *pIdx++ = v0;
|
---|
114 | *pIdx++ = v0 + originalVertexCount;
|
---|
115 | shadOp->indexData->indexCount += 3;
|
---|
116 |
|
---|
117 | // Are we extruding to infinity?
|
---|
118 | if (!(lightType == Light::LT_DIRECTIONAL &&
|
---|
119 | flags & SRF_EXTRUDE_TO_INFINITY))
|
---|
120 | {
|
---|
121 | // additional tri to make quad
|
---|
122 | *pIdx++ = v0 + originalVertexCount;
|
---|
123 | *pIdx++ = v1 + originalVertexCount;
|
---|
124 | *pIdx++ = v1;
|
---|
125 | shadOp->indexData->indexCount += 3;
|
---|
126 | }
|
---|
127 | // Do dark cap tri
|
---|
128 | // Use McGuire et al method, a triangle fan covering all silhouette
|
---|
129 | // edges and one point (taken from the initial tri)
|
---|
130 | if (flags & SRF_INCLUDE_DARK_CAP)
|
---|
131 | {
|
---|
132 | if (firstDarkCapTri)
|
---|
133 | {
|
---|
134 | darkCapStart = v0 + originalVertexCount;
|
---|
135 | firstDarkCapTri = false;
|
---|
136 | }
|
---|
137 | else
|
---|
138 | {
|
---|
139 | *pIdx++ = darkCapStart;
|
---|
140 | *pIdx++ = v1 + originalVertexCount;
|
---|
141 | *pIdx++ = v0 + originalVertexCount;
|
---|
142 | shadOp->indexData->indexCount += 3;
|
---|
143 | }
|
---|
144 |
|
---|
145 | }
|
---|
146 | }
|
---|
147 |
|
---|
148 | }
|
---|
149 |
|
---|
150 | // Do light cap
|
---|
151 | if (flags & SRF_INCLUDE_LIGHT_CAP)
|
---|
152 | {
|
---|
153 | ShadowRenderable* lightCapRend = 0;
|
---|
154 |
|
---|
155 | if ((*si)->isLightCapSeparate())
|
---|
156 | {
|
---|
157 | // separate light cap
|
---|
158 | lightCapRend = (*si)->getLightCapRenderable();
|
---|
159 | lightShadOp = lightCapRend->getRenderOperationForUpdate();
|
---|
160 | lightShadOp->indexData->indexCount = 0;
|
---|
161 | // start indexes after the current total
|
---|
162 | // NB we don't update the total here since that's done below
|
---|
163 | lightShadOp->indexData->indexStart =
|
---|
164 | indexStart + shadOp->indexData->indexCount;
|
---|
165 | }
|
---|
166 |
|
---|
167 | EdgeData::TriangleList::iterator ti, tiend;
|
---|
168 | tiend = edgeData->triangles.end();
|
---|
169 | for (ti = edgeData->triangles.begin(); ti != tiend; ++ti)
|
---|
170 | {
|
---|
171 | EdgeData::Triangle& t = *ti;
|
---|
172 | // Light facing, and vertex set matches
|
---|
173 | if (t.lightFacing && t.vertexSet == eg.vertexSet)
|
---|
174 | {
|
---|
175 | *pIdx++ = t.vertIndex[0];
|
---|
176 | *pIdx++ = t.vertIndex[1];
|
---|
177 | *pIdx++ = t.vertIndex[2];
|
---|
178 | if (lightShadOp)
|
---|
179 | {
|
---|
180 | lightShadOp->indexData->indexCount += 3;
|
---|
181 | }
|
---|
182 | else
|
---|
183 | {
|
---|
184 | shadOp->indexData->indexCount += 3;
|
---|
185 | }
|
---|
186 | }
|
---|
187 | }
|
---|
188 |
|
---|
189 | }
|
---|
190 | // update next indexStart (all renderables sharing the buffer)
|
---|
191 | indexStart += shadOp->indexData->indexCount;
|
---|
192 | // Add on the light cap too
|
---|
193 | if (lightShadOp)
|
---|
194 | indexStart += lightShadOp->indexData->indexCount;
|
---|
195 |
|
---|
196 |
|
---|
197 | }
|
---|
198 |
|
---|
199 |
|
---|
200 | // Unlock index buffer
|
---|
201 | indexBuffer->unlock();
|
---|
202 |
|
---|
203 | // In debug mode, check we didn't overrun the index buffer
|
---|
204 | assert(indexStart <= indexBuffer->getNumIndexes() &&
|
---|
205 | "Index buffer overrun while generating shadow volume!! "
|
---|
206 | "You must increase the size of the shadow index buffer.");
|
---|
207 |
|
---|
208 | }
|
---|
209 | // ------------------------------------------------------------------------
|
---|
210 | void ShadowCaster::extrudeVertices(
|
---|
211 | HardwareVertexBufferSharedPtr vertexBuffer,
|
---|
212 | size_t originalVertexCount, const Vector4& light, Real extrudeDist)
|
---|
213 | {
|
---|
214 | assert (vertexBuffer->getVertexSize() == sizeof(float) * 3
|
---|
215 | && "Position buffer should contain only positions!");
|
---|
216 |
|
---|
217 | // Extrude the first area of the buffer into the second area
|
---|
218 | // Lock the entire buffer for writing, even though we'll only be
|
---|
219 | // updating the latter because you can't have 2 locks on the same
|
---|
220 | // buffer
|
---|
221 | float* pSrc = static_cast<float*>(
|
---|
222 | vertexBuffer->lock(HardwareBuffer::HBL_NORMAL));
|
---|
223 |
|
---|
224 | float* pDest = pSrc + originalVertexCount * 3;
|
---|
225 | // Assume directional light, extrusion is along light direction
|
---|
226 | Vector3 extrusionDir(-light.x, -light.y, -light.z);
|
---|
227 | extrusionDir.normalise();
|
---|
228 | extrusionDir *= extrudeDist;
|
---|
229 | for (size_t vert = 0; vert < originalVertexCount; ++vert)
|
---|
230 | {
|
---|
231 | if (light.w != 0.0f)
|
---|
232 | {
|
---|
233 | // Point light, adjust extrusionDir
|
---|
234 | extrusionDir.x = pSrc[0] - light.x;
|
---|
235 | extrusionDir.y = pSrc[1] - light.y;
|
---|
236 | extrusionDir.z = pSrc[2] - light.z;
|
---|
237 | extrusionDir.normalise();
|
---|
238 | extrusionDir *= extrudeDist;
|
---|
239 | }
|
---|
240 | *pDest++ = *pSrc++ + extrusionDir.x;
|
---|
241 | *pDest++ = *pSrc++ + extrusionDir.y;
|
---|
242 | *pDest++ = *pSrc++ + extrusionDir.z;
|
---|
243 |
|
---|
244 | }
|
---|
245 | vertexBuffer->unlock();
|
---|
246 |
|
---|
247 | }
|
---|
248 | // ------------------------------------------------------------------------
|
---|
249 | void ShadowCaster::extrudeBounds(AxisAlignedBox& box, const Vector4& light, Real extrudeDist) const
|
---|
250 | {
|
---|
251 | Vector3 extrusionDir;
|
---|
252 |
|
---|
253 | if (light.w == 0)
|
---|
254 | {
|
---|
255 | // Parallel projection guarantees min/max relationship remains the same
|
---|
256 | extrusionDir.x = -light.x;
|
---|
257 | extrusionDir.y = -light.y;
|
---|
258 | extrusionDir.z = -light.z;
|
---|
259 | extrusionDir.normalise();
|
---|
260 | extrusionDir *= extrudeDist;
|
---|
261 | box.setExtents(box.getMinimum() + extrusionDir,
|
---|
262 | box.getMaximum() + extrusionDir);
|
---|
263 | }
|
---|
264 | else
|
---|
265 | {
|
---|
266 | const Vector3* corners = box.getAllCorners();
|
---|
267 | Vector3 vmin, vmax;
|
---|
268 |
|
---|
269 | for (unsigned short i = 0; i < 8; ++i)
|
---|
270 | {
|
---|
271 | extrusionDir.x = corners[i].x - light.x;
|
---|
272 | extrusionDir.y = corners[i].y - light.y;
|
---|
273 | extrusionDir.z = corners[i].z - light.z;
|
---|
274 | extrusionDir.normalise();
|
---|
275 | extrusionDir *= extrudeDist;
|
---|
276 | Vector3 res = corners[i] + extrusionDir;
|
---|
277 | if (i == 0)
|
---|
278 | {
|
---|
279 | vmin = res;
|
---|
280 | vmax = res;
|
---|
281 | }
|
---|
282 | else
|
---|
283 | {
|
---|
284 | vmin.makeFloor(res);
|
---|
285 | vmax.makeCeil(res);
|
---|
286 | }
|
---|
287 | }
|
---|
288 |
|
---|
289 | box.setExtents(vmin, vmax);
|
---|
290 |
|
---|
291 | }
|
---|
292 |
|
---|
293 | }
|
---|
294 | // ------------------------------------------------------------------------
|
---|
295 | Real ShadowCaster::getExtrusionDistance(const Vector3& objectPos, const Light* light) const
|
---|
296 | {
|
---|
297 | Vector3 diff = objectPos - light->getDerivedPosition();
|
---|
298 | return light->getAttenuationRange() - diff.length();
|
---|
299 | }
|
---|
300 |
|
---|
301 | }
|
---|