source: OGRE/trunk/ogrenew/OgreMain/src/OgreShadowCaster.cpp @ 657

Revision 657, 12.1 KB checked in by mattausch, 18 years ago (diff)

added ogre dependencies and patched ogre sources

Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4(Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2005 The OGRE Team
8Also see acknowledgements in Readme.html
9
10This program is free software; you can redistribute it and/or modify it under
11the terms of the GNU Lesser General Public License as published by the Free Software
12Foundation; either version 2 of the License, or (at your option) any later
13version.
14
15This program is distributed in the hope that it will be useful, but WITHOUT
16ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
18
19You should have received a copy of the GNU Lesser General Public License along with
20this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21Place - Suite 330, Boston, MA 02111-1307, USA, or go to
22http://www.gnu.org/copyleft/lesser.txt.
23-----------------------------------------------------------------------------
24*/
25#include "OgreStableHeaders.h"
26#include "OgreLight.h"
27#include "OgreEdgeListBuilder.h"
28
29namespace 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}
Note: See TracBrowser for help on using the repository browser.