Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages  

OgreShadowCaster.cpp

Go to the documentation of this file.
00001 /*
00002 -----------------------------------------------------------------------------
00003 This source file is part of OGRE
00004 (Object-oriented Graphics Rendering Engine)
00005 For the latest info, see http://www.ogre3d.org/
00006 
00007 Copyright © 2000-2004 The OGRE Team
00008 Also see acknowledgements in Readme.html
00009 
00010 This program is free software; you can redistribute it and/or modify it under
00011 the terms of the GNU Lesser General Public License as published by the Free Software
00012 Foundation; either version 2 of the License, or (at your option) any later
00013 version.
00014 
00015 This program is distributed in the hope that it will be useful, but WITHOUT
00016 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00017 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
00018 
00019 You should have received a copy of the GNU Lesser General Public License along with
00020 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
00021 Place - Suite 330, Boston, MA 02111-1307, USA, or go to
00022 http://www.gnu.org/copyleft/lesser.txt.
00023 -----------------------------------------------------------------------------
00024 */
00025 #include "OgreStableHeaders.h"
00026 #include "OgreLight.h"
00027 #include "OgreEdgeListBuilder.h"
00028 
00029 namespace Ogre {
00030     // ------------------------------------------------------------------------
00031     void ShadowCaster::updateEdgeListLightFacing(EdgeData* edgeData, 
00032         const Vector4& lightPos)
00033     {
00034         edgeData->updateTriangleLightFacing(lightPos);
00035     }
00036     // ------------------------------------------------------------------------
00037     void ShadowCaster::generateShadowVolume(EdgeData* edgeData, 
00038         HardwareIndexBufferSharedPtr indexBuffer, const Light* light,
00039         ShadowRenderableList& shadowRenderables, unsigned long flags)
00040     {
00041         // Edge groups should be 1:1 with shadow renderables
00042         assert(edgeData->edgeGroups.size() == shadowRenderables.size());
00043 
00044         EdgeData::EdgeGroupList::iterator egi, egiend;
00045         ShadowRenderableList::iterator si;
00046 
00047         Light::LightTypes lightType = light->getType();
00048 
00049         // Lock index buffer for writing
00050         unsigned short* pIdx = static_cast<unsigned short*>(
00051             indexBuffer->lock(HardwareBuffer::HBL_DISCARD));
00052         size_t indexStart = 0;
00053 
00054         // Iterate over the groups and form renderables for each based on their
00055         // lightFacing
00056         si = shadowRenderables.begin();
00057         egiend = edgeData->edgeGroups.end();
00058         for (egi = edgeData->edgeGroups.begin(); egi != egiend; ++egi, ++si)
00059         {
00060             EdgeData::EdgeGroup& eg = *egi;
00061             RenderOperation* lightShadOp = 0;
00062             // Initialise the index bounds for this shadow renderable
00063             RenderOperation* shadOp = (*si)->getRenderOperationForUpdate();
00064             shadOp->indexData->indexCount = 0;
00065             shadOp->indexData->indexStart = indexStart;
00066             // original number of verts (without extruded copy)
00067             size_t originalVertexCount = eg.vertexData->vertexCount;
00068             bool  firstDarkCapTri = true;
00069             unsigned short darkCapStart;
00070 
00071             EdgeData::EdgeList::iterator i, iend;
00072             iend = eg.edges.end();
00073             for (i = eg.edges.begin(); i != iend; ++i)
00074             {
00075                 EdgeData::Edge& edge = *i;
00076 
00077                 EdgeData::Triangle &t1 = edgeData->triangles[edge.triIndex[0]];
00078                 EdgeData::Triangle &t2 = edgeData->triangles[edge.triIndex[1]];
00079                 if (t1.lightFacing && (edge.degenerate || !t2.lightFacing))
00080                 {
00081                     /* Silhouette edge, first tri facing the light
00082                     Also covers degenerate tris where only tri 1 is valid
00083                     Remember verts run anticlockwise along the edge from 
00084                     tri 0 so to point shadow volume tris outward, light cap 
00085                     indexes have to be backwards
00086 
00087                     We emit 2 tris if light is a point light, 1 if light 
00088                     is directional, because directional lights cause all
00089                     points to converge to a single point at infinity.
00090 
00091                     First side tri = near1, near0, far0
00092                     Second tri = far0, far1, near1
00093 
00094                     'far' indexes are 'near' index + originalVertexCount
00095                     because 'far' verts are in the second half of the 
00096                     buffer
00097                     */
00098                     *pIdx++ = edge.vertIndex[1];
00099                     *pIdx++ = edge.vertIndex[0];
00100                     *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00101                     shadOp->indexData->indexCount += 3;
00102 
00103                     // Are we extruding to infinity?
00104                     if (!(lightType == Light::LT_DIRECTIONAL &&
00105                         flags & SRF_EXTRUDE_TO_INFINITY))
00106                     {
00107                         // additional tri to make quad
00108                         *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00109                         *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00110                         *pIdx++ = edge.vertIndex[1];
00111                         shadOp->indexData->indexCount += 3;
00112                     }
00113                     // Do dark cap tri
00114                     // Use McGuire et al method, a triangle fan covering all silhouette
00115                     // edges and one point (taken from the initial tri)
00116                     if (flags & SRF_INCLUDE_DARK_CAP)
00117                     {
00118                         if (firstDarkCapTri)
00119                         {
00120                             darkCapStart = edge.vertIndex[0] + originalVertexCount;
00121                             firstDarkCapTri = false;
00122                         }
00123                         else
00124                         {
00125                             *pIdx++ = darkCapStart;
00126                             *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00127                             *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00128                             shadOp->indexData->indexCount += 3;
00129                         }
00130 
00131                     }
00132                 }
00133                 else if (!t1.lightFacing && (edge.degenerate || t2.lightFacing))
00134                 {
00135                     // Silhouette edge, second tri facing the light
00136                     // Note edge indexes inverse of when t1 is light facing 
00137                     *pIdx++ = edge.vertIndex[0];
00138                     *pIdx++ = edge.vertIndex[1];
00139                     *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00140                     shadOp->indexData->indexCount += 3;
00141 
00142                     // Are we extruding to infinity?
00143                     if (!(lightType == Light::LT_DIRECTIONAL &&
00144                         flags & SRF_EXTRUDE_TO_INFINITY))
00145                     {
00146                         // additional tri to make quad
00147                         *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00148                         *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00149                         *pIdx++ = edge.vertIndex[0];
00150                         shadOp->indexData->indexCount += 3;
00151                     }
00152                     // Do dark cap tri
00153                     // Use McGuire et al method, a triangle fan covering all silhouette
00154                     // edges and one point (taken from the initial tri)
00155                     if (flags & SRF_INCLUDE_DARK_CAP)
00156                     {
00157                         if (firstDarkCapTri)
00158                         {
00159                             darkCapStart = edge.vertIndex[1] + originalVertexCount;
00160                             firstDarkCapTri = false;
00161                         }
00162                         else
00163                         {
00164                             *pIdx++ = darkCapStart;
00165                             *pIdx++ = edge.vertIndex[0] + originalVertexCount;
00166                             *pIdx++ = edge.vertIndex[1] + originalVertexCount;
00167                             shadOp->indexData->indexCount += 3;
00168                         }
00169 
00170                     }
00171                 }
00172 
00173             }
00174 
00175             // Do light cap
00176             if (flags & SRF_INCLUDE_LIGHT_CAP) 
00177             {
00178                 ShadowRenderable* lightCapRend = 0;
00179 
00180                 if ((*si)->isLightCapSeparate())
00181                 {
00182                     // separate light cap
00183                     lightCapRend = (*si)->getLightCapRenderable();
00184                     lightShadOp = lightCapRend->getRenderOperationForUpdate();
00185                     lightShadOp->indexData->indexCount = 0;
00186                     // start indexes after the current total
00187                     // NB we don't update the total here since that's done below
00188                     lightShadOp->indexData->indexStart = 
00189                         indexStart + shadOp->indexData->indexCount;
00190                 }
00191 
00192                 EdgeData::TriangleList::iterator ti, tiend;
00193                 tiend = edgeData->triangles.end();
00194                 for (ti = edgeData->triangles.begin(); ti != tiend; ++ti)
00195                 {
00196                     EdgeData::Triangle& t = *ti;
00197                     // Light facing, and vertex set matches
00198                     if (t.lightFacing && t.vertexSet == eg.vertexSet)
00199                     {
00200                         *pIdx++ = t.vertIndex[0];
00201                         *pIdx++ = t.vertIndex[1];
00202                         *pIdx++ = t.vertIndex[2];
00203                         if (lightShadOp)
00204                         {
00205                             lightShadOp->indexData->indexCount += 3;
00206                         }
00207                         else
00208                         {
00209                             shadOp->indexData->indexCount += 3;
00210                         }
00211                     }
00212                 }
00213 
00214             }
00215             // update next indexStart (all renderables sharing the buffer)
00216             indexStart += shadOp->indexData->indexCount;
00217             // Add on the light cap too
00218             if (lightShadOp)
00219                 indexStart += lightShadOp->indexData->indexCount;
00220 
00221 
00222         }
00223 
00224 
00225         // Unlock index buffer
00226         indexBuffer->unlock();
00227 
00228         // In debug mode, check we didn't overrun the index buffer
00229         assert(indexStart <= indexBuffer->getNumIndexes() &&
00230             "Index buffer overrun while generating shadow volume!! "
00231             "You must increase the size of the shadow index buffer.");
00232 
00233     }
00234     // ------------------------------------------------------------------------
00235     void ShadowCaster::extrudeVertices(
00236         HardwareVertexBufferSharedPtr vertexBuffer, 
00237         size_t originalVertexCount, const Vector4& light, Real extrudeDist)
00238     {
00239         assert (vertexBuffer->getVertexSize() == sizeof(Real) * 3
00240             && "Position buffer should contain only positions!");
00241 
00242         // Extrude the first area of the buffer into the second area
00243         // Lock the entire buffer for writing, even though we'll only be
00244         // updating the latter because you can't have 2 locks on the same
00245         // buffer
00246         Real* pSrc = static_cast<Real*>(
00247             vertexBuffer->lock(HardwareBuffer::HBL_NORMAL));
00248 
00249         Real* pDest = pSrc + originalVertexCount * 3;
00250         // Assume directional light, extrusion is along light direction
00251         Vector3 extrusionDir(-light.x, -light.y, -light.z);
00252         extrusionDir.normalise();
00253         extrusionDir *= extrudeDist;
00254         for (size_t vert = 0; vert < originalVertexCount; ++vert)
00255         {
00256             if (light.w != 0.0f)
00257             {
00258                 // Point light, adjust extrusionDir
00259                 extrusionDir.x = pSrc[0] - light.x;
00260                 extrusionDir.y = pSrc[1] - light.y;
00261                 extrusionDir.z = pSrc[2] - light.z;
00262                 extrusionDir.normalise();
00263                 extrusionDir *= extrudeDist;
00264             }
00265             *pDest++ = *pSrc++ + extrusionDir.x;
00266             *pDest++ = *pSrc++ + extrusionDir.y;
00267             *pDest++ = *pSrc++ + extrusionDir.z;
00268 
00269         }
00270         vertexBuffer->unlock();
00271 
00272     }
00273     // ------------------------------------------------------------------------
00274     void ShadowCaster::extrudeBounds(AxisAlignedBox& box, const Vector4& light, Real extrudeDist) const
00275     {
00276         Vector3 extrusionDir;
00277 
00278         if (light.w == 0)
00279         {
00280             // Parallel projection guarantees min/max relationship remains the same
00281             extrusionDir.x = -light.x;
00282             extrusionDir.y = -light.y;
00283             extrusionDir.z = -light.z;
00284             extrusionDir.normalise();
00285             extrusionDir *= extrudeDist;
00286             box.setExtents(box.getMinimum() + extrusionDir, 
00287                 box.getMaximum() + extrusionDir);
00288         }
00289         else
00290         {
00291             const Vector3* corners = box.getAllCorners();
00292             Vector3 vmin, vmax;
00293 
00294             for (unsigned short i = 0; i < 8; ++i)
00295             {
00296                 extrusionDir.x = corners[i].x - light.x;
00297                 extrusionDir.y = corners[i].y - light.y;
00298                 extrusionDir.z = corners[i].z - light.z;
00299                 extrusionDir.normalise();
00300                 extrusionDir *= extrudeDist;
00301                 Vector3 res = corners[i] + extrusionDir;
00302                 if (i == 0)
00303                 {
00304                     vmin = res;
00305                     vmax = res;
00306                 }
00307                 else
00308                 {
00309                     vmin.makeFloor(res);
00310                     vmax.makeCeil(res);
00311                 }
00312             }
00313 
00314             box.setExtents(vmin, vmax);
00315 
00316         }
00317 
00318     }
00319     // ------------------------------------------------------------------------
00320     Real ShadowCaster::getExtrusionDistance(const Vector3& objectPos, const Light* light) const
00321     {
00322         Vector3 diff = objectPos - light->getDerivedPosition();
00323         return light->getAttenuationRange() - diff.length();
00324     }
00325 
00326 }

Copyright © 2002-2003 by The OGRE Team
Last modified Fri May 14 23:22:47 2004